<commit_before>(function (Backbone, _, $, undefined) {
"use strict";

Backbone.$ = $;

window.Daybed = window.Daybed || {};

//
// SETTINGS : global config.
//
Daybed.SETTINGS = {
    SERVER: "http://localhost:8000"
};

//
//  Base model for Hawk authentication
//
Daybed.BackboneModel = Backbone.Model.extend({

  sync: function(method, model, options) {
    var url = options.url || _.result(model, 'url');

    var methodMap = {
      'create': 'POST',
      'update': 'PUT',
      'patch': 'PATCH',
      'delete': 'DELETE',
      'read': 'GET'
    };

    options.beforeSend = this._addHawkHeaders(url, methodMap[method]);

    return Backbone.sync.call(this, method, model, options);
  },

  _addHawkHeaders: function (method, url) {
    return function(xhr) {
        if (!url)
            return;

        if (Daybed.SETTINGS.credentials &&
            Daybed.SETTINGS.credentials.id &&
            Daybed.SETTINGS.credentials.key &&
            Daybed.SETTINGS.credentials.algorithm) {

        var hawkHeader = hawk.client.header(method, url, {
            credentials: Daybed.SETTINGS.credentials
        });
        xhr.setRequestHeader('Authorization', hawkHeader.field);
      }
    };
  }
});

//
//  A record
//
Daybed.Record = Daybed.BackboneModel.extend({
    urlRoot: function () {
        return Daybed.SETTINGS.SERVER +
               '/models/' + this.definition.id + '/records';
    },

    /**
     * Fields values
     */
    fieldsValues: function () {
        var columns = this.definition.fieldsNames(),
            fields = _.pick.apply(_, ([this.attributes]).concat(columns));
        return _.values(fields);
    }
});

//
// Collection of records
//
Daybed.RecordList = Backbone.Collection.extend({
    model: Daybed.Record,

    initialize: function (definition) {
        this.definition = definition;
    },

    url: function () {
        return Daybed.SETTINGS.SERVER +
               '/models/' + this.definition.id + '/records';
    },

    parse: function (response) {
        return response.data;
    },

    /**
     * Fetch only once Definition is ready.
     */
    fetch: function () {
        var args = Array.prototype.slice.call(arguments);
        this.definition.whenReady((function () {
            Backbone.Collection.prototype.fetch.apply(this, args);
        }).bind(this));
    },

    /**
     * Override instanciation to link with Definition instance.
     */
    _prepareModel: function () {
        var m = Backbone.Collection.prototype._prepareModel.apply(this, arguments);
        m.definition = this.definition;
        return m;
    }
});

//
//  Definition : a model
//
Daybed.Definition = Daybed.BackboneModel.extend({
    /**
     * Backbone.forms schema for Definition forms
     */
    schema: {
        id:  { type: 'Hidden', title: '' },
        title: 'Text',
        description: 'Text',
        fields: { type: 'List', itemType: 'Object', subSchema: {
            name: { validators: ['required'] },
            description: 'Text',
            required: { type: 'Checkbox', editorAttrs: { 'checked' : 'checked' } },
            type: { type: 'Select', options: ['int', 'string', 'decimal', 'boolean',
                                              'email', 'url', 'point', 'line', 'polygon'] }
        }}
    },

    /**
     * Meta-types are fake types. Daybed does not know them.
     */
    metaTypes: {
        'text': 'string'
    },

    initialize: function () {
        // Add meta types to schema choice list
        var choices = this.schema.fields.subSchema.type.options;
        for (var metatype in this.metaTypes) {
            if (!_.contains(choices, metatype))
                choices.push(metatype);
        }
    },

    save: function () {
        // Substitute meta types by daybed types
        _.each(this.attributes.fields, function (field) {
            var meta = this.metaTypes[field.type];
            if (meta) {
                field.meta = field.type;
                field.type = meta;
            }
        }, this);
        Daybed.BackboneModel.prototype.save.apply(this, arguments);
    },

    url: function () {
        return Daybed.SETTINGS.SERVER +
               '/models/' + this.id + '/definition';
    },

    /**
     * @returns {boolean} True if *Definition* is initialized (fetched from server)
     */
    isReady: function () {
        return this.attributes.fields && this.attributes.fields.length > 0;
    },

    /**
     * Calls ``cb`` when *Definition* was fetched from server.
     * @param {function} cb
     */
    whenReady: function (cb) {
        if (this.isReady())
            cb();
        else {
            this.once('change', function () {
                this.whenReady(cb);
            }, this);
        }
    },

    /**
     * Fields names
     */
    fieldsNames: function () {
        return _.pluck(this.attributes.fields, 'name');
    },

    /**
     * Builds a Backbone.forms schema from the *Definition* record,
     * for {Record} forms.
     * For each model field, add a Backbone.forms declaration.
     * @returns {Object}
     */
    recordSchema: function () {
        if (!this.isReady())
            throw "Definition is not ready. Fetch it first.";
        var typeMapping = {
            'int': 'Number',
            'string': 'Text',
            'text': 'TextArea',
            'boolean': 'Checkbox'
        };
        var fieldMapping = {
            'default': function (f) {
                var d = {help: f.description},
                    t = typeMapping[f.type];
                if (t) d.type = t;
                return d;
            },
            'enum': function (f) {
                var d = fieldMapping['default'](f);
                d.options = f.choices;
                d.type = f.choices.length > 3 ? 'Select' : 'Radio';
                return d;
            },
            'decimal': function (f) {
                var d = fieldMapping['default'](f);
                d.editorAttrs = {pattern: '[-+]?[0-9]*\\.?[0-9]+'};
                return d;
            },
            'email': function (f) {
                var d = fieldMapping['default'](f);
                d.validators = ['required', 'email'];
                return d;
            },
            'url': function (f) {
                var d = fieldMapping['default'](f);
                d.validators = ['required', 'url'];
                return d;
            }
        };
        var schema = {};
        // Backbone.Forms fields from this Daybed definition
        _.each(this.attributes.fields, function (field) {
            var build = fieldMapping[field.meta || field.type];
            schema[field.name] = (build ?
                                  build(field) : fieldMapping['default'](field));
        }, this);
        return schema;
    }
});

//
// Base form class
//
Daybed.FormView = Backbone.View.extend({
    model: Daybed.Record,
    tagName: "div",
    className: "well",

    template: Mustache.compile('
{{ l.title }}
' +
                               '

' +
                               '{{#l.cancel}}{{ l.cancel }} {{/l.cancel}}' +
                               '{{ l.save }}'),
    templateError: Mustache.compile('{{ msg }}'),

    events: {
        "click .submit": "submit",
        "click .cancel": "cancel"
    },

    initialize: function () {
        this.modelname = this.options.modelname;
        this.setup();
    },

    buildForm: function () {
        // Underlying backbone-forms object
        return new Backbone.Form({
            model: this.instance
        });
    },

    setup: function (instance) {
        // Stop watching previous bound instance if any.
        if (this.instance) {
            this.instance.off('change', this.success);
            this.instance.off('sync', this.success);
            this.instance.off('error', this.error);
        }

        // Bind new instance to this form
        this.instance = instance || this.options.instance || new this.model({});

        this.instance.on('change', this.refresh, this);
        this.instance.on('sync', this.success, this);
        this.instance.on('error', this.error, this);

        this.creation = this.instance.attributes.id === undefined;
        this.validateOnly = !!this.options.validateOnly;

        this.form = this.buildForm();

        this.refresh();

        // UI Labels...
        this.l = {};
        this.l.title = this.options.title || (this.creation ? "Create " : "Edit " + this.modelname);
        this.l.cancel = 'cancel' in this.options ? this.options.cancel : "Cancel";
        this.l.save = this.options.save || (this.creation ? "Create" : "Save");
    },

    render: function () {
        this.$el.html(this.template(this));
        this.$('.form').html(this.form.render().el);
        this.delegateEvents();
        return this;
    },

    cancel: function (e) {
        if (e) e.preventDefault();
        this.trigger('cancel');
        this.reset();
        return false;
    },

    reset: function () {
        this.$('form')[0].reset();
    },

    submit: function(e) {
        if (e) e.preventDefault();
        // Serialize form fields
        var data = this.form.getValue();
        this.trigger('submit', data);
        this.save();
        return false;
    },

    save: function () {
        // Hide previous validation errors (if any)
        this.$('.field-error').remove();
        // Store form data into instance, and save it
        this.form.commit();
        // Submit form (POST/PUT)
        var headers = {};
        // Header validate only tells Daybed not to store
        if (this.validateOnly)
            headers['X-Daybed-Validate-Only'] = 'true';
        this.instance.save({}, {headers: headers});
    },

    success: function (model, response, options) {
        this.trigger((this.creation ? 'created' :
                      this.validateOnly ? 'validated' :
                      'saved'), model, response, options);
        return false;
    },

    error: function (model, response, options) {
        var descriptions = [];
        try {
            descriptions = JSON.parse(response.responseText);
            this.showErrors(descriptions);
        }
        catch (e) {
            this.$el.html(this.templateError({msg: response.responseText}));
        }
        this.trigger('error', {model: model,
                               errors: descriptions});
        return false;
    },

    /**
     * Show each error along its field
     */
    showErrors: function (descriptions) {
        _.each(descriptions.errors, function (e) {
            var name = e.name.split('.')[0];
            this.$("[name='" + name + "']")
                .after(this.templateError({msg: e.description}));
        }, this);
    },

    /**
     * Refresh field values from instance attributes.
     */
    refresh: function () {
        for (var f in this.instance.changed) {
            if (f == 'id') continue;
            var formfield = this.$("[name='"+ f + "']");
            if (formfield.length === 0)
                console.warn("Could not find form field '" + f + "'");
            formfield.val(this.instance.get(f));
        }
    }
});

//
// FormView : Generic Backbone form
//
Daybed.RecordFormView = Daybed.FormView.extend({

    initialize: function () {
        this.definition = this.options.definition ? this.options.definition
                                                  : this.options.instance ? this.options.instance.definition
                                                                          : null;
        Daybed.FormView.prototype.initialize.call(this);
    },

    buildForm: function () {
        this.instance.definition = this.instance.definition || this.definition;
        this.instance.schema = this.instance.schema || this.definition.recordSchema();
        return Daybed.FormView.prototype.buildForm.call(this);
    },

    setup: function (instance) {
        this.definition.whenReady(function () {
            if (this.modelname === undefined) {
                this.modelname = this.definition.attributes.title.toLowerCase();
            }
            Daybed.FormView.prototype.setup.call(this, instance);
        }.bind(this));
    },

    render: function () {
        this.definition.whenReady(function () {
            Daybed.FormView.prototype.render.call(this);
        }.bind(this));
    }
});

/**
 * Form rendering helper
 */
Daybed.renderForm = function (selector, options) {
    options = options || {};
    var definition = options.definition ||
                     new Daybed.Definition(_.pick(options, 'id')),
        formView = new Daybed.RecordFormView(_.extend({definition: definition},
                                                      options));
    // Render once ready
    definition.whenReady(function () {
        $(selector).html(formView.render().el);
    });
    definition.fetch();
    return formView;
};

//
// TableRowView : a single row for TableView
//
Daybed.TableRowView = Backbone.View.extend({
    tagName: 'tr',

    template: Mustache.compile('{{#fieldsValues}}{{.}}	{{/fieldsValues}}' +
                               'Edit ' +
                               '    x	'),

    events: {
        'click .edit': 'edit',
        'click .close': 'destroy'
    },

    initialize: function () {
        this.model.on('change', this.render, this);
        this.model.on('destroy', this.remove, this);
    },

    render: function (){
        this.$el.html(this.template(this.model));
        return this;
    },

    destroy: function (e) {
        e.preventDefault();
        if (confirm("Are you sure ?") === true) {
            this.model.destroy();
        }
    },

    edit: function (e) {
        e.preventDefault();
        this.trigger('edit', this.model, this);
    }
});

//
// TableView : a generic list view for RecordList collections.
//
Daybed.TableView = Backbone.View.extend({
    tagName: 'table',
    className: 'table',
    rowView: Daybed.TableRowView,

    template: Mustache.compile('
' +
                               '{{#fields}}' +
                               '  {{name}}	' +
                               '{{/fields}}Actions	' +
                               '

'),

    initialize: function () {
        this.collection.on('add', this.addOne, this);
        this.collection.on('reset', this.addAll, this);
    },

    render: function () {
        this.$el.html(this.template(this.collection.definition.attributes));
        return this;
    },

    addOne: function (record) {
        var view = new this.rowView({model: record});
        view.on('edit', this.edit, this);
        this.$('tbody').prepend(view.render().el);
    },

    addAll: function () {
        this.collection.each(this.addOne, this);
    },

    edit: function (record, row) {
        this.trigger('edit', record, row);
    }
});

})(Backbone,  _, jQuery);
<commit_msg>Various minor fixes<commit_after>(function (Backbone, _, $, undefined) {
"use strict";

Backbone.$ = $;

window.Daybed = window.Daybed || {};

//
// SETTINGS : global config.
//
Daybed.SETTINGS = {
    SERVER: "http://localhost:8000"
};

//
//  Base model for Hawk authentication
//
Daybed.BackboneModel = Backbone.Model.extend({

  sync: function(method, model, options) {
    var url = options.url || _.result(model, 'url');

    var methodMap = {
      'create': 'POST',
      'update': 'PUT',
      'patch': 'PATCH',
      'delete': 'DELETE',
      'read': 'GET'
    };

    options.beforeSend = this._addHawkHeaders(url, methodMap[method]);

    return Backbone.sync.call(this, method, model, options);
  },

  _addHawkHeaders: function (url, method) {
    return function(xhr) {
        if (!url)
            return;

        if (Daybed.SETTINGS.credentials &&
            Daybed.SETTINGS.credentials.id &&
            Daybed.SETTINGS.credentials.key &&
            Daybed.SETTINGS.credentials.algorithm) {

        var hawkHeader = hawk.client.header(method, url, {
            credentials: Daybed.SETTINGS.credentials
        });
        xhr.setRequestHeader('Authorization', hawkHeader.field);
      }
    };
  }
});

//
//  A record
//
Daybed.Record = Daybed.BackboneModel.extend({
    urlRoot: function () {
        return Daybed.SETTINGS.SERVER +
               '/models/' + this.definition.id + '/records';
    },

    /**
     * Fields values
     */
    fieldsValues: function () {
        var columns = this.definition.fieldsNames(),
            fields = _.pick.apply(_, ([this.attributes]).concat(columns));
        return _.values(fields);
    }
});

//
// Collection of records
//
Daybed.RecordList = Backbone.Collection.extend({
    model: Daybed.Record,

    initialize: function (definition) {
        this.definition = definition;
    },

    url: function () {
        return Daybed.SETTINGS.SERVER +
               '/models/' + this.definition.id + '/records';
    },

    parse: function (response) {
        return response.records;
    },

    /**
     * Fetch only once Definition is ready.
     */
    fetch: function () {
        var args = Array.prototype.slice.call(arguments);
        this.definition.whenReady((function () {
            Backbone.Collection.prototype.fetch.apply(this, args);
        }).bind(this));
    },

    /**
     * Override instanciation to link with Definition instance.
     */
    _prepareModel: function () {
        var m = Backbone.Collection.prototype._prepareModel.apply(this, arguments);
        m.definition = this.definition;
        return m;
    }
});

//
//  Definition : a model
//
Daybed.Definition = Daybed.BackboneModel.extend({
    /**
     * Backbone.forms schema for Definition forms
     */
    schema: {
        id:  { type: 'Hidden', title: '' },
        title: 'Text',
        description: 'Text',
        fields: { type: 'List', itemType: 'Object', subSchema: {
            name: { validators: ['required'] },
            description: 'Text',
            required: { type: 'Checkbox', editorAttrs: { 'checked' : 'checked' } },
            type: { type: 'Select', options: ['int', 'string', 'decimal', 'boolean',
                                              'email', 'url', 'point', 'line', 'polygon'] }
        }}
    },

    /**
     * Meta-types are fake types. Daybed does not know them.
     */
    metaTypes: {
        'text': 'string'
    },

    initialize: function () {
        // Add meta types to schema choice list
        var choices = this.schema.fields.subSchema.type.options;
        for (var metatype in this.metaTypes) {
            if (!_.contains(choices, metatype))
                choices.push(metatype);
        }
    },

    save: function () {
        // Substitute meta types by daybed types
        _.each(this.attributes.fields, function (field) {
            var meta = this.metaTypes[field.type];
            if (meta) {
                field.meta = field.type;
                field.type = meta;
            }
        }, this);
        Daybed.BackboneModel.prototype.save.apply(this, arguments);
    },

    url: function () {
        return Daybed.SETTINGS.SERVER +
               '/models/' + this.id + '/definition';
    },

    /**
     * @returns {boolean} True if *Definition* is initialized (fetched from server)
     */
    isReady: function () {
        return this.attributes.fields && this.attributes.fields.length > 0;
    },

    /**
     * Calls ``cb`` when *Definition* was fetched from server.
     * @param {function} cb
     */
    whenReady: function (cb) {
        if (this.isReady())
            cb();
        else {
            this.once('change', function () {
                this.whenReady(cb);
            }, this);
        }
    },

    /**
     * Fields names
     */
    fieldsNames: function () {
        return _.pluck(this.attributes.fields, 'name');
    },

    /**
     * Builds a Backbone.forms schema from the *Definition* record,
     * for {Record} forms.
     * For each model field, add a Backbone.forms declaration.
     * @returns {Object}
     */
    recordSchema: function () {
        if (!this.isReady())
            throw "Definition is not ready. Fetch it first.";
        var typeMapping = {
            'int': 'Number',
            'string': 'Text',
            'text': 'TextArea',
            'boolean': 'Checkbox'
        };
        var fieldMapping = {
            'default': function (f) {
                var d = {help: f.description},
                    t = typeMapping[f.type];
                if (t) d.type = t;
                return d;
            },
            'enum': function (f) {
                var d = fieldMapping['default'](f);
                d.options = f.choices;
                d.type = f.choices.length > 3 ? 'Select' : 'Radio';
                return d;
            },
            'decimal': function (f) {
                var d = fieldMapping['default'](f);
                d.editorAttrs = {pattern: '[-+]?[0-9]*\\.?[0-9]+'};
                return d;
            },
            'email': function (f) {
                var d = fieldMapping['default'](f);
                d.validators = ['required', 'email'];
                return d;
            },
            'url': function (f) {
                var d = fieldMapping['default'](f);
                d.validators = ['required', 'url'];
                return d;
            }
        };
        var schema = {};
        // Backbone.Forms fields from this Daybed definition
        _.each(this.attributes.fields, function (field) {
            var build = fieldMapping[field.meta || field.type];
            schema[field.name] = (build ?
                                  build(field) : fieldMapping['default'](field));
        }, this);
        return schema;
    }
});

//
// Base form class
//
Daybed.FormView = Backbone.View.extend({
    model: Daybed.Record,
    tagName: "div",
    className: "well",

    template: Mustache.compile('
{{ l.title }}
' +
                               '

' +
                               '{{#l.cancel}}{{ l.cancel }} {{/l.cancel}}' +
                               '{{ l.save }}'),
    templateError: Mustache.compile('{{ msg }}'),

    events: {
        "click .submit": "submit",
        "click .cancel": "cancel"
    },

    initialize: function () {
        this.modelname = this.options.modelname;
        this.setup();
    },

    buildForm: function () {
        // Underlying backbone-forms object
        return new Backbone.Form({
            model: this.instance
        });
    },

    setup: function (instance) {
        // Stop watching previous bound instance if any.
        if (this.instance) {
            this.instance.off('change', this.success);
            this.instance.off('sync', this.success);
            this.instance.off('error', this.error);
        }

        // Bind new instance to this form
        this.instance = instance || this.options.instance || new this.model({});

        this.instance.on('change', this.refresh, this);
        this.instance.on('sync', this.success, this);
        this.instance.on('error', this.error, this);

        this.creation = this.instance.attributes.id === undefined;
        this.validateOnly = !!this.options.validateOnly;

        this.form = this.buildForm();

        this.refresh();

        // UI Labels...
        this.l = {};
        this.l.title = this.options.title || (this.creation ? "Create " : "Edit " + this.modelname);
        this.l.cancel = 'cancel' in this.options ? this.options.cancel : "Cancel";
        this.l.save = this.options.save || (this.creation ? "Create" : "Save");
    },

    render: function () {
        this.$el.html(this.template(this));
        this.$('.form').html(this.form.render().el);
        this.delegateEvents();
        return this;
    },

    cancel: function (e) {
        if (e) e.preventDefault();
        this.trigger('cancel');
        this.reset();
        return false;
    },

    reset: function () {
        this.$('form')[0].reset();
    },

    submit: function(e) {
        if (e) e.preventDefault();
        // Serialize form fields
        var data = this.form.getValue();
        this.trigger('submit', data);
        this.save();
        return false;
    },

    save: function () {
        // Hide previous validation errors (if any)
        this.$('.field-error').remove();
        // Store form data into instance, and save it
        this.form.commit();
        // Submit form (POST/PUT)
        var headers = {};
        // Header validate only tells Daybed not to store
        if (this.validateOnly)
            headers['X-Daybed-Validate-Only'] = 'true';
        this.instance.save({}, {headers: headers});
    },

    success: function (model, response, options) {
        this.trigger((this.creation ? 'created' :
                      this.validateOnly ? 'validated' :
                      'saved'), model, response, options);
        return false;
    },

    error: function (model, response, options) {
        var descriptions = [];
        try {
            descriptions = JSON.parse(response.responseText);
            this.showErrors(descriptions);
        }
        catch (e) {
            this.$el.html(this.templateError({msg: response.responseText}));
        }
        this.trigger('error', {model: model,
                               errors: descriptions});
        return false;
    },

    /**
     * Show each error along its field
     */
    showErrors: function (descriptions) {
        _.each(descriptions.errors, function (e) {
            var name = e.name.split('.')[0];
            this.$("[name='" + name + "']")
                .after(this.templateError({msg: e.description}));
        }, this);
    },

    /**
     * Refresh field values from instance attributes.
     */
    refresh: function () {
        for (var f in this.instance.changed) {
            if (f == 'id') continue;
            var formfield = this.$("[name='"+ f + "']");
            if (formfield.length === 0)
                console.warn("Could not find form field '" + f + "'");
            formfield.val(this.instance.get(f));
        }
    }
});

//
// FormView : Generic Backbone form
//
Daybed.RecordFormView = Daybed.FormView.extend({

    initialize: function () {
        this.definition = this.options.definition ? this.options.definition
                                                  : this.options.instance ? this.options.instance.definition
                                                                          : null;
        Daybed.FormView.prototype.initialize.call(this);
    },

    buildForm: function () {
        this.instance.definition = this.instance.definition || this.definition;
        this.instance.schema = this.instance.schema || this.definition.recordSchema();
        return Daybed.FormView.prototype.buildForm.call(this);
    },

    setup: function (instance) {
        this.definition.whenReady(function () {
            if (this.modelname === undefined) {
                this.modelname = this.definition.attributes.title.toLowerCase();
            }
            Daybed.FormView.prototype.setup.call(this, instance);
        }.bind(this));
    },

    render: function () {
        this.definition.whenReady(function () {
            Daybed.FormView.prototype.render.call(this);
        }.bind(this));
        return this;
    }
});

/**
 * Form rendering helper
 */
Daybed.renderForm = function (selector, options) {
    options = options || {};
    var definition = options.definition ||
                     new Daybed.Definition(_.pick(options, 'id')),
        formView = new Daybed.RecordFormView(_.extend({definition: definition},
                                                      options));
    // Render once ready
    definition.whenReady(function () {
        $(selector).html(formView.render().el);
    });
    definition.fetch();
    return formView;
};

//
// TableRowView : a single row for TableView
//
Daybed.TableRowView = Backbone.View.extend({
    tagName: 'tr',

    template: Mustache.compile('{{#fieldsValues}}{{.}}	{{/fieldsValues}}' +
                               'Edit ' +
                               '    x	'),

    events: {
        'click .edit': 'edit',
        'click .close': 'destroy'
    },

    initialize: function () {
        this.model.on('change', this.render, this);
        this.model.on('destroy', this.remove, this);
    },

    render: function (){
        this.$el.html(this.template(this.model));
        return this;
    },

    destroy: function (e) {
        e.preventDefault();
        if (confirm("Are you sure ?") === true) {
            this.model.destroy();
        }
    },

    edit: function (e) {
        e.preventDefault();
        this.trigger('edit', this.model, this);
    }
});

//
// TableView : a generic list view for RecordList collections.
//
Daybed.TableView = Backbone.View.extend({
    tagName: 'table',
    className: 'table',
    rowView: Daybed.TableRowView,

    template: Mustache.compile('
' +
                               '{{#fields}}' +
                               '  {{name}}	' +
                               '{{/fields}}Actions	' +
                               '

'),

    initialize: function () {
        this.collection.on('add', this.addOne, this);
        this.collection.on('reset', this.addAll, this);
    },

    render: function () {
        this.$el.html(this.template(this.collection.definition.attributes));
        return this;
    },

    addOne: function (record) {
        var view = new this.rowView({model: record});
        view.on('edit', this.edit, this);
        this.$('tbody').prepend(view.render().el);
    },

    addAll: function () {
        this.collection.each(this.addOne, this);
    },

    edit: function (record, row) {
        this.trigger('edit', record, row);
    }
});

})(Backbone,  _, jQuery);
<|endoftext|>


<commit_before>/*
 * This file is part of Arduino
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Copyright 2015 Arduino Srl (http://www.arduino.org/)
 *
 * authors: arduino.org team - support@arduino.org
 *
 */

(function () {
	"use strict";

	var child_process   = require('child_process'),
		timer			= require('timers'),
		os              = require('os'),
		path			= require('path');

	var domainName = "org-arduino-ide-domain-debug",
		dManager;

	var openOcdProcess,
		gdbProcess;

	var rootDir = __dirname.substring(0, __dirname.lastIndexOf(path.sep)),
		interval = 0;

	function getTmpFolder()
	{
		return os.tmpdir();
	}

	function getOpenOcd()
	{
		return rootDir+((process.platform =='win32')? '\\hardware\\tools\\OpenOCD-0.9.0-arduino\\bin\\openocd' : '/hardware/tools/OpenOCD-0.9.0-arduino/bin/openocd')
	}

	function getScriptDir()
	{
		return rootDir+((process.platform =='win32')? '\\hardware\\tools\\OpenOCD-0.9.0-arduino\\share\\openocd\\scripts' : '/hardware/tools/OpenOCD-0.9.0-arduino/share/openocd/scripts')
	}

	function getScript()
	{
		return rootDir+((process.platform =='win32')? '\\hardware\\arduino\\samd\\variants\\arduino_zero\\openocd_scripts\\arduino_zero.cfg' : '/hardware/arduino/samd/variants/arduino_zero/openocd_scripts/arduino_zero.cfg')
	}

	function getGdb()
	{
		return rootDir+((process.platform =='win32')? '\\hardware\\tools\\samd\\bin\\arm-none-eabi-gdb' : '/hardware/tools/samd/bin/arm-none-eabi-gdb')
	}

	function stopAll()
	{
		if(!openOcdProcess.killed)
		{
			if(process.platform == 'win32')
				process.kill(openOcdProcess.pid, 'SIGKILL');
			else
				process.kill(-openOcdProcess.pid)
		}
		if(!gdbProcess.killed)
			process.kill(gdbProcess.pid, 'SIGKILL');

	}

	function launchOpenOcd()
	{
		var OpenOcdCmd = [getOpenOcd(), "-s", getScriptDir(), "-f", getScript()];
		openOcdProcess = child_process.spawn(OpenOcdCmd[0], OpenOcdCmd.slice(1), {detached: true});

		openOcdProcess.on('close', function(code, signal){
			console.log("OPENOCD PROCESS KILLED");
			dManager.emitEvent(domainName, "close_flag", "1")
		});

		return openOcdProcess.pid;
	}

	function launchGdb(elfFile, sketchFolder)
	{
		var gdbCmd = [getGdb(), "-d", "'" + sketchFolder + "'"]
		gdbProcess = child_process.exec(gdbCmd[0], gdbCmd.slice(1));

		gdbProcess.stdout.on("data", function(data){
			dManager.emitEvent(domainName, "debug_data", data.toString());
		});

		gdbProcess.stderr.on("data", function(data){
			dManager.emitEvent(domainName, "debug_err", data.toString());
		});

		gdbProcess.on('close', function(code, signal){
			console.log("GDB PROCESS KILLED");
			dManager.emitEvent(domainName, "close_flag", "1")
		});

		if(gdbProcess.pid)
			timer.setTimeout(function(){
				locateElfFile(elfFile)
				timer.setTimeout(function(){
					locateLiveProgram()
				}, interval);
			}, interval);
	}

	function locateElfFile(filepath)
	{
		console.log("--|| Locate elf file ||--")
		if(process.platform == 'win32')
			gdbProcess.stdin.write("file " + filepath + " \n")
		else
			gdbProcess.stdin.write("file " + filepath.substring(0,filepath.lastIndexOf(path.sep)) + " \n")
		console.log("file " + filepath + " \n")

	}

	function locateLiveProgram()
	{
		console.log("--|| Locate live program ||--")
		gdbProcess.stdin.write("target remote localhost:3333"+" \n")
		console.log("target remote localhost:3333"+" \n")
		//dManager.emitEvent(domainName, "debug_data", "target remote localhost:3333"+" \n");
	}

	function stopExecution()
	{
		console.log("--|| Stop sketch ||--")
		gdbProcess.stdin.write(" monitor reset halt"+" \n")
		dManager.emitEvent(domainName, "debug_data", "Halt")
	}

	function restartExecution()
	{
		console.log("--|| Restart sketch ||--")
		gdbProcess.stdin.write(" monitor reset run"+" \n")
		dManager.emitEvent(domainName, "debug_data", "Resume")
	}

	function stepNextBp()
	{
		console.log("--|| Continue sketch execution ||--")
		gdbProcess.stdin.write(" continue" + " \n")
		//dManager.emitEvent(domainName, "debug_data", "continue")
	}

	function stepNextLine()
	{
		console.log("--|| Step Next Line ||--")
		gdbProcess.stdin.write(" next" + " \n")
		//dManager.emitEvent(domainName, "debug_data", "next")
	}

	function showBreakpoints()
	{
		console.log("--|| Show a list of breakpoints ||--")
		gdbProcess.stdin.write(" info breakpoints " + " \n")
		//dManager.emitEvent(domainName, "debug_data", "info breakpoints")
	}

	function setBreakpoint(filename, line)
	{
		console.log("--|| Set breakpoint at " + line + " ||--")
		gdbProcess.stdin.write(" break " + filename +  ":" + line + " \n")
		//dManager.emitEvent(domainName, "debug_data", "b " + line)
	}

	function showVariables()
	{
		console.log("--|| Show variables ||--")
		gdbProcess.stdin.write(" info locals" + " \n")
		//dManager.emitEvent(domainName, "debug_data", "print " + variable)
	}

	function saveBreakpoints(bpList, filename)
	{
		console.log("--|| Save breakpoint on file ||--")
		//gdbProcess.stdin.write("save breakpoints" + filename +" \n")
		//oppure
		fs.writeFile(filename, bpList, function(err){
			if(err)
				dManager.emitEvent(domainName, "debug_err", "Error in breakpoint file saving...");
			else
				dManager.emitEvent(domainName, "debug_data", "Breakpoint file saved");

		})
	}

	function deleteBreakpoint(filename, line)
	{
		console.log("--|| Delete breakpoint at " + line + " ||--")
		gdbProcess.stdin.write("clear " + filename +  ":" + line + " \n")
	}

	function init(domainManager){
		if(!domainManager.hasDomain( domainName )){
			domainManager.registerDomain( domainName, {major: 0, minor: 1});
		}
		dManager = domainManager;

//------------     COMMANDS     ------------
		//<editor-fold desc="launchOpenOcd">
		dManager.registerCommand(
			domainName,
			"launchOpenOcd",
			launchOpenOcd,
			false,
			"Start Open Ocd",
			[],
			[{	name:"OpenOcdPID",
				type:"string",
				description:"OpenOcd Process ID"
			}]
		);
		//</editor-fold>

		//<editor-fold desc="stopAll">
		dManager.registerCommand(
			domainName,
			"stopAll",
			stopAll,
			false,
			"Stop Debug"
		);
		//</editor-fold>

		//<editor-fold desc="halt">
		dManager.registerCommand(
			domainName,
			"halt",
			stopExecution,
			false,
			"Stop sketch execution"
		);
		//</editor-fold>

		//<editor-fold desc="restart">
		dManager.registerCommand(
			domainName,
			"restart",
			restartExecution,
			false,
			"Restart sketch execution"
		);
		//</editor-fold>

		//<editor-fold desc="launchGdb">
		dManager.registerCommand(
			domainName,
			"launchGdb",
			launchGdb,
			false,
			"Start Gdb",
			[{
				name:"elfFile",
				type:"string",
				description:"Elf file to locate"
			},
			{
				name:"sketchFolder",
				type:"string",
				description:"Sketch folder"
			}]
		);
		//</editor-fold>

		//<editor-fold desc="show_breakpoints">
		dManager.registerCommand(
			domainName,
			"show_breakpoints",
			showBreakpoints,
			false,
			"Show a list of breakpoints",
			[],
			[{	name:"breakpointList",
				type:"string",
				description:"List of breakpoints"
			}]
		);
		//</editor-fold>

		//<editor-fold desc="set_breakpoint">
		dManager.registerCommand(
			domainName,
			"set_breakpoint",
			setBreakpoint,
			false,
			"Set breakpoint",
			[{	name:"sketchname",
				type:"string",
				description:"File in witch set breakpoint"
			},
				{	name:"breakpointLine",
				type:"int",
				description:"Set a breakpoint at breakpointLine row"
			}]
		);
		//</editor-fold>

		//<editor-fold desc="deleteBreakpoint">
		dManager.registerCommand(
			domainName,
			"deleteBreakpoint",
			deleteBreakpoint,
			false,
			"Delete breakpoint",
			[{	name:"sketchname",
				type:"string",
				description:"File in witch delete breakpoint"
			},
				{	name:"breakpointLine",
					type:"int",
					description:"Delete the breakpoint at breakpointLine row"
				}]
		);
		//</editor-fold>

		//<editor-fold desc="saveBreakpoint">
		dManager.registerCommand(
			domainName,
			"saveBreakpoints",
			saveBreakpoints,
			false,
			"Save breakpoint in a file",
			[{	name:"bpList",
				type:"string",
				description:"List of breakpoints"
			},
			{	name:"filename",
				type:"string",
				description:"Name of file(absolute) to save breakpoints"
			}]
		);
		//</editor-fold>

		//<editor-fold desc="show_variables">
		dManager.registerCommand(
			domainName,
			"show_variables",
			showVariables,
			false,
			"Show variables with their values"
		);
		//</editor-fold>

		//<editor-fold desc="step_next_line">
		dManager.registerCommand(
			domainName,
			"step_next_line",
			stepNextLine,
			false,
			"Step next line"
		);
		//</editor-fold>

		//<editor-fold desc="step_next_bp">
		dManager.registerCommand(
			domainName,
			"step_next_bp",
			stepNextBp,
			false,
			"Step next line"
		);
		//</editor-fold>

		//<editor-fold desc="getTmpFolder">
		dManager.registerCommand(
			domainName,
			"getTmpFolder",
			getTmpFolder,
			false,
			"Get tmp folder"
		);
		//</editor-fold>

//------------     EVENTS     ------------
		//<editor-fold desc="debug_data">
		dManager.registerEvent(
			domainName,
			"debug_data",
			[{	name:"ddata",
				type:"string",
				description:"data from gdb"
			}]
		);
		//</editor-fold>

		//<editor-fold desc="debug_err">
		dManager.registerEvent(
			domainName,
			"debug_err",
			[{	name:"derr",
				type:"string",
				description:"error from gdb"
			}]
		);
		//</editor-fold>

		//<editor-fold desc="close_flag">
		dManager.registerEvent(
			domainName,
			"close_flag",
			[{	name:"flag",
				type:"int",
				description:"Communicates if openOcd and GDB were closed"
			}]
		);
		//</editor-fold>

	}

	exports.init = init;
}());<commit_msg>linux exception management<commit_after>/*
 * This file is part of Arduino
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Copyright 2015 Arduino Srl (http://www.arduino.org/)
 *
 * authors: arduino.org team - support@arduino.org
 *
 */

(function () {
	"use strict";

	var child_process   = require('child_process'),
		timer			= require('timers'),
		os              = require('os'),
		path			= require('path');

	var domainName = "org-arduino-ide-domain-debug",
		dManager;

	var openOcdProcess,
		gdbProcess;

	var rootDir = __dirname.substring(0, __dirname.lastIndexOf(path.sep)),
		interval = 0;

	function getTmpFolder()
	{
		return os.tmpdir();
	}

	function getOpenOcd()
	{
		return rootDir+((process.platform =='win32')? '\\hardware\\tools\\OpenOCD-0.9.0-arduino\\bin\\openocd' : '/hardware/tools/OpenOCD-0.9.0-arduino/bin/openocd')
	}

	function getScriptDir()
	{
		return rootDir+((process.platform =='win32')? '\\hardware\\tools\\OpenOCD-0.9.0-arduino\\share\\openocd\\scripts' : '/hardware/tools/OpenOCD-0.9.0-arduino/share/openocd/scripts')
	}

	function getScript()
	{
		return rootDir+((process.platform =='win32')? '\\hardware\\arduino\\samd\\variants\\arduino_zero\\openocd_scripts\\arduino_zero.cfg' : '/hardware/arduino/samd/variants/arduino_zero/openocd_scripts/arduino_zero.cfg')
	}

	function getGdb()
	{
		return rootDir+((process.platform =='win32')? '\\hardware\\tools\\samd\\bin\\arm-none-eabi-gdb' : '/hardware/tools/samd/bin/arm-none-eabi-gdb')
	}

	function stopAll()
	{
		if(!openOcdProcess.killed)
		{
			if(process.platform == 'win32')
				process.kill(openOcdProcess.pid, 'SIGKILL');
			else
				process.kill(-openOcdProcess.pid)
		}
		if(!gdbProcess.killed)
			process.kill(gdbProcess.pid, 'SIGKILL');

	}

	function launchOpenOcd()
	{
		var OpenOcdCmd = [getOpenOcd(), "-s", getScriptDir(), "-f", getScript()];
		openOcdProcess = child_process.spawn(OpenOcdCmd[0], OpenOcdCmd.slice(1), {detached: true});

		openOcdProcess.on('close', function(code, signal){
			console.log("OPENOCD PROCESS KILLED");
			dManager.emitEvent(domainName, "close_flag", "1")
		});

		return openOcdProcess.pid;
	}

	function launchGdb(elfFile, sketchFolder)
	{
		var gdbCmd = [getGdb(), "-d", "'" + sketchFolder + "'"]
		gdbProcess = child_process.exec(gdbCmd[0], gdbCmd.slice(1));

		gdbProcess.stdout.on("data", function(data){
			dManager.emitEvent(domainName, "debug_data", data.toString());
		});

		gdbProcess.stderr.on("data", function(data){
			dManager.emitEvent(domainName, "debug_err", data.toString());
		});

		gdbProcess.on('close', function(code, signal){
			console.log("GDB PROCESS KILLED");
			dManager.emitEvent(domainName, "close_flag", "1")
		});

		if(gdbProcess.pid)
			timer.setTimeout(function(){
				locateElfFile(elfFile)
				timer.setTimeout(function(){
					locateLiveProgram()
				}, interval);
			}, interval);
	}

	function locateElfFile(filepath)
	{
		console.log("--|| Locate elf file ||--")
		if(process.platform == 'win32' || process.platform == 'linux') {
			gdbProcess.stdin.write("file " + filepath + " \n")
			console.log("file " + filepath + " \n")
		}
		else {
			gdbProcess.stdin.write("file " + filepath.substring(0, filepath.lastIndexOf(path.sep)) + " \n")
			console.log("file " + filepath.substring(0, filepath.lastIndexOf(path.sep)) + " \n")
		}

	}

	function locateLiveProgram()
	{
		console.log("--|| Locate live program ||--")
		gdbProcess.stdin.write("target remote localhost:3333"+" \n")
		console.log("target remote localhost:3333"+" \n")
		//dManager.emitEvent(domainName, "debug_data", "target remote localhost:3333"+" \n");
	}

	function stopExecution()
	{
		console.log("--|| Stop sketch ||--")
		gdbProcess.stdin.write(" monitor reset halt"+" \n")
		dManager.emitEvent(domainName, "debug_data", "Halt")
	}

	function restartExecution()
	{
		console.log("--|| Restart sketch ||--")
		gdbProcess.stdin.write(" monitor reset run"+" \n")
		dManager.emitEvent(domainName, "debug_data", "Resume")
	}

	function stepNextBp()
	{
		console.log("--|| Continue sketch execution ||--")
		gdbProcess.stdin.write(" continue" + " \n")
		//dManager.emitEvent(domainName, "debug_data", "continue")
	}

	function stepNextLine()
	{
		console.log("--|| Step Next Line ||--")
		gdbProcess.stdin.write(" next" + " \n")
		//dManager.emitEvent(domainName, "debug_data", "next")
	}

	function showBreakpoints()
	{
		console.log("--|| Show a list of breakpoints ||--")
		gdbProcess.stdin.write(" info breakpoints " + " \n")
		//dManager.emitEvent(domainName, "debug_data", "info breakpoints")
	}

	function setBreakpoint(filename, line)
	{
		console.log("--|| Set breakpoint at " + line + " ||--")
		gdbProcess.stdin.write(" break " + filename +  ":" + line + " \n")
		//dManager.emitEvent(domainName, "debug_data", "b " + line)
	}

	function showVariables()
	{
		console.log("--|| Show variables ||--")
		gdbProcess.stdin.write(" info locals" + " \n")
		//dManager.emitEvent(domainName, "debug_data", "print " + variable)
	}

	function saveBreakpoints(bpList, filename)
	{
		console.log("--|| Save breakpoint on file ||--")
		//gdbProcess.stdin.write("save breakpoints" + filename +" \n")
		//oppure
		fs.writeFile(filename, bpList, function(err){
			if(err)
				dManager.emitEvent(domainName, "debug_err", "Error in breakpoint file saving...");
			else
				dManager.emitEvent(domainName, "debug_data", "Breakpoint file saved");

		})
	}

	function deleteBreakpoint(filename, line)
	{
		console.log("--|| Delete breakpoint at " + line + " ||--")
		gdbProcess.stdin.write("clear " + filename +  ":" + line + " \n")
	}

	function init(domainManager){
		if(!domainManager.hasDomain( domainName )){
			domainManager.registerDomain( domainName, {major: 0, minor: 1});
		}
		dManager = domainManager;

//------------     COMMANDS     ------------
		//<editor-fold desc="launchOpenOcd">
		dManager.registerCommand(
			domainName,
			"launchOpenOcd",
			launchOpenOcd,
			false,
			"Start Open Ocd",
			[],
			[{	name:"OpenOcdPID",
				type:"string",
				description:"OpenOcd Process ID"
			}]
		);
		//</editor-fold>

		//<editor-fold desc="stopAll">
		dManager.registerCommand(
			domainName,
			"stopAll",
			stopAll,
			false,
			"Stop Debug"
		);
		//</editor-fold>

		//<editor-fold desc="halt">
		dManager.registerCommand(
			domainName,
			"halt",
			stopExecution,
			false,
			"Stop sketch execution"
		);
		//</editor-fold>

		//<editor-fold desc="restart">
		dManager.registerCommand(
			domainName,
			"restart",
			restartExecution,
			false,
			"Restart sketch execution"
		);
		//</editor-fold>

		//<editor-fold desc="launchGdb">
		dManager.registerCommand(
			domainName,
			"launchGdb",
			launchGdb,
			false,
			"Start Gdb",
			[{
				name:"elfFile",
				type:"string",
				description:"Elf file to locate"
			},
			{
				name:"sketchFolder",
				type:"string",
				description:"Sketch folder"
			}]
		);
		//</editor-fold>

		//<editor-fold desc="show_breakpoints">
		dManager.registerCommand(
			domainName,
			"show_breakpoints",
			showBreakpoints,
			false,
			"Show a list of breakpoints",
			[],
			[{	name:"breakpointList",
				type:"string",
				description:"List of breakpoints"
			}]
		);
		//</editor-fold>

		//<editor-fold desc="set_breakpoint">
		dManager.registerCommand(
			domainName,
			"set_breakpoint",
			setBreakpoint,
			false,
			"Set breakpoint",
			[{	name:"sketchname",
				type:"string",
				description:"File in witch set breakpoint"
			},
				{	name:"breakpointLine",
				type:"int",
				description:"Set a breakpoint at breakpointLine row"
			}]
		);
		//</editor-fold>

		//<editor-fold desc="deleteBreakpoint">
		dManager.registerCommand(
			domainName,
			"deleteBreakpoint",
			deleteBreakpoint,
			false,
			"Delete breakpoint",
			[{	name:"sketchname",
				type:"string",
				description:"File in witch delete breakpoint"
			},
				{	name:"breakpointLine",
					type:"int",
					description:"Delete the breakpoint at breakpointLine row"
				}]
		);
		//</editor-fold>

		//<editor-fold desc="saveBreakpoint">
		dManager.registerCommand(
			domainName,
			"saveBreakpoints",
			saveBreakpoints,
			false,
			"Save breakpoint in a file",
			[{	name:"bpList",
				type:"string",
				description:"List of breakpoints"
			},
			{	name:"filename",
				type:"string",
				description:"Name of file(absolute) to save breakpoints"
			}]
		);
		//</editor-fold>

		//<editor-fold desc="show_variables">
		dManager.registerCommand(
			domainName,
			"show_variables",
			showVariables,
			false,
			"Show variables with their values"
		);
		//</editor-fold>

		//<editor-fold desc="step_next_line">
		dManager.registerCommand(
			domainName,
			"step_next_line",
			stepNextLine,
			false,
			"Step next line"
		);
		//</editor-fold>

		//<editor-fold desc="step_next_bp">
		dManager.registerCommand(
			domainName,
			"step_next_bp",
			stepNextBp,
			false,
			"Step next line"
		);
		//</editor-fold>

		//<editor-fold desc="getTmpFolder">
		dManager.registerCommand(
			domainName,
			"getTmpFolder",
			getTmpFolder,
			false,
			"Get tmp folder"
		);
		//</editor-fold>

//------------     EVENTS     ------------
		//<editor-fold desc="debug_data">
		dManager.registerEvent(
			domainName,
			"debug_data",
			[{	name:"ddata",
				type:"string",
				description:"data from gdb"
			}]
		);
		//</editor-fold>

		//<editor-fold desc="debug_err">
		dManager.registerEvent(
			domainName,
			"debug_err",
			[{	name:"derr",
				type:"string",
				description:"error from gdb"
			}]
		);
		//</editor-fold>

		//<editor-fold desc="close_flag">
		dManager.registerEvent(
			domainName,
			"close_flag",
			[{	name:"flag",
				type:"int",
				description:"Communicates if openOcd and GDB were closed"
			}]
		);
		//</editor-fold>

	}

	exports.init = init;
}());<|endoftext|>


<commit_before>var health = require('health-monitor');
var exec = require('child_process').exec;
var _ = require('underscore');

var config = require('./config.json');

var urlsApps = {};
_.each(config.apps, function(app) { urlsApps[app.url] = app.name });

var prodInProgress = {};
_.each(urlsApps, function(val, key) { prodInProgress[key] = false });

health.monitor(_.keys(urlsApps), config.opts, function(err, url) {
  if (!err) return; // all good

  var name = urlsApps[url];

  prodInProgress[url] = true;
  var done = function() { prodInProgress[url] = false; }

  log(name+' -- healthcheck failed');
  exec('pm2 jlist', { maxBuffer: 1024*1024 }, function(err, stdout, stderr) {
    if (err) return logErr(err) && done();

    var processesInfos = JSON.parse(stdout.toString());
    var processInfo = _.find(processesInfos, {name: name})
    if (!(processInfo && processInfo.pm2_env)) return done();
    if (processInfo.pm2_env.status != 'online') return done();

    log(name+' -- attempting to restart');
    exec('pm2 restart '+name, function(err) {
      if (err) {
        logErr(name+' -- error while trying to restart');
        logErr(err);
      } else {
        log(name+' -- restarted');
      }
      return done();
    }
  });
});

function log(msg) {
  console.log(new Date(), msg);
}

function logErr(err) {
  console.error(new Date(), err && err.stack || err);
}
<commit_msg>avoid race condition<commit_after>var health = require('health-monitor');
var exec = require('child_process').exec;
var _ = require('underscore');

var config = require('./config.json');

var urlsApps = {};
_.each(config.apps, function(app) { urlsApps[app.url] = app.name });

var prodInProgress = {};
_.each(urlsApps, function(val, key) { prodInProgress[key] = false });

health.monitor(_.keys(urlsApps), config.opts, function(err, url) {
  if (!err) return; // all good
  if (prodInProgress[url]) return;

  var name = urlsApps[url];

  prodInProgress[url] = true;
  var done = function() { prodInProgress[url] = false; }

  log(name+' -- healthcheck failed');
  exec('pm2 jlist', { maxBuffer: 1024*1024 }, function(err, stdout, stderr) {
    if (err) return logErr(err) && done();

    var processesInfos = JSON.parse(stdout.toString());
    var processInfo = _.find(processesInfos, {name: name})
    if (!(processInfo && processInfo.pm2_env)) return done();
    if (processInfo.pm2_env.status != 'online') return done();

    log(name+' -- attempting to restart');
    exec('pm2 restart '+name, function(err) {
      if (err) {
        logErr(name+' -- error while trying to restart');
        logErr(err);
      } else {
        log(name+' -- restarted');
      }
      return done();
    }
  });
});

function log(msg) {
  console.log(new Date(), msg);
}

function logErr(err) {
  console.error(new Date(), err && err.stack || err);
}
<|endoftext|>


<commit_before>module.exports = /* glsl */`
uniform float uReflectance;

// https://google.github.io/filament/Filament.md.html#materialsystem/specularbrdf
// Distribution
// Walter et al. 2007, "Microfacet Models for Refraction through Rough Surfaces"
float D_GGX(float linearRoughness, float NoH, const vec3 h, const vec3 normalWorld) {
#if defined(TARGET_MOBILE)
  vec3 NxH = cross(normalWorld, h);
  float oneMinusNoHSquared = dot(NxH, NxH);
#else
  float oneMinusNoHSquared = 1.0 - NoH * NoH;
#endif

  float a = NoH * linearRoughness;
  float k = linearRoughness / (oneMinusNoHSquared + a * a);
  float d = k * k * (1.0 / PI);
  return saturateMediump(d);
}

// Burley 2012, "Physically-Based Shading at Disney"
float D_GGX_Anisotropic(float at, float ab, float ToH, float BoH, float NoH) {
  float a2 = at * ab;
  highp vec3 d = vec3(ab * ToH, at * BoH, a2 * NoH);
  highp float d2 = dot(d, d);
  float b2 = a2 / d2;
  return a2 * b2 * b2 * (1.0 / PI);
}

float distribution(float linearRoughness, float NoH, const vec3 h, const vec3 normalWorld) {
  return D_GGX(linearRoughness, NoH, h, normalWorld);
}

float distributionAnisotropic(float at, float ab, float ToH, float BoH, float NoH) {
  return D_GGX_Anisotropic(at, ab, ToH, BoH, NoH);
}

float distributionClearCoat(float linearRoughness, float NoH, const vec3 h, const vec3 normalWorld) {
  return D_GGX(linearRoughness, NoH, h, normalWorld);
}

// Visibility
// Heitz 2014, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs"
float V_SmithGGXCorrelated(float linearRoughness, float NoV, float NoL) {
  float a2 = linearRoughness * linearRoughness;
  float lambdaV = NoL * sqrt((NoV - a2 * NoV) * NoV + a2);
  float lambdaL = NoV * sqrt((NoL - a2 * NoL) * NoL + a2);
  float v = 0.5 / (lambdaV + lambdaL);
  // a2=0 => v = 1 / 4*NoL*NoV   => min=1/4, max=+inf
  // a2=1 => v = 1 / 2*(NoL+NoV) => min=1/4, max=+inf
  // clamp to the maximum value representable in mediump
  return saturateMediump(v);
}

// Hammon 2017, "PBR Diffuse Lighting for GGX+Smith Microsurfaces"
float V_SmithGGXCorrelated_Fast(float linearRoughness, float NoV, float NoL) {
  float v = 0.5 / mix(2.0 * NoL * NoV, NoL + NoV, linearRoughness);
  return saturateMediump(v);
}

// Heitz 2014, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs"
float V_SmithGGXCorrelated_Anisotropic(float at, float ab, float ToV, float BoV, float ToL, float BoL, float NoV, float NoL) {
  float lambdaV = NoL * length(vec3(at * ToV, ab * BoV, NoV));
  float lambdaL = NoV * length(vec3(at * ToL, ab * BoL, NoL));
  float v = 0.5 / (lambdaV + lambdaL);
  return saturateMediump(v);
}

// Kelemen 2001, "A Microfacet Based Coupled Specular-Matte BRDF Model with Importance Sampling"
float V_Kelemen(float LoH) {
  return saturateMediump(0.25 / (LoH * LoH));
}

// Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886"
float V_Neubelt(float NoV, float NoL) {
  return saturateMediump(1.0 / (4.0 * (NoL + NoV - NoL * NoV)));
}

float visibility(float linearRoughness, float NoV, float NoL) {
  #if !defined(TARGET_MOBILE)
    return V_SmithGGXCorrelated(linearRoughness, NoV, NoL);
  #else
    return V_SmithGGXCorrelated_Fast(linearRoughness, NoV, NoL);
  #endif
}

float visibilityAnisotropic(float linearRoughness, float at, float ab, float ToV, float BoV, float ToL, float BoL, float NoV, float NoL) {
  #if !defined(TARGET_MOBILE)
    return V_SmithGGXCorrelated(linearRoughness, NoV, NoL);
  #else
    return V_SmithGGXCorrelated_Anisotropic(at, ab, ToV, BoV, ToL, BoL, NoV, NoL);
  #endif
}

float visibilityClearCoat(float roughness, float linearRoughness, float LoH) {
  return V_Kelemen(LoH);
}

// Fresnel
// Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"
vec3 F_Schlick(const vec3 f0, float f90, float VoH) {
  return f0 + (f90 - f0) * pow(1.0 - VoH, 5.0);
}

vec3 F_Schlick(const vec3 f0, float VoH) {
  float f = pow(1.0 - VoH, 5.0);
  return f + f0 * (1.0 - f);
}

float F_Schlick(float f0, float f90, float VoH) {
  return f0 + (f90 - f0) * pow(1.0 - VoH, 5.0);
}

vec3 fresnel(const vec3 f0, float LoH) {
  #if defined(TARGET_MOBILE)
    return F_Schlick(f0, LoH); // f90 = 1.0
  #else
    float f90 = saturate(dot(f0, vec3(50.0 * 0.33)));
    return F_Schlick(f0, f90, LoH);
  #endif
}

// Diffuse
float DiffuseLambert() {
  return 1.0 / PI;
}

// Burley 2012, "Physically-Based Shading at Disney"
float DiffuseBurley(float linearRoughness, float NoV, float NoL, float LoH) {
  float f90 = 0.5 + 2.0 * linearRoughness * LoH * LoH;
  float lightScatter = F_Schlick(1.0, f90, NoL);
  float viewScatter  = F_Schlick(1.0, f90, NoV);
  return lightScatter * viewScatter * (1.0 / PI);
}
`
<commit_msg>Clean up brdf<commit_after>module.exports = /* glsl */`
uniform float uReflectance;

// https://google.github.io/filament/Filament.md.html#materialsystem/specularbrdf
// Distribution
// Walter et al. 2007, "Microfacet Models for Refraction through Rough Surfaces"
float D_GGX(float linearRoughness, float NoH, const vec3 h, const vec3 normalWorld) {
#if defined(TARGET_MOBILE)
  vec3 NxH = cross(normalWorld, h);
  float oneMinusNoHSquared = dot(NxH, NxH);
#else
  float oneMinusNoHSquared = 1.0 - NoH * NoH;
#endif

  float a = NoH * linearRoughness;
  float k = linearRoughness / (oneMinusNoHSquared + a * a);
  float d = k * k * (1.0 / PI);
  return saturateMediump(d);
}

float distribution(float linearRoughness, float NoH, const vec3 h, const vec3 normalWorld) {
  return D_GGX(linearRoughness, NoH, h, normalWorld);
}

float distributionClearCoat(float linearRoughness, float NoH, const vec3 h, const vec3 normalWorld) {
  return D_GGX(linearRoughness, NoH, h, normalWorld);
}

// Visibility
// Heitz 2014, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs"
float V_SmithGGXCorrelated(float linearRoughness, float NoV, float NoL) {
  float a2 = linearRoughness * linearRoughness;
  float lambdaV = NoL * sqrt((NoV - a2 * NoV) * NoV + a2);
  float lambdaL = NoV * sqrt((NoL - a2 * NoL) * NoL + a2);
  float v = 0.5 / (lambdaV + lambdaL);
  // a2=0 => v = 1 / 4*NoL*NoV   => min=1/4, max=+inf
  // a2=1 => v = 1 / 2*(NoL+NoV) => min=1/4, max=+inf
  // clamp to the maximum value representable in mediump
  return saturateMediump(v);
}

// Hammon 2017, "PBR Diffuse Lighting for GGX+Smith Microsurfaces"
float V_SmithGGXCorrelated_Fast(float linearRoughness, float NoV, float NoL) {
  float v = 0.5 / mix(2.0 * NoL * NoV, NoL + NoV, linearRoughness);
  return saturateMediump(v);
}

// Kelemen 2001, "A Microfacet Based Coupled Specular-Matte BRDF Model with Importance Sampling"
float V_Kelemen(float LoH) {
  return saturateMediump(0.25 / (LoH * LoH));
}

// Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886"
float V_Neubelt(float NoV, float NoL) {
  return saturateMediump(1.0 / (4.0 * (NoL + NoV - NoL * NoV)));
}

float visibility(float linearRoughness, float NoV, float NoL) {
  #if !defined(TARGET_MOBILE)
    return V_SmithGGXCorrelated(linearRoughness, NoV, NoL);
  #else
    return V_SmithGGXCorrelated_Fast(linearRoughness, NoV, NoL);
  #endif
}

float visibilityClearCoat(float roughness, float linearRoughness, float LoH) {
  return V_Kelemen(LoH);
}

// Fresnel
// Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"
vec3 F_Schlick(const vec3 f0, float f90, float VoH) {
  return f0 + (f90 - f0) * pow(1.0 - VoH, 5.0);
}

vec3 F_Schlick(const vec3 f0, float VoH) {
  float f = pow(1.0 - VoH, 5.0);
  return f + f0 * (1.0 - f);
}

float F_Schlick(float f0, float f90, float VoH) {
  return f0 + (f90 - f0) * pow(1.0 - VoH, 5.0);
}

vec3 fresnel(const vec3 f0, float LoH) {
  #if defined(TARGET_MOBILE)
    return F_Schlick(f0, LoH); // f90 = 1.0
  #else
    float f90 = saturate(dot(f0, vec3(50.0 * 0.33)));
    return F_Schlick(f0, f90, LoH);
  #endif
}

// Diffuse
float DiffuseLambert() {
  return 1.0 / PI;
}

// Burley 2012, "Physically-Based Shading at Disney"
float DiffuseBurley(float linearRoughness, float NoV, float NoL, float LoH) {
  float f90 = 0.5 + 2.0 * linearRoughness * LoH * LoH;
  float lightScatter = F_Schlick(1.0, f90, NoL);
  float viewScatter  = F_Schlick(1.0, f90, NoV);
  return lightScatter * viewScatter * (1.0 / PI);
}
`
<|endoftext|>


<commit_before>'use strict';

var request = require('request');

var URL_BITLY = /bit\.ly\//;
var URL_ISGD = /is\.gd\//;
var URL_TCO = /t\.co\//;
var URL_JMP = /j\.mp\//;
var URL_TINYURL = /tinyurl\.com\//;

// Get the real url if this is a short url
// Assuming short urls are under 25 characters
exports.process = function(media, url, quoteFix, client, callback) {
  var resp = {
    media: media,
    url: url
  };

  if (quoteFix.length < 28 &&
     (quoteFix.match(URL_BITLY) ||
     quoteFix.match(URL_ISGD) ||
     quoteFix.match(URL_TCO) ||
     quoteFix.match(URL_JMP) ||
     quoteFix.match(URL_TINYURL))) {

    if (!media.match(/^http:\/\//) && !media.match(/^https:\/\//)) {
      media = 'http://' + media;
      quoteFix = 'http://' + quoteFix;
    }

    client.get('shorturl:' + quoteFix, function(err, url) {
      if (err) {
        callback(null, resp);

      } else {
        if (!url) {
          request({
            method: 'HEAD',
            url: quoteFix,
            followAllRedirects: true }, function (errCheck, response) {
              if (errCheck) {
                callback(null, resp);

              } else {
                resp = {
                  media: response.request.href,
                  url: response.request.href.split('/')
                }

                client.set('shorturl:' + quoteFix, response.request.href);
                client.expire('shorturl:' + quoteFix, 60 * 60 * 12) // 12 hours
                callback(null, resp);
              }
          });

        } else {
          resp = {
            media: url,
            url: url.split('/')
          }

          callback(null, resp);
        }
      }
    });

  } else {
    callback(null, resp);
  }
};
<commit_msg>reduce ttl<commit_after>'use strict';

var request = require('request');

var URL_BITLY = /bit\.ly\//;
var URL_ISGD = /is\.gd\//;
var URL_TCO = /t\.co\//;
var URL_JMP = /j\.mp\//;
var URL_TINYURL = /tinyurl\.com\//;

// Get the real url if this is a short url
// Assuming short urls are under 25 characters
exports.process = function(media, url, quoteFix, client, callback) {
  var resp = {
    media: media,
    url: url
  };

  if (quoteFix.length < 28 &&
     (quoteFix.match(URL_BITLY) ||
     quoteFix.match(URL_ISGD) ||
     quoteFix.match(URL_TCO) ||
     quoteFix.match(URL_JMP) ||
     quoteFix.match(URL_TINYURL))) {

    if (!media.match(/^http:\/\//) && !media.match(/^https:\/\//)) {
      media = 'http://' + media;
      quoteFix = 'http://' + quoteFix;
    }

    client.get('shorturl:' + quoteFix, function(err, url) {
      if (err) {
        callback(null, resp);

      } else {
        if (!url) {
          request({
            method: 'HEAD',
            url: quoteFix,
            followAllRedirects: true }, function (errCheck, response) {
              if (errCheck) {
                callback(null, resp);

              } else {
                resp = {
                  media: response.request.href,
                  url: response.request.href.split('/')
                }

                client.set('shorturl:' + quoteFix, response.request.href);
                client.expire('shorturl:' + quoteFix, 60 * 60 * 6) // 6 hours
                callback(null, resp);
              }
          });

        } else {
          resp = {
            media: url,
            url: url.split('/')
          }

          callback(null, resp);
        }
      }
    });

  } else {
    callback(null, resp);
  }
};
<|endoftext|>


<commit_before>//let React = require('react');
//let ReactDOM = require('react-dom');

var Cell = function (props) {
    return (
        	);
}

var Board = function (props) {
    var rows = [];

    for (let i = 1; i <= props.boardHeight; i++) {
        let cells = [];

        for (let j = 1; j <= props.boardWidth; j++) {
            let id = createId(i, j),
                alive = props.cells[id].alive ? true : false;
            cells.push(
                <Cell
                    id={id}
                    key={id}
                    alive={alive}
                    handleCellClick={props.handleCellClick} />
            );
        }
        rows.push(
{cells}
);
    }

    return (

{rows}

);
};

var Form = React.createClass({
    getInitialState: function () {
        return {
            boardWidth: this.props.boardWidth,
            boardHeight: this.props.boardHeight
        };
    },
    render: function () {
        return (
            <form onSubmit={this._onSubmit}>

                    Height
                    <input
                        id="boardHeight"
                        value={this.state.boardHeight}
                        type="text"
                        onChange={this._onHeightInput}
                        />

                    Width
                    <input
                        id="boardWidth"
                        value={this.state.boardWidth}
                        type="text"
                        onChange={this._onWidthInput}
                        />

                <button type="submit">submit</button>
                <button type="" onClick={this.props.handleStartClick}>start</button>
                <button type="" onClick={this.props.handleStopClick}>stop</button>
            </form>
        );
    },
    _onWidthInput: function (e) {
        if (typeof e.target.value === "string") {
            this.setState({ boardWidth: e.target.value });
        }
    },
    _onHeightInput: function (e) {
        if (typeof e.target.value === "string") {
            this.setState({ boardHeight: e.target.value });
        }
    },
    _onSubmit: function (e) {
        e.preventDefault();

        this.props.onBoardSizeChange({
            boardHeight: this.state.boardHeight,
            boardWidth: this.state.boardWidth
        });
    }
});

var Game = React.createClass({
    getInitialState: function () {
        let height = 20,
            width = 20;

        return {
            boardHeight: height,
            boardWidth: width,
            cells:{}
        };
    },
    componentWillMount: function(){
       this._populateCells(this.state.boardHeight, this.state.boardWidth);
    },
    render: function () {
        return (

                <Board
                    boardWidth={this.state.boardWidth}
                    boardHeight={this.state.boardHeight}
                    handleCellClick={this._handleCellClick}
                    cells={this.state.cells}
                    />
                <Form
                    onBoardSizeChange={this._updateBoard}
                    boardWidth={this.state.boardWidth}
                    boardHeight={this.state.boardHeight}
                    handleStartClick={this._handleStartClick}
                    handleStopClick={this._handleStopClick}
                    />

        );
    },
    _updateBoard: function (boardSize) {
        this.setState({
            boardWidth: boardSize.boardWidth,
            boardHeight: boardSize.boardHeight
        });
    },
    _handleCellClick: function (e) {
        let cells = Object.assign({}, this.state.cells);
        cells[e.target.id].alive = cells[e.target.id].alive ? false : true;

        this.setState({ cells: cells });
    },
    _populateCells: function (height, width) {
        let cells = {};

        for (let i = 1; i <= width; i++) {
            for (let j = 1; j <= height; j++) {
                let id = createId(i, j);
                cells[id] = cell(i, j);
            }
        }
        this.setState({cells: cells}, function(){
            console.log(this.state.cells);
        });
    },
    _handleStartClick: function () {
        let self = this;
        let interval = setInterval(function(){
            self._runGeneration();
        }, 200);

        this.setState({interval: interval});
    },
    _handleStopClick: function(){
       clearInterval(this.state.interval);
    },
    _runGeneration: function () {
        let cells = Object.assign({}, this.state.cells);

        for (let id in cells) {
            let alive = 0;
            cells[id]
                .neighbors
                .forEach(function (x) {
                    if (cells[x] && cells[x].alive) {
                        alive += 1;
                    }
            });

            cells[id].liveNeighbors = alive;
        }

        for (let id in cells) {
            let cell = cells[id];
            if (cell.liveNeighbors < 2){
                cell.alive = false;
            }

            if (cell.alive && cell.liveNeighbors > 3){
                cell.alive = false;
            }

            if (!cell.alive && cell.liveNeighbors === 3){
                cell.alive = true;
            }
        }

        this.setState({ cells: cells });
    }

});

function createId(x, y) {
    return .5 * (x + y) * (x + y + 1) + y;
}

function cell(x, y) {
    return {
        alive: false,
        liveNeighbors: 0,
        neighbors: findNeighbors(x, y)
    };

    function findNeighbors(x, y) {
        return [
            createId(x - 1, y - 1),
            createId(x + 1, y),
            createId(x, y + 1),
            createId(x + 1, y + 1),
            createId(x, y - 1),
            createId(x + 1, y - 1),
            createId(x - 1, y + 1),
            createId(x - 1, y)
        ];
    }

}

ReactDOM.render(<Game/>, document.getElementById('game'));
<commit_msg>implemented generation counter<commit_after>//let React = require('react');
//let ReactDOM = require('react-dom');

var Cell = function (props) {
    return (
        	);
}

var Board = function (props) {
    var rows = [];

    for (let i = 1; i <= props.boardHeight; i++) {
        let cells = [];

        for (let j = 1; j <= props.boardWidth; j++) {
            let id = createId(i, j),
                alive = props.cells[id].alive ? true : false;
            cells.push(
                <Cell
                    id={id}
                    key={id}
                    alive={alive}
                    handleCellClick={props.handleCellClick} />
            );
        }
        rows.push(
{cells}
);
    }

    return (

{rows}

);
};

var Form = React.createClass({
    getInitialState: function () {
        return {
            boardWidth: this.props.boardWidth,
            boardHeight: this.props.boardHeight
        };
    },
    render: function () {
        return (
            <form onSubmit={this._onSubmit}>

                    Height
                    <input
                        id="boardHeight"
                        value={this.state.boardHeight}
                        type="text"
                        onChange={this._onHeightInput}
                        />

                    Width
                    <input
                        id="boardWidth"
                        value={this.state.boardWidth}
                        type="text"
                        onChange={this._onWidthInput}
                        />

                <button type="submit">submit</button>
                <button type="" onClick={this.props.handleStartClick}>start</button>
                <button type="" onClick={this.props.handleStopClick}>stop</button>
            </form>
        );
    },
    _onWidthInput: function (e) {
        if (typeof e.target.value === "string") {
            this.setState({ boardWidth: e.target.value });
        }
    },
    _onHeightInput: function (e) {
        if (typeof e.target.value === "string") {
            this.setState({ boardHeight: e.target.value });
        }
    },
    _onSubmit: function (e) {
        e.preventDefault();

        this.props.onBoardSizeChange({
            boardHeight: this.state.boardHeight,
            boardWidth: this.state.boardWidth
        });
    }
});

var Game = React.createClass({
    getInitialState: function () {
        let height = 20,
            width = 20;

        return {
            boardHeight: height,
            boardWidth: width,
            generation: 0,
            cells:{}
        };
    },
    componentWillMount: function(){
       this._populateCells(this.state.boardHeight, this.state.boardWidth);
    },
    render: function () {
        return (

                <Board
                    boardWidth={this.state.boardWidth}
                    boardHeight={this.state.boardHeight}
                    handleCellClick={this._handleCellClick}
                    cells={this.state.cells}
                    />
                <Form
                    onBoardSizeChange={this._updateBoard}
                    boardWidth={this.state.boardWidth}
                    boardHeight={this.state.boardHeight}
                    handleStartClick={this._handleStartClick}
                    handleStopClick={this._handleStopClick}
                    />

{this.state.generation}

        );
    },
    _updateBoard: function (boardSize) {
        this.setState({
            boardWidth: boardSize.boardWidth,
            boardHeight: boardSize.boardHeight
        });
    },
    _handleCellClick: function (e) {
        let cells = Object.assign({}, this.state.cells);
        cells[e.target.id].alive = cells[e.target.id].alive ? false : true;

        this.setState({ cells: cells });
    },
    _populateCells: function (height, width) {
        let cells = {};

        for (let i = 1; i <= width; i++) {
            for (let j = 1; j <= height; j++) {
                let id = createId(i, j);
                cells[id] = cell(i, j);
            }
        }
        this.setState({cells: cells}, function(){
            console.log(this.state.cells);
        });
    },
    _handleStartClick: function () {
        let self = this;
        let interval = setInterval(function(){
            self._runGeneration();
        }, 200);

        this.setState({interval: interval});
    },
    _handleStopClick: function(){
       clearInterval(this.state.interval);
    },
    _runGeneration: function () {
        let cells = Object.assign({}, this.state.cells);

        for (let id in cells) {
            let alive = 0;
            cells[id]
                .neighbors
                .forEach(function (x) {
                    if (cells[x] && cells[x].alive) {
                        alive += 1;
                    }
            });

            cells[id].liveNeighbors = alive;
        }

        for (let id in cells) {
            let cell = cells[id];
            if (cell.liveNeighbors < 2){
                cell.alive = false;
            }

            if (cell.alive && cell.liveNeighbors > 3){
                cell.alive = false;
            }

            if (!cell.alive && cell.liveNeighbors === 3){
                cell.alive = true;
            }
        }

        this.setState({ cells: cells });
        this.setState({generation: this.state.generation + 1});
    }

});

function createId(x, y) {
    return .5 * (x + y) * (x + y + 1) + y;
}

function cell(x, y) {
    return {
        alive: false,
        liveNeighbors: 0,
        neighbors: findNeighbors(x, y)
    };

    function findNeighbors(x, y) {
        return [
            createId(x - 1, y - 1),
            createId(x + 1, y),
            createId(x, y + 1),
            createId(x + 1, y + 1),
            createId(x, y - 1),
            createId(x + 1, y - 1),
            createId(x - 1, y + 1),
            createId(x - 1, y)
        ];
    }

}

ReactDOM.render(<Game/>, document.getElementById('game'));
<|endoftext|>


<commit_before>$(function () {

    $('.list.accordion').on('click', 'a', function (event) {
        event.preventDefault();

        // Toggle slide animation and "active" class for sublist
        var $target = $(event.target).closest('li');
        $target.children('ul,ol').slideToggle('fast', function () {
            $target.toggleClass('active');
        });
    });

});<commit_msg>Fix U+FEFF but in nav/list.js<commit_after>$(function () {

    $('.list.accordion').on('click', 'a', function (event) {
        event.preventDefault();

        // Toggle slide animation and "active" class for sublist
        var $target = $(event.target).closest('li');
        $target.children('ul,ol').slideToggle('fast', function () {
            $target.toggleClass('active');
        });
    });

});<|endoftext|>


<commit_before>// Check My Links by Paul Livingstone
// @ocodia

String.prototype.startsWith = function(text) {
  return this.substr(0, text.length) == text;
};

String.prototype.contains = function(text) {
  return this.indexOf(text) !== -1;
};

function removeClassFromElements(classname) {
    var x = document.getElementsByClassName(classname);
    var i;
    for (i = 0; i < x.length; i++) {
        x[i].classList.remove(classname);
    }
}

chrome.extension.onMessage.addListener(

  function doStuff(request, sender) {
  // Gather links
  var pageLinks = document.getElementsByTagName('a');
  var totalvalid = pageLinks.length;
  var queued = 0;
  var checked = 0;
  var invalid = 0;
  var passed = 0;
  var rpBox;
  // Clear the Previous Run
  if(document.getElementById("CMY_ReportBox")){
      document.getElementById("CMY_ReportBox").remove();
  }
  removeClassFromElements("CMY_Link");
  removeClassFromElements("CMY_Valid");
  removeClassFromElements("CMY_Invalid");

  (
  function(pg){

    var blacklist = request.bl;
    blacklist = blacklist.split("\n");

    var blacklisted;

    // Inject Styles and Elements for feedback report

    var reportStyle = document.createElement("style");
    reportStyle.setAttribute("rel", "stylesheet");
    reportStyle.setAttribute("type", "text/css");
    document.getElementsByTagName("head")[0].appendChild(reportStyle);

    reportStyle.appendChild(document.createTextNode(".CMY_Link{background: #333 !important; color: #fff !important; font-weight: bold; border-right: 1px solid #fff;}"));
    reportStyle.appendChild(document.createTextNode(".CMY_Invalid{background: #990000 !important; color: #fff !important;}"));
    reportStyle.appendChild(document.createTextNode(".CMY_Valid{background: #669900 !important; color: #fff !important;}"));
    reportStyle.appendChild(document.createTextNode(".CMY_Response{color:#fff; border-left: 1px solid #fff; padding: 0px 5px; margin: 0px 0px 0px 5px;}"));
    reportStyle.appendChild(document.createTextNode("#CMY_ReportBox{font-weight: bold; width: 180px; position: fixed; right:0px; top: 0px; background: #fff; margin: 20px; padding: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 14px; line-height: 14px; border-radius: 5px; z-index: 9999; box-shadow: 0px 0px 3px(0,0,0,0.2);}"));
    reportStyle.appendChild(document.createTextNode("#CMY_RB_Header{border-radius: 5px 5px 0px 0px; border-bottom: 1px solid #444; background: -webkit-gradient(linear, center top, center bottom, from(#777), to(#3B3B3B)); text-align: center; color: #000; font-size: 12px; padding: 5px; margin: 0px; text-shadow: 1px 1px 1px #666;}"));
    reportStyle.appendChild(document.createTextNode("#CMY_ReportBox .CMY_RB_ResultCount{font-size: 14px; box-sizing: border-box; width: 50%; color: #fff; font-weight: bold; line-height: 14px; text-shadow: 0px 0px 4px rgba(0,0,0,0.3); text-align: left; padding: 10px 10px 10px 40px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAABQCAYAAAD2gj5JAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAR2SURBVHja7JjdaxxVGMbPObM7HzszuwkoVdv+DSJCK2oilaz1o4KBJqYVTW+0ou2NjZZaQ2vTIoGoTa010gixjbtJm1KF9qZ3ghdeFgreeKeIopjd7Mxukt3sOT5nsklnZ2aTGPVCmIHDZnfe85vnvO/znjCHCiHIv33RGLrpyV29dp+SJPlEgsqv3Te/LH39j6ASmNDIZdNmCd1k8qfqvMv3VRx+c1NQAHsBnAKQ2m0KUQ1PKVmc5/NukWcTm1T4lR/IPKGkrmr0mGawOyFo14v2IFPIlls551AL4CSALADknJOBWpWcy31YEE3LB/AdPG1YNymhlHx67cLcocCS8xFAITh5a3FBnJs4M8ubCgXguwCeMTOMmGkmoQRJPz89Wjyc7bN7lARymA4rBPAIgJ8AWA9ZavdL9s9WG9uWbsckbTnxtaog5RL/bqEidiRVolqZMPDzwT/PBtPEVumM7Esk6S9Q5KnEd5JUKbEy7PG2e5hqt4eWLBWOrmv+F17L7LLbWd4w2RYUa/kSkiAjlx/WUDjQyGF9Qx3VfTDTabWznJFiWz1VtOl2HVU+Ul0Gir/VpgB3IL85PcW2KcoqeKXKo2sB12xTgHdJMFJxHxTXETYQrPKmNhSAn0QqxjSdXlyqkZH1FK5ca7ZpxeXf4qOzZtC5qbNFEW/SMTSGxtAYGkNjaAyNoTE0hsbQGPo/ghIJ9Y+sbvY/rVt/PKtbvcF7/tGlmzt26+YPiHs/eK9J6VOG9UqS0LEUpUaS0nJViAMzldJMUEjWsHYmCL1qULpdp5QvEXLiSnnudGj5AL4K4HmTMdWijCTxOg6o4wref7Vcuu4DPgrgFB683cLrNaB4xSYEcUMYIzcqTmn1uEMh9DgCPaCGQEzEBGbj+0SPme5uPPgRqVACbQANxMo4FfGIO2pS9nDTGQr+OIolF6RC5jtgATiNCZM9ZuYUVE0C+IDtKWRk5UQEU5Ywd1Aj9PtQ9fem0j2YMC5BzJdDedi0iLgahjwr1HxAXEu4fxypGvnCLfBIS2GpfVA2BnDGDxaN0bQ8pB2UY585sx9FHiGtXCjKFBL++oLgv3O/oRvBvgnlhsKPN2x+5PA9m7IhWTQW5W9C8hec2f1Rc6PiZZV3LsJKMoet+g2/Z/uttr0balP48DHYJC9tk25UuYVSWTyn5Pl47npLKIAdAE4DeL/l+ZBK/7ZscZlz5N5FDQ6gFtdCUAA7AcwBuDXoQ3mWiKhvMJ7AI+6lYfACwC8DPNOUUwDGjGggB+wUqrx/XvA3sOQSDxQF8bpNlUuwY0cASqfRMXXNW/JdYwM4COAH426hNuEWZxzBD0JZCIxWvaIT9mMTFEFD2G1OgsIbWZb7xEkAhwFcPYrDbiR9LMEOv1u0iboQhy+Xi7+FCrXHsCl2qRPw59vo5WFY6vR4o/UifNyPuGEovAXgmxfdgtPSUntSdhq7zYPYHG5fKhedVpV/zrDVFKMPYck/QeGv6+38TH4+b1h0rZ1fjmd0S4mK+0/+R/0lwAD2yuPPDbbSegAAAABJRU5ErkJggg%3D%3D); background-repeat: no-repeat;}"));
    reportStyle.appendChild(document.createTextNode("#CMY_ReportBox .CMY_RB_LinkCounts{text-align: center; background: #111; font-size: 11px; font-weight: bold; padding: 0px 0px 10px 0px; box-sizing: border-box; color: #fff; line-height: 12px; width: 50%;}"));
    reportStyle.appendChild(document.createTextNode("#CMY_ReportBox #CMY_RB_LC_Left{float: left;}"));
    reportStyle.appendChild(document.createTextNode("#CMY_ReportBox #CMY_RB_LC_Right{float: right; color: #f59703;}"));
    reportStyle.appendChild(document.createTextNode("#CMY_ReportBox #CMY_RB_Perc{font-size: 50px; line-height: 50px; color:#fff; background: #111; padding: 10px; text-shadow: 0px 0px 5px rgba(255,255,255,0.8); text-align: center;}"));
    reportStyle.appendChild(document.createTextNode("#CMY_ReportBox #CMY_RB_Pass{border-top: 1px solid #bddf5d; border-right: 1px solid #8db615; float:left; border-radius: 0px 0px 0px 5px; background-color:#9fcd19; background-position-x: 8px; background-position-y: 5px;}"));
    reportStyle.appendChild(document.createTextNode("#CMY_ReportBox #CMY_RB_Fail{border-top: 1px solid #c54f4f; float: right; border-radius: 0px 0px 5px 0px; background-color: #a9060a; background-position-x: 8px; background-position-y: -52px;}"));

    var reportBox = document.createElement("div");
    var rbHeader = document.createElement("div");
    var rbPerc = document.createElement("div");
    var rbAmt = document.createElement("div");
    var rbQueue = document.createElement("div");
    var rbPass = document.createElement("div");
    var rbFail = document.createElement("div");

    reportBox.setAttribute("id", "CMY_ReportBox");
    rbHeader.setAttribute("id", "CMY_RB_Header");
    rbHeader.innerHTML = "Link Results";
    rbPerc.setAttribute("id", "CMY_RB_Perc");

    rbAmt.setAttribute("id", "CMY_RB_LC_Left");
    rbAmt.setAttribute("class", "CMY_RB_LinkCounts");

    rbQueue.setAttribute("id", "CMY_RB_LC_Right");
    rbQueue.setAttribute("class", "CMY_RB_LinkCounts");

    rbPass.setAttribute("id", "CMY_RB_Pass");
    rbPass.setAttribute("class", "CMY_RB_ResultCount");
    rbFail.setAttribute("id", "CMY_RB_Fail");
    rbFail.setAttribute("class", "CMY_RB_ResultCount");

    document.getElementsByTagName("body")[0].appendChild(reportBox);
    rpBox = document.getElementById("CMY_ReportBox");

    rpBox.appendChild(rbHeader);
    rpBox.appendChild(rbPerc);
    rpBox.appendChild(rbAmt);
    rpBox.appendChild(rbQueue);
    rpBox.appendChild(rbPass);
    rpBox.appendChild(rbFail);

    rpBoxPerc = document.getElementById("CMY_RB_Perc");
    rpBoxAmt = document.getElementById("CMY_RB_LC_Left");
    rpBoxQueue = document.getElementById("CMY_RB_LC_Right");
    rpBoxPass = document.getElementById("CMY_RB_Pass");
    rpBoxFail = document.getElementById("CMY_RB_Fail");

    rpBoxPerc.innerHTML = "0%";
    rpBoxAmt.innerHTML = "Links: 0";
    rpBoxQueue.innerHTML = "Queue: 0";
    rpBoxPass.innerHTML = "0";
    rpBoxFail.innerHTML = "0";

    // Run through links, add feedback classes and ignore empty href and non http* links
    for (var i = 0; i < pg.length; i++){

      var link = pg[i];
      var url = link.href;
      var rel = link.rel;
      blacklisted = false;

      if (url.length > 0 && url.startsWith('http') && rel !== "nofollow"){
        for (var b = 0; b < blacklist.length; b++)
        {
          if (blacklist[b] !== "" && url.contains(blacklist[b])){
            blacklisted = true;
          }
        }

        if (blacklisted === true){
          console.log("Skipped (blacklisted): " + url);
          totalvalid -=1;
        }
        else{
          queued +=1;
          link.classList.add("CMY_Link");
          checkURL(url, link);
          //console.log("Checking:" + url);
        }

      }
      else{
        console.log("Skipped: " + url);
        totalvalid -=1;
      }
    }

    rpBoxAmt.innerHTML = "Links: " + totalvalid;
    // Remove the event listener in the event this is run again without reloading
    chrome.extension.onMessage.removeListener(doStuff);
  }(pageLinks)
  )

  // Send links to get checked via XHR
  function checkURL(url, link) {
    chrome.extension.sendMessage({"action": "check", "url": url},
    function (response) {
      if (response) {
        if (200 <= response && response < 400) {
          link.classList.add("CMY_Valid");
          queued -=1;
          passed +=1;
          checked +=1;
          rpBoxPass.innerHTML = passed;
        }
        else {
          console.log("Response " + response + ": " + url);
          link.classList.add("CMY_Invalid");
          link.innerHTML += " " + response + "";
          queued -=1;
          invalid +=1;
          checked += 1;
          rpBoxFail.innerHTML = invalid;
        }
        rpBoxPerc.innerHTML = Math.round((checked)/totalvalid * 100) + "%";
        rpBoxQueue.innerHTML = "Queue: " + queued;
      }
    });
  }
    return true;

  });

<commit_msg>Close UI Button<commit_after>// Check My Links by Paul Livingstone
// @ocodia

String.prototype.startsWith = function(text) {
  return this.substr(0, text.length) == text;
};

String.prototype.contains = function(text) {
  return this.indexOf(text) !== -1;
};

function removeClassFromElements(classname) {
    var x = document.getElementsByClassName(classname);
    var i;
    for (i = 0; i < x.length; i++) {
        x[i].classList.remove(classname);
    }
}

function removeDOMElement(id){
  if(document.getElementById(id)){
      document.getElementById(id).remove();
  }
}

chrome.extension.onMessage.addListener(

  function doStuff(request, sender) {
  // Gather links
  var pageLinks = document.getElementsByTagName('a');
  var totalvalid = pageLinks.length;
  var queued = 0;
  var checked = 0;
  var invalid = 0;
  var passed = 0;
  var rpBox;
  // Clear the Previous Run
  removeDOMElement("CMY_ReportBox");
  removeClassFromElements("CMY_Link");
  removeClassFromElements("CMY_Valid");
  removeClassFromElements("CMY_Invalid");

  (
  function(pg){

    var blacklist = request.bl;
    blacklist = blacklist.split("\n");

    var blacklisted;

    // Inject Styles and Elements for feedback report

    var reportStyle = document.createElement("style");
    reportStyle.setAttribute("rel", "stylesheet");
    reportStyle.setAttribute("type", "text/css");
    document.getElementsByTagName("head")[0].appendChild(reportStyle);

    reportStyle.appendChild(document.createTextNode(".CMY_Link{background: #333 !important; color: #fff !important; font-weight: bold; border-right: 1px solid #fff;}"));
    reportStyle.appendChild(document.createTextNode(".CMY_Invalid{background: #990000 !important; color: #fff !important;}"));
    reportStyle.appendChild(document.createTextNode(".CMY_Valid{background: #669900 !important; color: #fff !important;}"));
    reportStyle.appendChild(document.createTextNode(".CMY_Response{color:#fff; border-left: 1px solid #fff; padding: 0px 5px; margin: 0px 0px 0px 5px;}"));
    reportStyle.appendChild(document.createTextNode("#CMY_ReportBox{font-weight: bold; width: 180px; position: fixed; right:0px; top: 0px; background: #fff; margin: 20px; padding: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 14px; line-height: 14px; border-radius: 5px; z-index: 9999; box-shadow: 0px 0px 3px(0,0,0,0.2);}"));
    reportStyle.appendChild(document.createTextNode("#CMY_RB_Header{border-radius: 5px 5px 0px 0px; border-bottom: 1px solid #444; background: -webkit-gradient(linear, center top, center bottom, from(#777), to(#3B3B3B)); text-align: center; color: #000; font-size: 12px; padding: 5px; margin: 0px; text-shadow: 1px 1px 1px #666;}"));
    reportStyle.appendChild(document.createTextNode("#CMY_ReportBox .CMY_RB_ResultCount{font-size: 14px; box-sizing: border-box; width: 50%; color: #fff; font-weight: bold; line-height: 14px; text-shadow: 0px 0px 4px rgba(0,0,0,0.3); text-align: left; padding: 10px 10px 10px 40px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAABQCAYAAAD2gj5JAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAR2SURBVHja7JjdaxxVGMbPObM7HzszuwkoVdv+DSJCK2oilaz1o4KBJqYVTW+0ou2NjZZaQ2vTIoGoTa010gixjbtJm1KF9qZ3ghdeFgreeKeIopjd7Mxukt3sOT5nsklnZ2aTGPVCmIHDZnfe85vnvO/znjCHCiHIv33RGLrpyV29dp+SJPlEgsqv3Te/LH39j6ASmNDIZdNmCd1k8qfqvMv3VRx+c1NQAHsBnAKQ2m0KUQ1PKVmc5/NukWcTm1T4lR/IPKGkrmr0mGawOyFo14v2IFPIlls551AL4CSALADknJOBWpWcy31YEE3LB/AdPG1YNymhlHx67cLcocCS8xFAITh5a3FBnJs4M8ubCgXguwCeMTOMmGkmoQRJPz89Wjyc7bN7lARymA4rBPAIgJ8AWA9ZavdL9s9WG9uWbsckbTnxtaog5RL/bqEidiRVolqZMPDzwT/PBtPEVumM7Esk6S9Q5KnEd5JUKbEy7PG2e5hqt4eWLBWOrmv+F17L7LLbWd4w2RYUa/kSkiAjlx/WUDjQyGF9Qx3VfTDTabWznJFiWz1VtOl2HVU+Ul0Gir/VpgB3IL85PcW2KcoqeKXKo2sB12xTgHdJMFJxHxTXETYQrPKmNhSAn0QqxjSdXlyqkZH1FK5ca7ZpxeXf4qOzZtC5qbNFEW/SMTSGxtAYGkNjaAyNoTE0hsbQGPo/ghIJ9Y+sbvY/rVt/PKtbvcF7/tGlmzt26+YPiHs/eK9J6VOG9UqS0LEUpUaS0nJViAMzldJMUEjWsHYmCL1qULpdp5QvEXLiSnnudGj5AL4K4HmTMdWijCTxOg6o4wref7Vcuu4DPgrgFB683cLrNaB4xSYEcUMYIzcqTmn1uEMh9DgCPaCGQEzEBGbj+0SPme5uPPgRqVACbQANxMo4FfGIO2pS9nDTGQr+OIolF6RC5jtgATiNCZM9ZuYUVE0C+IDtKWRk5UQEU5Ywd1Aj9PtQ9fem0j2YMC5BzJdDedi0iLgahjwr1HxAXEu4fxypGvnCLfBIS2GpfVA2BnDGDxaN0bQ8pB2UY585sx9FHiGtXCjKFBL++oLgv3O/oRvBvgnlhsKPN2x+5PA9m7IhWTQW5W9C8hec2f1Rc6PiZZV3LsJKMoet+g2/Z/uttr0balP48DHYJC9tk25UuYVSWTyn5Pl47npLKIAdAE4DeL/l+ZBK/7ZscZlz5N5FDQ6gFtdCUAA7AcwBuDXoQ3mWiKhvMJ7AI+6lYfACwC8DPNOUUwDGjGggB+wUqrx/XvA3sOQSDxQF8bpNlUuwY0cASqfRMXXNW/JdYwM4COAH426hNuEWZxzBD0JZCIxWvaIT9mMTFEFD2G1OgsIbWZb7xEkAhwFcPYrDbiR9LMEOv1u0iboQhy+Xi7+FCrXHsCl2qRPw59vo5WFY6vR4o/UifNyPuGEovAXgmxfdgtPSUntSdhq7zYPYHG5fKhedVpV/zrDVFKMPYck/QeGv6+38TH4+b1h0rZ1fjmd0S4mK+0/+R/0lwAD2yuPPDbbSegAAAABJRU5ErkJggg%3D%3D); background-repeat: no-repeat;}"));
    reportStyle.appendChild(document.createTextNode("#CMY_ReportBox .CMY_RB_LinkCounts{text-align: center; background: #111; font-size: 11px; font-weight: bold; padding: 0px 0px 10px 0px; box-sizing: border-box; color: #fff; line-height: 12px; width: 50%;}"));
    reportStyle.appendChild(document.createTextNode("#CMY_ReportBox #CMY_RB_LC_Left{float: left;}"));
    reportStyle.appendChild(document.createTextNode("#CMY_ReportBox #CMY_RB_LC_Right{float: right; color: #f59703;}"));
    reportStyle.appendChild(document.createTextNode("#CMY_ReportBox #CMY_RB_Perc{font-size: 50px; line-height: 50px; color:#fff; background: #111; padding: 10px; text-shadow: 0px 0px 5px rgba(255,255,255,0.8); text-align: center;}"));
    reportStyle.appendChild(document.createTextNode("#CMY_ReportBox #CMY_RB_Pass{border-top: 1px solid #bddf5d; border-right: 1px solid #8db615; float:left; border-radius: 0px 0px 0px 5px; background-color:#9fcd19; background-position-x: 8px; background-position-y: 5px;}"));
    reportStyle.appendChild(document.createTextNode("#CMY_ReportBox #CMY_RB_Fail{border-top: 1px solid #c54f4f; float: right; border-radius: 0px 0px 5px 0px; background-color: #a9060a; background-position-x: 8px; background-position-y: -52px;}"));
    reportStyle.appendChild(document.createTextNode("#CMY_ReportBox #CMY_RB_Close{float: right;color:#ffffff}"));

    var reportBox = document.createElement("div");
    var rbHeader = document.createElement("div");
    var rbPerc = document.createElement("div");
    var rbAmt = document.createElement("div");
    var rbQueue = document.createElement("div");
    var rbPass = document.createElement("div");
    var rbFail = document.createElement("div");
    var rbClose = document.createElement("div");
    rbClose.innerHTML = "X";
    rbClose.setAttribute("id", "CMY_RB_Close");

    reportBox.setAttribute("id", "CMY_ReportBox");
    rbHeader.setAttribute("id", "CMY_RB_Header");
    rbHeader.innerHTML = "Link Results";
    rbPerc.setAttribute("id", "CMY_RB_Perc");

    rbAmt.setAttribute("id", "CMY_RB_LC_Left");
    rbAmt.setAttribute("class", "CMY_RB_LinkCounts");

    rbQueue.setAttribute("id", "CMY_RB_LC_Right");
    rbQueue.setAttribute("class", "CMY_RB_LinkCounts");

    rbPass.setAttribute("id", "CMY_RB_Pass");
    rbPass.setAttribute("class", "CMY_RB_ResultCount");
    rbFail.setAttribute("id", "CMY_RB_Fail");
    rbFail.setAttribute("class", "CMY_RB_ResultCount");

    document.getElementsByTagName("body")[0].appendChild(reportBox);
    rpBox = document.getElementById("CMY_ReportBox");

    rbHeader.appendChild(rbClose);
    rpBox.appendChild(rbHeader);
    rpBox.appendChild(rbPerc);
    rpBox.appendChild(rbAmt);
    rpBox.appendChild(rbQueue);
    rpBox.appendChild(rbPass);
    rpBox.appendChild(rbFail);

    rpBoxPerc = document.getElementById("CMY_RB_Perc");
    rpBoxAmt = document.getElementById("CMY_RB_LC_Left");
    rpBoxQueue = document.getElementById("CMY_RB_LC_Right");
    rpBoxPass = document.getElementById("CMY_RB_Pass");
    rpBoxFail = document.getElementById("CMY_RB_Fail");

    rpBoxPerc.innerHTML = "0%";
    rpBoxAmt.innerHTML = "Links: 0";
    rpBoxQueue.innerHTML = "Queue: 0";
    rpBoxPass.innerHTML = "0";
    rpBoxFail.innerHTML = "0";

    // Run through links, add feedback classes and ignore empty href and non http* links
    for (var i = 0; i < pg.length; i++){

      var link = pg[i];
      var url = link.href;
      var rel = link.rel;
      blacklisted = false;

      if (url.length > 0 && url.startsWith('http') && rel !== "nofollow"){
        for (var b = 0; b < blacklist.length; b++)
        {
          if (blacklist[b] !== "" && url.contains(blacklist[b])){
            blacklisted = true;
          }
        }

        if (blacklisted === true){
          console.log("Skipped (blacklisted): " + url);
          totalvalid -=1;
        }
        else{
          queued +=1;
          link.classList.add("CMY_Link");
          checkURL(url, link);
          //console.log("Checking:" + url);
        }

      }
      else{
        console.log("Skipped: " + url);
        totalvalid -=1;
      }
    }

    rpBoxAmt.innerHTML = "Links: " + totalvalid;
    // When close element is clicked, hide UI
    document.getElementById("CMY_RB_Close").onclick=function(){removeDOMElement("CMY_ReportBox");};
    // Remove the event listener in the event this is run again without reloading
    chrome.extension.onMessage.removeListener(doStuff);
  }(pageLinks)
  )

  // Send links to get checked via XHR
  function checkURL(url, link) {
    chrome.extension.sendMessage({"action": "check", "url": url},
    function (response) {
      if (response) {
        if (200 <= response && response < 400) {
          link.classList.add("CMY_Valid");
          queued -=1;
          passed +=1;
          checked +=1;
          rpBoxPass.innerHTML = passed;
        }
        else {
          console.log("Response " + response + ": " + url);
          link.classList.add("CMY_Invalid");
          link.innerHTML += " " + response + "";
          queued -=1;
          invalid +=1;
          checked += 1;
          rpBoxFail.innerHTML = invalid;
        }
        rpBoxPerc.innerHTML = Math.round((checked)/totalvalid * 100) + "%";
        rpBoxQueue.innerHTML = "Queue: " + queued;
      }
    });
  }
    return true;

  });

<|endoftext|>