<commit_before>import Immutable from 'immutable';
import {isObject, consume} from './util';

class Type {
  constructor(value) {
    this.valid = undefined;
    value !== undefined && this.set(value);
    this._watchers = [];
  }

  observe(watcher) {
    this._watchers.push(watcher);
  }

  notifyWatchers(...args) {
    this._watchers.forEach(watcher => watcher(...args));
  }

  addError(error) {
    this.errors.push(error);
  }

  setDefault() {
    this.set(this.default);
  }

  hasValidator(validator) {
    return this.validatorFactories.indexOf(validator) !== -1;
  }

  get validatorFactories() {
    return this.validators.map(v => v.factory);
  }

  static clone(overrides) {
    class cloned extends this {};
    Object.assign(cloned.prototype, overrides);
    return cloned;
  }

  static named(name) {
    return this.clone({name});
  }

  static using(overrides) {
    // maybe pre-process overrides?
    return this.clone(overrides);
  }

  static validatedBy(...validators) {
    return this.clone({validators});
  }

  static fromDefaults() {
    let defaulted = new this();
    defaulted.setDefault();
    return defaulted;
  }
}

Type.prototype.default = undefined;
Type.prototype.validators = [];

class AdaptationError extends Error {};

class Scalar extends Type {
  constructor() {
    super();
    this._watchers = [];
    this.value = undefined;
  }

  get allErrors() {
    return this.errors;
  }

  set(raw) {
    try {
      this.value = this.adapt(raw);
    } catch (e) {
      this.value = undefined;
      this.notifyWatchers(false, this);
      return false;
    }
    this.notifyWatchers(true, this);

    return true;
  }

  validate(context) {
    this.errors = [];

    this.valid = this.validators.reduce((valid, v) => {
      return valid && v(this, context);
    }, true);

    return this.valid;
  }
}

class Bool extends Scalar {
  adapt(raw) {
    // TODO: more restrictive?
    return !!raw;
  }
}

class Str extends Scalar {
  adapt(raw) {
    return raw.toString();
  }
}

class Num extends Scalar {
  // ?
}

class Int extends Num {
  adapt(raw) {
    let value = parseInt(raw, 10);
    if (isNaN(value)) {
      throw new AdaptationError(`${value} is not a number`);
    }
    return value;
  }
}

class Enum extends Scalar {
  constructor(value) {
    super();
    this.childSchema = new this.childType();
    if (value !== undefined) {
      this.set(value);
    }
  }

  adapt(raw) {
    let value = this.childSchema.adapt(raw);
    if (!this.validValue(value)) {
      throw new AdaptationError();
    }
    return value;
  }

  validValue(value) {
    return this.validValues.indexOf(value) !== -1;
  }

  static of(childType) {
    return this.clone({childType});
  }

  static valued(validValues) {
    return this.clone({validValues})
  }
}

Enum.prototype.childType = Str;

class Container extends Type {
  validate(context) {
    this.errors = [];
    var success = !!this.memberValues.reduce((valid, member) => {
      var result = member.validate(context);
      return valid && result;
    }, true);
    this.valid = !!this.validators.reduce((valid, validator) => valid &= validator(this, context), success);
    return this.valid;
  }
}

class List extends Container {
  get value() {
    return Immutable.List(this.members.map(m => m.value));
  }

  get members() {
    return this._members;
  }

  // aliased for concordance with Container.prototype.validate()
  get memberValues() {
    return this._members;
  }

  set members(members) {
    this._members = members;
  }

  get allErrors() {
    return {
      self: this.errors,
      children: this.members.map(m => m.allErrors)
    };
  }

  // Attempt to convert each member of raw array to the
  // member type of the List. Any failure will result in an
  // empty array for this.members.

  // TODO: short-circuit conversion if any member fails.
  set(raw) {
    if (raw && raw.toJS) {
      raw = raw.toJS();
    }
    this.members = [];
    if (!(raw && raw.forEach)) {
      this.notifyWatchers(false, this);
      return false;
    }
    let success = true;
    let items = [];
    raw.forEach(mbr => {
      let member = new this.memberType();
      member.parent = this;
      success &= member.set(mbr);
      member.observe(this.notifyWatchers.bind(this));
      items.push(member);
    });
    this.members = success ? items : this.members;
    this.notifyWatchers(!!success, this);
    return !!success;
  }

  static of(type) {
    return this.clone({memberType: type});
  }
}

List.prototype.members = [];

class Map extends Container {
  constructor(value) {
    super(value);
    // construct an empty schema
    if (!this._members) {
      this.set({});
    }
  }

  get value() {
    return Immutable.Map(Object.keys(this._members).reduce((v, m) => {
      v[m] = this._members[m].value;
      return v;
    }, {}));
  }

  // member elements as list
  get memberValues() {
    return Object.values(this._members);
  }

  get members() {
    return this._members;
  }

  set members(members) {
    this._members = members;
  }

  get allErrors() {
    return {
      self: this.errors,
      children: Object.entries(this.members).reduce((errors, [k, v]) => {
        errors[k] = v.allErrors;
        return errors;
      }, {})
    };
  }

  set(raw, {notify = true} = {}) {
    if (raw && raw.toJS) {
      raw = raw.toJS();
    }
    let success = true;
    if (raw === undefined) {
      raw = {};
    }
    if (!isObject(raw)) {
      raw = {}
      success = false;
    }
    let keys = Object.keys(this.memberSchema);
    let members = {}
    success = !!keys.reduce((success, k) => {
      let member = new this.memberSchema[k]();
      member.name = k;
      member.parent = this;
      members[k] = member;
      if (raw[k] !== undefined) {
        success &= member.set(raw[k]);
      }
      member.observe(this.notifyWatchers.bind(this));
      return success;
    }, true);

    if (success) {
      // should this.members only be defined here?
      // or in constructor?
      this.members = members;
    } else {
      // TODO: We don't need to do this if raw was not an object.
      this.set({}, {notify: false})
    }
    if (notify) this.notifyWatchers(success, this);
    return success;
  }

  static of(...members) {
    let memberSchema = members.reduce((ms, m) => {
      ms[m.prototype.name] = m;
      return ms;
    }, {});
    return this.clone({memberSchema});
  }

  setDefault() {
    if (this.default) {
      this.set(this.default);
    } else {
      this.memberValues.forEach(m => m.setDefault());
    }
  }
}

export default {Type, Scalar, Num, Int, Str, Bool, Enum, Container, List, Map};
<commit_msg>Forward-port IE static method fixes<commit_after>import Immutable from 'immutable';
import {isObject, consume} from './util';

// Thank you IE, for making this necessary
// Per http://babeljs.io/docs/advanced/caveats/, static methods do not
// propagate down the inheritance chain because __proto__ is not a thing.
// Decorate any concrete schema class with this to ensure that it and any
// cloned versions of itself will have these static methods.
function staticify(cls) {
  Object.assign(cls, {
    clone(overrides) {
      class cloned extends this {};
      Object.assign(cloned.prototype, overrides);
      staticify(cloned);
      // Also, thank you IE, for making this necessary
      Reflect.ownKeys(this).forEach(k => {
        if (!cloned.hasOwnProperty(k)) {
          cloned[k] = this[k];
        }
      })
      return cloned;
    },

    named(name) {
      return this.clone({name});
    },

    using(overrides) {
      // maybe pre-process overrides?
      return this.clone(overrides);
    },

    validatedBy(...validators) {
      return this.clone({validators});
    },

    fromDefaults() {
      let defaulted = new this();
      defaulted.setDefault();
      return defaulted;
    }
  });
}

class Type {
  constructor(value) {
    this.valid = undefined;
    value !== undefined && this.set(value);
    this._watchers = [];
  }

  observe(watcher) {
    this._watchers.push(watcher);
  }

  notifyWatchers(...args) {
    this._watchers.forEach(watcher => watcher(...args));
  }

  addError(error) {
    this.errors.push(error);
  }

  setDefault() {
    this.set(this.default);
  }

  hasValidator(validator) {
    return this.validatorFactories.indexOf(validator) !== -1;
  }

  get validatorFactories() {
    return this.validators.map(v => v.factory);
  }
}

Type.prototype.default = undefined;
Type.prototype.validators = [];

class AdaptationError extends Error {};

class Scalar extends Type {
  constructor() {
    super();
    this._watchers = [];
    this.value = undefined;
  }

  get allErrors() {
    return this.errors;
  }

  set(raw) {
    try {
      this.value = this.adapt(raw);
    } catch (e) {
      this.value = undefined;
      this.notifyWatchers(false, this);
      return false;
    }
    this.notifyWatchers(true, this);

    return true;
  }

  validate(context) {
    this.errors = [];

    this.valid = this.validators.reduce((valid, v) => {
      return valid && v(this, context);
    }, true);

    return this.valid;
  }
}

@staticify
class Bool extends Scalar {
  adapt(raw) {
    // TODO: more restrictive?
    return !!raw;
  }
}

@staticify
class Str extends Scalar {
  adapt(raw) {
    return raw.toString();
  }
}

class Num extends Scalar {
  // ?
}

@staticify
class Int extends Num {
  adapt(raw) {
    let value = parseInt(raw, 10);
    if (isNaN(value)) {
      throw new AdaptationError(`${value} is not a number`);
    }
    return value;
  }
}

@staticify
class Enum extends Scalar {
  constructor(value) {
    super();
    this.childSchema = new this.childType();
    if (value !== undefined) {
      this.set(value);
    }
  }

  adapt(raw) {
    let value = this.childSchema.adapt(raw);
    if (!this.validValue(value)) {
      throw new AdaptationError();
    }
    return value;
  }

  validValue(value) {
    return this.validValues.indexOf(value) !== -1;
  }

  static of(childType) {
    return this.clone({childType});
  }

  static valued(validValues) {
    return this.clone({validValues});
  }
}

Enum.prototype.childType = Str;

class Container extends Type {
  validate(context) {
    this.errors = [];
    var success = !!this.memberValues.reduce((valid, member) => {
      var result = member.validate(context);
      return valid && result;
    }, true);
    this.valid = !!this.validators.reduce((valid, validator) => valid &= validator(this, context), success);
    return this.valid;
  }
}

@staticify
class List extends Container {
  get value() {
    return Immutable.List(this.members.map(m => m.value));
  }

  get members() {
    return this._members;
  }

  // aliased for concordance with Container.prototype.validate()
  get memberValues() {
    return this._members;
  }

  set members(members) {
    this._members = members;
  }

  get allErrors() {
    return {
      self: this.errors,
      children: this.members.map(m => m.allErrors)
    };
  }

  // Attempt to convert each member of raw array to the
  // member type of the List. Any failure will result in an
  // empty array for this.members.

  // TODO: short-circuit conversion if any member fails.
  set(raw) {
    if (raw && raw.toJS) {
      raw = raw.toJS();
    }
    this.members = [];
    if (!(raw && raw.forEach)) {
      this.notifyWatchers(false, this);
      return false;
    }
    let success = true;
    let items = [];
    raw.forEach(mbr => {
      let member = new this.memberType();
      member.parent = this;
      success &= member.set(mbr);
      member.observe(this.notifyWatchers.bind(this));
      items.push(member);
    });
    this.members = success ? items : this.members;
    this.notifyWatchers(!!success, this);
    return !!success;
  }

  static of(type) {
    return this.clone({memberType: type});
  }
}

List.prototype.members = [];

@staticify
class Map extends Container {
  constructor(value) {
    super(value);
    // construct an empty schema
    if (!this._members) {
      this.set({});
    }
  }

  get value() {
    return Immutable.Map(Object.keys(this._members).reduce((v, m) => {
      v[m] = this._members[m].value;
      return v;
    }, {}));
  }

  // member elements as list
  get memberValues() {
    return Object.values(this._members);
  }

  get members() {
    return this._members;
  }

  set members(members) {
    this._members = members;
  }

  get allErrors() {
    return {
      self: this.errors,
      children: Object.entries(this.members).reduce((errors, [k, v]) => {
        errors[k] = v.allErrors;
        return errors;
      }, {})
    };
  }

  set(raw, {notify = true} = {}) {
    if (raw && raw.toJS) {
      raw = raw.toJS();
    }
    let success = true;
    if (raw === undefined) {
      raw = {};
    }
    if (!isObject(raw)) {
      raw = {}
      success = false;
    }
    let keys = Object.keys(this.memberSchema);
    let members = {}
    success = !!keys.reduce((success, k) => {
      let member = new this.memberSchema[k]();
      member.name = k;
      member.parent = this;
      members[k] = member;
      if (raw[k] !== undefined) {
        success &= member.set(raw[k]);
      }
      member.observe(this.notifyWatchers.bind(this));
      return success;
    }, true);

    if (success) {
      // should this.members only be defined here?
      // or in constructor?
      this.members = members;
    } else {
      // TODO: We don't need to do this if raw was not an object.
      this.set({}, {notify: false})
    }
    if (notify) this.notifyWatchers(success, this);
    return success;
  }

  static of(...members) {
    let memberSchema = members.reduce((ms, m) => {
      ms[m.prototype.name] = m;
      return ms;
    }, {});
    return this.clone({memberSchema});
  }

  setDefault() {
    if (this.default) {
      this.set(this.default);
    } else {
      this.memberValues.forEach(m => m.setDefault());
    }
  }
}

export default {Type, Scalar, Num, Int, Str, Bool, Enum, Container, List, Map};
<|endoftext|>


<commit_before>(function ($) {
    //-----------------------+
    // Better val() function |
    //-----------------------+
    $.fn.valInternal = jQuery.fn.val;
    $.fn.val = function (val) {
        if (this.length) {
            var type = this.attr('type');
            type = type ? type : this.get(0).tagName.toLowerCase();
            switch (type) {
                case 'checkbox':
                    if (arguments.length) {
                        this.prop('checked', !!val);
                        return $.fn.valInternal.call(this, val);
                    }
                    return this.is(':checked') ? $.fn.valInternal.call(this) : '';

                case 'radio':
                    var parent = this.parent();
                    var el = parent.find(':checked');
                    if (arguments.length) {
                        console.log(val);
                        el.prop('checked', false);
                        el = parent.find('[value="' + val + '"]');
                        el.prop('checked', true);
                        return val;
                    }
                    return el.valInternal.call(el);
            }
        }

        if (arguments.length) {
            return $.fn.valInternal.call(this, val);
        } else {
            return $.fn.valInternal.call(this);
        }
    };

    //-------+
    // Setup |
    //-------+
    $.ajaxSetup({async: false});

    //-----------------+
    // Selects Command |
    //-----------------+
    $(document).on('mouseover', '#command', function () {
        // select text
        this.select();
    });
    $(document).on('mouseout', '#command', function () {
        // deselect text
        this.selectionStart = this.selectionEnd;
    });

    //------+
    // Init |
    //------+
    var URL = document.URL.replace(/(\/index.html.*)|(\/)$/, '');
    window.form = $('#form').get(0);
    form.values = {};
    form.options = $('#options').get(0);
    form.modules = {};
    form.task.onChange = [];
    form.command = '';

    //-----------+
    // Functions |
    //-----------+

    // Load form options
    form.options.load = function (name) {
        $.get(URL + '/' + name + '/~builder/options.html', function (response) {
            form.options.innerHTML += response;
        });
    };

    // Add command argument
    form.setCommand = function (cond, name, value) {
        form.command += cond ? ' -' + name + (value ? ' ' + value : '') : '';
    };

    // Invoke module update
    form.update = function (modules) {
        modules.forEach(function (module) {
            if (form.modules[module] && form.modules[module].onUpdate) {
                form.modules[module].onUpdate();
            }
        });
    };

    //--------------------+
    // Handle form update |
    //--------------------+
    var update = function (event) {
        if (event) {
            // task select
            if ($(event.target).is('[name=task]')) {
                change();
                return;
            }
        }

        // command update
        form.command = URL;
        var task = '/' + form.task.value;
        form.command += task + ' -qO- | sh -s --';

        // no interaction
        form.setCommand(form.no_interaction.checked, 'n');

        // environment
        form.setCommand(form.env.value, form.env.value);

        // switch support
        var support = $(form.support).val();
        console.log('----------');
        console.log(form.support);
        console.log(form.support.value);
        console.log(support);
        // support WBPO
        if (support === "wbpo") {
            form.setCommand(true, 'with-wbpo');
        }
        // support Webino
        if (support !== "webino") {
            form.setCommand(true, 'without-webino');
        }

        // admin email
        form.setCommand(form.admin_email.value, 'admin-email', form.admin_email.value);

        // update module options
        if (form.modules[form.task.value] && form.modules[form.task.value].options) {
            form.update(form.modules[form.task.value].options);
        }

        // update command
        $('#command').val('wget ' + form.command);
    };

    //--------------------+
    // Handle task select |
    //--------------------+
    var change = function () {
        // store form values
        $(form).find('input,select').each(function (n, node) {
            var el = $(node);
            node.name && (form.values[node.name] = el.val());
        });

        // load options
        form.options.innerHTML = '';
        if (form.modules[form.task.value] && form.modules[form.task.value].options) {
            form.modules[form.task.value].options.forEach(function (module) {
                form.options.load(module);
            });
        }

        // restore form values
        for (var key in form.values) {
            if (form.values.hasOwnProperty(key)) {
                $(form).find('[name='+ key +']').val(form.values[key]);
            }
        }

        // update command
        update();
    };

    //------------------+
    // Bind form update |
    //------------------+
    $(document).on('change', 'form', update);
    $(document).on('keyup', 'form', update);

    //------------+
    // Init tasks |
    //------------+
    $(form.task).find('option:not(:disabled)').each(function () {
        this.value && $.get(URL + '/' + this.value + '/~builder/script.js');
    });

    //------------+
    // Initialize |
    //------------+
    change();

})(jQuery);
<commit_msg>Support WIP [ci skip]<commit_after>(function ($) {
    //-----------------------+
    // Better val() function |
    //-----------------------+
    $.fn.valInternal = jQuery.fn.val;
    $.fn.val = function (val) {
        if (this.length) {
            var type = this.attr('type');
            type = type ? type : this.get(0).tagName.toLowerCase();
            switch (type) {
                case 'checkbox':
                    if (arguments.length) {
                        this.prop('checked', !!val);
                        return $.fn.valInternal.call(this, val);
                    }
                    return this.is(':checked') ? $.fn.valInternal.call(this) : '';

                case 'radio':
                    var parent = this.parent();
                    var el = parent.find(':checked');
                    if (arguments.length) {
                        console.log(val);
                        el.prop('checked', false);
                        el = parent.find('[value="' + val + '"]');
                        el.prop('checked', true);
                        return val;
                    }
                    return el.attr('value');
            }
        }

        if (arguments.length) {
            return $.fn.valInternal.call(this, val);
        } else {
            return $.fn.valInternal.call(this);
        }
    };

    //-------+
    // Setup |
    //-------+
    $.ajaxSetup({async: false});

    //-----------------+
    // Selects Command |
    //-----------------+
    $(document).on('mouseover', '#command', function () {
        // select text
        this.select();
    });
    $(document).on('mouseout', '#command', function () {
        // deselect text
        this.selectionStart = this.selectionEnd;
    });

    //------+
    // Init |
    //------+
    var URL = document.URL.replace(/(\/index.html.*)|(\/)$/, '');
    window.form = $('#form').get(0);
    form.values = {};
    form.options = $('#options').get(0);
    form.modules = {};
    form.task.onChange = [];
    form.command = '';

    //-----------+
    // Functions |
    //-----------+

    // Load form options
    form.options.load = function (name) {
        $.get(URL + '/' + name + '/~builder/options.html', function (response) {
            form.options.innerHTML += response;
        });
    };

    // Add command argument
    form.setCommand = function (cond, name, value) {
        form.command += cond ? ' -' + name + (value ? ' ' + value : '') : '';
    };

    // Invoke module update
    form.update = function (modules) {
        modules.forEach(function (module) {
            if (form.modules[module] && form.modules[module].onUpdate) {
                form.modules[module].onUpdate();
            }
        });
    };

    //--------------------+
    // Handle form update |
    //--------------------+
    var update = function (event) {
        if (event) {
            // task select
            if ($(event.target).is('[name=task]')) {
                change();
                return;
            }
        }

        // command update
        form.command = URL;
        var task = '/' + form.task.value;
        form.command += task + ' -qO- | sh -s --';

        // no interaction
        form.setCommand(form.no_interaction.checked, 'n');

        // environment
        form.setCommand(form.env.value, form.env.value);

        // switch support
        var support = $(form.support).val();
        console.log('----------');
        console.log(form.support);
        console.log(form.support.value);
        console.log(support);
        // support WBPO
        if (support === "wbpo") {
            form.setCommand(true, 'with-wbpo');
        }
        // support Webino
        if (support !== "webino") {
            form.setCommand(true, 'without-webino');
        }

        // admin email
        form.setCommand(form.admin_email.value, 'admin-email', form.admin_email.value);

        // update module options
        if (form.modules[form.task.value] && form.modules[form.task.value].options) {
            form.update(form.modules[form.task.value].options);
        }

        // update command
        $('#command').val('wget ' + form.command);
    };

    //--------------------+
    // Handle task select |
    //--------------------+
    var change = function () {
        // store form values
        $(form).find('input,select').each(function (n, node) {
            var el = $(node);
            node.name && (form.values[node.name] = el.val());
        });

        // load options
        form.options.innerHTML = '';
        if (form.modules[form.task.value] && form.modules[form.task.value].options) {
            form.modules[form.task.value].options.forEach(function (module) {
                form.options.load(module);
            });
        }

        // restore form values
        for (var key in form.values) {
            if (form.values.hasOwnProperty(key)) {
                $(form).find('[name='+ key +']').val(form.values[key]);
            }
        }

        // update command
        update();
    };

    //------------------+
    // Bind form update |
    //------------------+
    $(document).on('change', 'form', update);
    $(document).on('keyup', 'form', update);

    //------------+
    // Init tasks |
    //------------+
    $(form.task).find('option:not(:disabled)').each(function () {
        this.value && $.get(URL + '/' + this.value + '/~builder/script.js');
    });

    //------------+
    // Initialize |
    //------------+
    change();

})(jQuery);
<|endoftext|>


<commit_before>// @ts-check

'use strict';

chrome.contextMenus.create({
    contexts: ['page', 'frame', 'selection', 'link', 'editable', 'image'],
    id: 'background_img',
    title: chrome.i18n.getMessage('title')
}, () => {
    console.log(chrome.runtime.lastError);
});

chrome.contextMenus.onClicked.addListener((info, tab) => {
    chrome.tabs.sendMessage(tab.id, null, { frameId: info.frameId }, response => {

        if (chrome.runtime.lastError) {
            chrome.tabs.executeScript({ code: '', frameId: info.frameId }, () => {
                const reason = chrome.runtime.lastError ? 'security' : 'reload';
                alert(chrome.i18n.getMessage(reason));
            });
            return;
        }

        if (!Array.isArray(response) || response.length === 0) {
            const message = chrome.i18n.getMessage('failure');
            chrome.tabs.sendMessage(tab.id, message, { frameId: info.frameId }, result => {
                if (!result) return;
                chrome.tabs.create({
                    windowId: tab.windowId,
                    openerTabId: tab.id,
                    index: tab.index + 1,
                    url: 'https://github.com/foooomio/view-background-image/issues'
                });
            });
            return;
        }

        for (const image of response) {
            chrome.tabs.create({
                windowId: tab.windowId,
                openerTabId: tab.id,
                index: tab.index + 1,
                url: image
            });
        }

    });
});
<commit_msg>Add a feature to open images in background tabs<commit_after>// @ts-check

'use strict';

chrome.contextMenus.create({
    contexts: ['page', 'frame', 'selection', 'link', 'editable', 'image'],
    id: 'background_img',
    title: chrome.i18n.getMessage('title')
}, () => {
    console.log(chrome.runtime.lastError);
});

chrome.contextMenus.onClicked.addListener((info, tab) => {
    chrome.tabs.sendMessage(tab.id, null, { frameId: info.frameId }, response => {

        if (chrome.runtime.lastError) {
            chrome.tabs.executeScript({ code: '', frameId: info.frameId }, () => {
                const reason = chrome.runtime.lastError ? 'security' : 'reload';
                alert(chrome.i18n.getMessage(reason));
            });
            return;
        }

        if (!Array.isArray(response) || response.length === 0) {
            const message = chrome.i18n.getMessage('failure');
            chrome.tabs.sendMessage(tab.id, message, { frameId: info.frameId }, result => {
                if (!result) return;
                chrome.tabs.create({
                    windowId: tab.windowId,
                    openerTabId: tab.id,
                    index: tab.index + 1,
                    url: 'https://github.com/foooomio/view-background-image/issues'
                });
            });
            return;
        }

        for (const image of response) {
            chrome.tabs.create({
                windowId: tab.windowId,
                openerTabId: tab.id,
                index: tab.index + 1,
                active: !shouldOpenInBackground(info),
                url: image
            });
        }

    });
});

/**
 * @param {any} info
 * @returns {boolean}
 * @description Currently this function works well only on Firefox.
 */
function shouldOpenInBackground(info) {
    if (info.button === 1) return true;

    if (info.modifiers && info.modifiers.length === 1) {
        const key = info.modifiers[0];
        return key === 'Ctrl' || key === 'Command';
    }

    return false;
}
<|endoftext|>


<commit_before>function htmlspecialchars(string, quote_style) {
    // http://kevin.vanzonneveld.net
    // +   original by: Mirek Slugen
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: Nathan
    // +   bugfixed by: Arno
    // *     example 1: htmlspecialchars("Test", 'ENT_QUOTES');
    // *     returns 1: '<a href='test'>Test</a&gt'

    string = string.toString();

    // Always encode
    string = string.replace(/&/g, '&');
    string = string.replace(/</g, '<');
    string = string.replace(/>/g, '>');

    // Encode depending on quote_style
    if (quote_style == 'ENT_QUOTES') {
        string = string.replace(/"/g, '"');
        string = string.replace(/'/g, ''');
    } else if (quote_style != 'ENT_NOQUOTES') {
        // All other cases (ENT_COMPAT, default, but not ENT_NOQUOTES)
        string = string.replace(/"/g, '"');
    }

    return string;
}<commit_msg>Fixed htmlspecialchars example<commit_after>function htmlspecialchars(string, quote_style) {
    // http://kevin.vanzonneveld.net
    // +   original by: Mirek Slugen
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: Nathan
    // +   bugfixed by: Arno
    // *     example 1: htmlspecialchars("Test", 'ENT_QUOTES');
    // *     returns 1: '<a href='test'>Test</a>'

    string = string.toString();

    // Always encode
    string = string.replace(/&/g, '&');
    string = string.replace(/</g, '<');
    string = string.replace(/>/g, '>');

    // Encode depending on quote_style
    if (quote_style == 'ENT_QUOTES') {
        string = string.replace(/"/g, '"');
        string = string.replace(/'/g, ''');
    } else if (quote_style != 'ENT_NOQUOTES') {
        // All other cases (ENT_COMPAT, default, but not ENT_NOQUOTES)
        string = string.replace(/"/g, '"');
    }

    return string;
}<|endoftext|>


<commit_before>var pathModule = require('path');
var Promise = require('bluebird');
var urlTools = require('urltools');
var estraverse = require('estraverse');
var readPkgUp = require('read-pkg-up');

module.exports = function (queryObj, options) {
    options = options || {};
    return function bundleWebpack(assetGraph) {
        var webpack;
        try {
            webpack = require.main.require('webpack');
        } catch (e) {}

        var configPath = options.configPath || pathModule.resolve(urlTools.fileUrlToFsPath(assetGraph.root), 'webpack.config.js');

        var config;
        try {
            config = require.main.require(configPath);
        } catch (err) {
            if (err.code !== 'MODULE_NOT_FOUND') {
                throw err;
            }
            // webpack.config.js was not found in the assetgraph's root.
            // Look for it in the directory that contains the nearest package.json:
            var readPkgUpResult = readPkgUp.sync();
            if (readPkgUpResult.path) {
                var alternativeConfigPath = pathModule.resolve(pathModule.dirname(readPkgUpResult.path), 'webpack.config.js');
                if (alternativeConfigPath !== configPath) {
                    configPath = alternativeConfigPath;
                    try {
                        config = require.main.require(configPath);
                    } catch (err2) {
                        if (err2.code !== 'MODULE_NOT_FOUND') {
                            throw err2;
                        }
                    }
                }
            }

            if (!webpack) {
                return;
            }
            if (typeof options.configPath === 'undefined') {
                assetGraph.emit('info', new Error('Could not load webpack config ' + configPath + ', but webpack is installed: ' + err.message));
                return;
            } else {
                err.message = 'Could not load webpack config ' + options.configPath + ': ' + err.message;
                throw err;
            }
        }
        config.context = config.context || urlTools.fileUrlToFsPath(assetGraph.root);
        config.output = config.output || {};
        if (typeof config.output.path === 'string') {
            config.output.path = pathModule.resolve(config.context, config.output.path);
        }
        config.devtool = config.devtool || 'source-map';
        config.output.devtoolModuleFilenameTemplate = config.output.devtoolModuleFilenameTemplate || '/[resource-path]';

        var compiler = webpack(config);
        var outputFileSystem = new webpack.MemoryOutputFileSystem();
        compiler.outputFileSystem = outputFileSystem;

        return Promise.fromNode(function (cb) {
            compiler.run(cb);
        }).then(function (stats) {
            var existingAssetsWereReplaced;
            var urls = [];
            var basePath = config.output.path;
            if (config.output.publicPath) {
                basePath = pathModule.resolve(config.context, config.output.publicPath.replace(/^\//, ''));
            }
            stats.toJson({assets: true}).assets.forEach(function (asset) {
                var url = urlTools.fsFilePathToFileUrl(pathModule.resolve(basePath, asset.name));
                var outputPath = urlTools.fsFilePathToFileUrl(pathModule.resolve(config.output.path, asset.name));
                urls.push({
                    url: url,
                    output: outputPath
                });
                var existingAsset = assetGraph.findAssets({url: url})[0];
                if (existingAsset) {
                    assetGraph.emit('info', new Error('Replacing previously built artifact: ' + url));
                    existingAssetsWereReplaced = true;
                    existingAsset.incomingRelations.forEach(function (relation) {
                        relation.to = {url: url};
                    });
                    assetGraph.removeAsset(existingAsset);
                }
            });
            assetGraph.emit('info', stats.toString({colors: true}));
            if (existingAssetsWereReplaced) {
                assetGraph.emit('info', new Error('Please remove ' + config.output.path + ' before building with assetgraph to speed up the process'));
            }
            return assetGraph.loadAssets(urls.map(function (url) {
                return {
                    url: url.url,
                    rawSrc: outputFileSystem.readFileSync(urlTools.fileUrlToFsPath(url.output))
                };
            })).then(function () {
                var bundleAsset = assetGraph.findAssets({url: urlTools.fsFilePathToFileUrl(pathModule.resolve(basePath, config.output.filename))})[0];
                var replacementsMade = false;
                estraverse.traverse(bundleAsset.parseTree, {
                    enter: function (node) {
                        if (node.type === 'FunctionExpression' &&
                            node.params.length === 3 &&
                            node.params[0].type === 'Identifier' && node.params[0].name === 'module' &&
                            node.params[1].type === 'Identifier' && node.params[1].name === 'exports' &&
                            node.params[2].type === 'Identifier' && node.params[2].name === '__webpack_require__' &&
                            node.leadingComments && (node.leadingComments.length === 2 || node.leadingComments.length === 3) &&
                            /^ \d+ $/.test(node.leadingComments[node.leadingComments.length - 2].value) &&
                            node.leadingComments[node.leadingComments.length - 1].value === '*' &&
                            node.body.type === 'BlockStatement' &&
                            node.body.body.length === 1 &&
                            node.body.body[0].type === 'ExpressionStatement' &&
                            node.body.body[0].expression.type === 'AssignmentExpression' &&
                            node.body.body[0].expression.left.type === 'MemberExpression' &&
                            node.body.body[0].expression.left.object.type === 'Identifier' &&
                            node.body.body[0].expression.left.object.name === 'module' &&
                            node.body.body[0].expression.left.property.type === 'Identifier' &&
                            node.body.body[0].expression.left.property.name === 'exports' &&
                            node.body.body[0].expression.right.type === 'BinaryExpression' &&
                            node.body.body[0].expression.right.operator === '+' &&
                            node.body.body[0].expression.right.left.type === 'MemberExpression' &&
                            node.body.body[0].expression.right.left.object.type === 'Identifier' &&
                            node.body.body[0].expression.right.left.object.name === node.params[2].name &&
                            node.body.body[0].expression.right.left.property.type === 'Identifier' &&
                            node.body.body[0].expression.right.left.property.name === 'p' &&
                            node.body.body[0].expression.right.right.type === 'Literal' &&
                            typeof node.body.body[0].expression.right.right.value === 'string'
                        ) {
                            node.body.body[0].expression.right = {
                                type: 'CallExpression',
                                range: node.body.body[0].expression.right.range,
                                callee: {
                                    type: 'MemberExpression',
                                    computed: false,
                                    object: {
                                        type: 'Literal',
                                        // FIXME: Fall back to config.output.path instead of hardcoding /dist/:
                                        value: (config.output.publicPath || '/dist/') + node.body.body[0].expression.right.right.value
                                    },
                                    property: {
                                        type: 'Identifier',
                                        name: 'toString'
                                    }
                                },
                                arguments: [
                                    {
                                        type: 'Literal',
                                        value: 'url'
                                    }
                                ]
                            };
                            replacementsMade = true;
                        }
                    }
                });
                if (replacementsMade) {
                    bundleAsset.markDirty();
                    bundleAsset._outgoingRelations.forEach(function (relation) {
                        assetGraph.removeRelation(relation);
                    });
                    bundleAsset._outgoingRelations = undefined;
                    bundleAsset.isPopulated = false;
                    bundleAsset.populate();
                }
            });
        });
    };
};
<commit_msg>bundleWebpack: Look for asset references in all JavaScript assets output by webpack, don't assume there's just a single bundle.<commit_after>var pathModule = require('path');
var Promise = require('bluebird');
var urlTools = require('urltools');
var estraverse = require('estraverse');
var readPkgUp = require('read-pkg-up');

module.exports = function (queryObj, options) {
    options = options || {};
    return function bundleWebpack(assetGraph) {
        var webpack;
        try {
            webpack = require.main.require('webpack');
        } catch (e) {}

        var configPath = options.configPath || pathModule.resolve(urlTools.fileUrlToFsPath(assetGraph.root), 'webpack.config.js');

        var config;
        try {
            config = require.main.require(configPath);
        } catch (err) {
            if (err.code !== 'MODULE_NOT_FOUND') {
                throw err;
            }
            // webpack.config.js was not found in the assetgraph's root.
            // Look for it in the directory that contains the nearest package.json:
            var readPkgUpResult = readPkgUp.sync();
            if (readPkgUpResult.path) {
                var alternativeConfigPath = pathModule.resolve(pathModule.dirname(readPkgUpResult.path), 'webpack.config.js');
                if (alternativeConfigPath !== configPath) {
                    configPath = alternativeConfigPath;
                    try {
                        config = require.main.require(configPath);
                    } catch (err2) {
                        if (err2.code !== 'MODULE_NOT_FOUND') {
                            throw err2;
                        }
                    }
                }
            }

            if (!webpack) {
                return;
            }
            if (typeof options.configPath === 'undefined') {
                assetGraph.emit('info', new Error('Could not load webpack config ' + configPath + ', but webpack is installed: ' + err.message));
                return;
            } else {
                err.message = 'Could not load webpack config ' + options.configPath + ': ' + err.message;
                throw err;
            }
        }
        config.context = config.context || urlTools.fileUrlToFsPath(assetGraph.root);
        config.output = config.output || {};
        if (typeof config.output.path === 'string') {
            config.output.path = pathModule.resolve(config.context, config.output.path);
        }
        config.devtool = config.devtool || 'source-map';
        config.output.devtoolModuleFilenameTemplate = config.output.devtoolModuleFilenameTemplate || '/[resource-path]';

        var compiler = webpack(config);
        var outputFileSystem = new webpack.MemoryOutputFileSystem();
        compiler.outputFileSystem = outputFileSystem;

        return Promise.fromNode(function (cb) {
            compiler.run(cb);
        }).then(function (stats) {
            var existingAssetsWereReplaced;
            var urls = [];
            var basePath = config.output.path;
            if (config.output.publicPath) {
                basePath = pathModule.resolve(config.context, config.output.publicPath.replace(/^\//, ''));
            }
            stats.toJson({assets: true}).assets.forEach(function (asset) {
                var url = urlTools.fsFilePathToFileUrl(pathModule.resolve(basePath, asset.name));
                var outputPath = urlTools.fsFilePathToFileUrl(pathModule.resolve(config.output.path, asset.name));
                urls.push({
                    url: url,
                    output: outputPath
                });
                var existingAsset = assetGraph.findAssets({url: url})[0];
                if (existingAsset) {
                    assetGraph.emit('info', new Error('Replacing previously built artifact: ' + url));
                    existingAssetsWereReplaced = true;
                    existingAsset.incomingRelations.forEach(function (relation) {
                        relation.to = {url: url};
                    });
                    assetGraph.removeAsset(existingAsset);
                }
            });
            assetGraph.emit('info', stats.toString({colors: true}));
            if (existingAssetsWereReplaced) {
                assetGraph.emit('info', new Error('Please remove ' + config.output.path + ' before building with assetgraph to speed up the process'));
            }
            return assetGraph.loadAssets(urls.map(function (url) {
                return {
                    url: url.url,
                    rawSrc: outputFileSystem.readFileSync(urlTools.fileUrlToFsPath(url.output))
                };
            })).then(function () {
                assetGraph.findAssets({
                    type: 'JavaScript',
                    url: urls.map(function (url) { return url.url; })
                }).forEach(function (asset) {
                    var replacementsMade = false;
                    estraverse.traverse(asset.parseTree, {
                        enter: function (node) {
                            if (node.type === 'FunctionExpression' &&
                                node.params.length === 3 &&
                                node.params[0].type === 'Identifier' && node.params[0].name === 'module' &&
                                node.params[1].type === 'Identifier' && node.params[1].name === 'exports' &&
                                node.params[2].type === 'Identifier' && node.params[2].name === '__webpack_require__' &&
                                node.leadingComments && (node.leadingComments.length === 2 || node.leadingComments.length === 3) &&
                                /^ \d+ $/.test(node.leadingComments[node.leadingComments.length - 2].value) &&
                                node.leadingComments[node.leadingComments.length - 1].value === '*' &&
                                node.body.type === 'BlockStatement' &&
                                node.body.body.length === 1 &&
                                node.body.body[0].type === 'ExpressionStatement' &&
                                node.body.body[0].expression.type === 'AssignmentExpression' &&
                                node.body.body[0].expression.left.type === 'MemberExpression' &&
                                node.body.body[0].expression.left.object.type === 'Identifier' &&
                                node.body.body[0].expression.left.object.name === 'module' &&
                                node.body.body[0].expression.left.property.type === 'Identifier' &&
                                node.body.body[0].expression.left.property.name === 'exports' &&
                                node.body.body[0].expression.right.type === 'BinaryExpression' &&
                                node.body.body[0].expression.right.operator === '+' &&
                                node.body.body[0].expression.right.left.type === 'MemberExpression' &&
                                node.body.body[0].expression.right.left.object.type === 'Identifier' &&
                                node.body.body[0].expression.right.left.object.name === node.params[2].name &&
                                node.body.body[0].expression.right.left.property.type === 'Identifier' &&
                                node.body.body[0].expression.right.left.property.name === 'p' &&
                                node.body.body[0].expression.right.right.type === 'Literal' &&
                                typeof node.body.body[0].expression.right.right.value === 'string'
                            ) {
                                node.body.body[0].expression.right = {
                                    type: 'CallExpression',
                                    range: node.body.body[0].expression.right.range,
                                    callee: {
                                        type: 'MemberExpression',
                                        computed: false,
                                        object: {
                                            type: 'Literal',
                                            // FIXME: Fall back to config.output.path instead of hardcoding /dist/:
                                            value: (config.output.publicPath || '/dist/') + node.body.body[0].expression.right.right.value
                                        },
                                        property: {
                                            type: 'Identifier',
                                            name: 'toString'
                                        }
                                    },
                                    arguments: [
                                        {
                                            type: 'Literal',
                                            value: 'url'
                                        }
                                    ]
                                };
                                replacementsMade = true;
                            }
                        }
                    });
                    if (replacementsMade) {
                        asset.markDirty();
                        asset._outgoingRelations.forEach(function (relation) {
                            assetGraph.removeRelation(relation);
                        });
                        asset._outgoingRelations = undefined;
                        asset.isPopulated = false;
                        asset.populate();
                    }
                });
            });
        });
    };
};
<|endoftext|>


<commit_before>const querystring = require('querystring');
const btoa = require('btoa');
const fetch = require('isomorphic-fetch');

const GitBookError = require('./error');
const defaultConfig = require('./defaultConfig');

/**
 * ApiClient is a helper class to make API requests
 * from React components using the user's token and the
 * API Secret as password for BasicAuth.
 *
 * @type {Class}
 */
class ApiClient {

    /**
     * Initialize a new API Client from configuration and a JSON encoded account
     *
     * @param  {Object} config
     * @param  {Object} account
     */
    constructor(account = {}, config = defaultConfig) {
        // config.apiHost and account.auth.token are used
        // to keep compatibility with GitBook.com payload.

        // Set base URL for requests
        this.endpoint = config.host || config.apiHost;

        // Set Basic Auth informations
        this.auth = (account && account.token) ?
            btoa(account.username + ':' + ((account.auth ? account.auth.token : account.token)) || '')
            : null;

        // Set common headers
        this.headers = {
            'Accept':        'application/json',
            'Content-Type':  'application/json',
            'Authorization': this.auth ? 'Basic ' + this.auth : undefined
        };
    }

    /**
     * Return true if api calls are authentified
     */
    isAuthenticated() {
        return Boolean(this.auth);
    }

    /**
     * enpointUrl returns the full targeted URL with API host and encoded querystring
     * @param  {String} url     Relative URL to API endpoint
     * @param  {Object} params  Object containing query string parameters to encode
     * @return {String}
     */
    endpointUrl(url, params) {
        url = url[0] == '/' ? url : '/' + url;
        return this.endpoint + url + (params ? '?' + querystring.stringify(params) : '');
    }

    /**
     * request executes the request to an API endpoint <url> with options <opts>
     * It returns a Promise providing the data from the response as a JS Object
     *
     * @param  {String} url
     * @param  {Object} opts  <opts> may contain the following properties:
     *                        - {String} method: HTTP method for the request
     *                        - {Object} data:   Body for the request to be encoded as JSON
     *                        - {Object} params: An Object containing the query string parameters to encode
     * @return {Promise}
     */
    request(url, opts) {
        // Default options
        opts = opts || {};

        // Configuration for fetch
        const headers = this.headers;
        const cfg = {
            method: opts.method || 'GET',
            headers
        };

        if (Boolean(opts.data)) {
            cfg.body = JSON.stringify(opts.data);
        }

        // Construct full URL
        url = this.endpointUrl(url, opts.params);

        return fetch(url, cfg)
        .then(response => this.parseResponse(response));
    }

    /**
     * delete is a shorthand method to send a DELETE HTTP request
     * See request description for more details about <url>, <params> and return type
     * @param  {String} url
     * @param  {Object} params
     * @return {Promise}
     */
    delete(url, params) {
        return this.request(url, {
            method: 'DELETE',
            params
        });
    }

    /**
     * get is a shorthand method to send a GET HTTP request
     * See request description for more details about <url>, <params> and return type
     * @param  {String} url
     * @param  {Object} params
     * @return {Promise}
     */
    get(url, params) {
        return this.request(url, {
            params
        });
    }

    /**
     * patch is a shorthand method to send a PATCH HTTP request
     * See request description for more details about <url>, <data>, <params> and return type
     * @param  {String} url
     * @param  {Object} params
     * @param  {Object} data
     * @return {Promise}
     */
    patch(url, data, params) {
        return this.request(url, {
            method: 'PATCH',
            data,
            params
        });
    }

    /**
     * post is a shorthand method to send a POST HTTP request
     * See request description for more details about <url>, <data>, <params> and return type
     * @param  {String} url
     * @param  {Object} params
     * @param  {Object} data
     * @return {Promise}
     */
    post(url, data, params) {
        return this.request(url, {
            method: 'POST',
            data,
            params
        });
    }

    /**
     * put is a shorthand method to send a PUT HTTP request
     * See request description for more details about <url>, <data>, <params> and return type
     * @param  {String} url
     * @param  {Object} params
     * @param  {Object} data
     * @return {Promise}
     */
    put(url, data, params) {
        return this.request(url, {
            method: 'PUT',
            data,
            params
        });
    }

    /**
     * parseResponse is responsible for handling the response to a fetch request
     * It checks that <response> was successfull and contains the correct Content-Type
     * It returns a Promise for trying to parse the encoded JSON body to a JS Object
     *
     * @param  {Response} response
     * @return {Promise}
     */
    parseResponse(response) {
        const contentType = response.headers.get('Content-Type');

        if (!response.ok) {
            return GitBookError.createForResponse(response);
        }

        if (contentType.indexOf('application/json') < 0) {
            throw new Error('Invalid content type for response');
        }

        return response.json();
    }
}

module.exports = ApiClient;
<commit_msg>Last parameter of http method can be used to set options<commit_after>const querystring = require('querystring');
const btoa = require('btoa');
const fetch = require('isomorphic-fetch');

const GitBookError = require('./error');
const defaultConfig = require('./defaultConfig');

/**
 * ApiClient is a helper class to make API requests
 * from React components using the user's token and the
 * API Secret as password for BasicAuth.
 *
 * @type {Class}
 */
class ApiClient {

    /**
     * Initialize a new API Client from configuration and a JSON encoded account
     *
     * @param  {Object} config
     * @param  {Object} account
     */
    constructor(account = {}, config = defaultConfig) {
        // config.apiHost and account.auth.token are used
        // to keep compatibility with GitBook.com payload.

        // Set base URL for requests
        this.endpoint = config.host || config.apiHost;

        // Set Basic Auth informations
        this.auth = (account && account.token) ?
            btoa(account.username + ':' + ((account.auth ? account.auth.token : account.token)) || '')
            : null;

        // Set common headers
        this.headers = {
            'Accept':        'application/json',
            'Content-Type':  'application/json',
            'Authorization': this.auth ? 'Basic ' + this.auth : undefined
        };
    }

    /**
     * Return true if api calls are authentified
     */
    isAuthenticated() {
        return Boolean(this.auth);
    }

    /**
     * enpointUrl returns the full targeted URL with API host and encoded querystring
     * @param  {String} url     Relative URL to API endpoint
     * @param  {Object} params  Object containing query string parameters to encode
     * @return {String}
     */
    endpointUrl(url, params) {
        url = url[0] == '/' ? url : '/' + url;
        return this.endpoint + url + (params ? '?' + querystring.stringify(params) : '');
    }

    /**
     * request executes the request to an API endpoint <url> with options <opts>
     * It returns a Promise providing the data from the response as a JS Object
     *
     * @param  {String} url
     * @param  {Object} opts  <opts> may contain the following properties:
     *                        - {String} method: HTTP method for the request
     *                        - {Object} data:   Body for the request to be encoded as JSON
     *                        - {Object} params: An Object containing the query string parameters to encode
     * @return {Promise}
     */
    request(url, opts = {}) {
        // Configuration for fetch
        const cfg = {
            method: opts.method || 'GET',
            headers: {
                ...(this.headers),
                ...(opts.headers || {})
            }
        };

        if (Boolean(opts.data)) {
            cfg.body = JSON.stringify(opts.data);
        }

        // Construct full URL
        url = this.endpointUrl(url, opts.params);

        return fetch(url, cfg)
        .then(response => this.parseResponse(response));
    }

    /**
     * delete is a shorthand method to send a DELETE HTTP request
     * See request description for more details about <url>, <params> and return type
     * @param  {String} url
     * @param  {Object} params
     * @return {Promise}
     */
    delete(url, params, options = {}) {
        return this.request(url, {
            ...options,
            method: 'DELETE',
            params
        });
    }

    /**
     * get is a shorthand method to send a GET HTTP request
     * See request description for more details about <url>, <params> and return type
     * @param  {String} url
     * @param  {Object} params
     * @return {Promise}
     */
    get(url, params, options = {}) {
        return this.request(url, {
            ...options,
            params
        });
    }

    /**
     * patch is a shorthand method to send a PATCH HTTP request
     * See request description for more details about <url>, <data>, <params> and return type
     * @param  {String} url
     * @param  {Object} params
     * @param  {Object} data
     * @return {Promise}
     */
    patch(url, data, options = {}) {
        return this.request(url, {
            ...options,
            method: 'PATCH',
            data
        });
    }

    /**
     * post is a shorthand method to send a POST HTTP request
     * See request description for more details about <url>, <data>, <params> and return type
     * @param  {String} url
     * @param  {Object} params
     * @param  {Object} data
     * @return {Promise}
     */
    post(url, data, options = {}) {
        return this.request(url, {
            ...options,
            method: 'POST',
            data
        });
    }

    /**
     * put is a shorthand method to send a PUT HTTP request
     * See request description for more details about <url>, <data>, <params> and return type
     * @param  {String} url
     * @param  {Object} params
     * @param  {Object} data
     * @return {Promise}
     */
    put(url, data, options = {}) {
        return this.request(url, {
            ...options,
            method: 'PUT',
            data
        });
    }

    /**
     * parseResponse is responsible for handling the response to a fetch request
     * It checks that <response> was successfull and contains the correct Content-Type
     * It returns a Promise for trying to parse the encoded JSON body to a JS Object
     *
     * @param  {Response} response
     * @return {Promise}
     */
    parseResponse(response) {
        const contentType = response.headers.get('Content-Type');

        if (!response.ok) {
            return GitBookError.createForResponse(response);
        }

        if (contentType.indexOf('application/json') < 0) {
            throw new Error('Invalid content type for response');
        }

        return response.json();
    }
}

module.exports = ApiClient;
<|endoftext|>


<commit_before>
/**
 * Module requirements.
 */

var Polling = require('./polling')
  , util = require('../util')

/**
 * Module exports.
 */

module.exports = JSONPPolling;

/**
 * Cached regular expressions.
 */

var rNewline = /\n/g

/**
 * Global JSONP callbacks.
 */

var callbacks = global.___eio = [];

/**
 * Noop.
 */

function empty () { }

/**
 * JSONP Polling constructor.
 *
 * @param {Object} opts.
 * @api public
 */

function JSONPPolling (opts) {
  Polling.call(this, opts);

  // add callback to jsonp global
  var self = this;
  callbacks.push(function (msg) {
    self.onData(msg);
  });

  // append to query string
  this.query.j = callbacks.length - 1;
};

/**
 * Inherits from Polling.
 */

util.inherits(JSONPPolling, Polling);

/**
 * Opens the socket.
 *
 * @api private
 */

JSONPPolling.prototype.doOpen = function () {
  var self = this;
  util.defer(function () {
    Polling.prototype.doOpen.call(self);
  });
};

/**
 * Closes the socket
 *
 * @api private
 */

JSONPPolling.prototype.doClose = function () {
  if (this.script) {
    this.script.parentNode.removeChild(this.script);
    this.script = null;
  }

  if (this.form) {
    this.form.parentNode.removeChild(this.form);
    this.form = null;
  }

  Polling.prototype.doClose.call(this);
};

/**
 * Starts a poll cycle.
 *
 * @api private
 */

JSONPPolling.prototype.doPoll = function () {
  var script = document.createElement('script');

  if (this.script) {
    this.script.parentNode.removeChild(this.script);
    this.script = null;
  }

  script.async = true;
  script.src = this.uri();

  var insertAt = document.getElementsByTagName('script')[0]
  insertAt.parentNode.insertBefore(script, insertAt);
  this.script = script;

  if (util.ua.gecko) {
    setTimeout(function () {
      var iframe = document.createElement('iframe');
      document.body.appendChild(iframe);
      document.body.removeChild(iframe);
    }, 100);
  }
};

/**
 * Writes with a hidden iframe.
 *
 * @param {String} data to send
 * @param {Function} called upon flush.
 * @api private
 */

JSONPPolling.prototype.doWrite = function (data, fn) {
  var self = this

  if (!this.form) {
    var form = document.createElement('form')
      , area = document.createElement('textarea')
      , id = this.iframeId = 'socketio_iframe_' + this.index
      , iframe;

    form.className = 'socketio';
    form.style.position = 'absolute';
    form.style.top = '-1000px';
    form.style.left = '-1000px';
    form.target = id;
    form.method = 'POST';
    form.setAttribute('accept-charset', 'utf-8');
    area.name = 'd';
    form.appendChild(area);
    document.body.appendChild(form);

    this.form = form;
    this.area = area;
  }

  this.form.action = this.uri();

  function complete () {
    initIframe();
    fn();
  };

  function initIframe () {
    if (self.iframe) {
      self.form.removeChild(self.iframe);
    }

    try {
      // ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
      iframe = document.createElement('<iframe name="'+ self.iframeId +'">');
    } catch (e) {
      iframe = document.createElement('iframe');
      iframe.name = self.iframeId;
    }

    iframe.id = self.iframeId;

    self.form.appendChild(iframe);
    self.iframe = iframe;
  };

  initIframe();

  // escape \n to prevent it from being converted into \r\n by some UAs
  this.area.value = data.replace(rNewline, '\\n');

  try {
    this.form.submit();
  } catch(e) {}

  if (this.iframe.attachEvent) {
    iframe.onreadystatechange = function () {
      if (self.iframe.readyState == 'complete') {
        complete();
      }
    };
  } else {
    this.iframe.onload = complete;
  }
};
<commit_msg>Fixed JSONP (fixes #24)<commit_after>
/**
 * Module requirements.
 */

var Polling = require('./polling')
  , util = require('../util')

/**
 * Module exports.
 */

module.exports = JSONPPolling;

/**
 * Cached regular expressions.
 */

var rNewline = /\n/g

/**
 * Global JSONP callbacks.
 */

var callbacks = global.___eio = [];

/**
 * Callbacks count.
 */

var index = 0;

/**
 * Noop.
 */

function empty () { }

/**
 * JSONP Polling constructor.
 *
 * @param {Object} opts.
 * @api public
 */

function JSONPPolling (opts) {
  Polling.call(this, opts);

  // callback identifier
  this.index = index++;

  // add callback to jsonp global
  var self = this;
  callbacks.push(function (msg) {
    self.onData(msg);
  });

  // append to query string
  this.query.j = callbacks.length - 1;
};

/**
 * Inherits from Polling.
 */

util.inherits(JSONPPolling, Polling);

/**
 * Opens the socket.
 *
 * @api private
 */

JSONPPolling.prototype.doOpen = function () {
  var self = this;
  util.defer(function () {
    Polling.prototype.doOpen.call(self);
  });
};

/**
 * Closes the socket
 *
 * @api private
 */

JSONPPolling.prototype.doClose = function () {
  if (this.script) {
    this.script.parentNode.removeChild(this.script);
    this.script = null;
  }

  if (this.form) {
    this.form.parentNode.removeChild(this.form);
    this.form = null;
  }

  Polling.prototype.doClose.call(this);
};

/**
 * Starts a poll cycle.
 *
 * @api private
 */

JSONPPolling.prototype.doPoll = function () {
  var script = document.createElement('script');

  if (this.script) {
    this.script.parentNode.removeChild(this.script);
    this.script = null;
  }

  script.async = true;
  script.src = this.uri();

  var insertAt = document.getElementsByTagName('script')[0]
  insertAt.parentNode.insertBefore(script, insertAt);
  this.script = script;

  if (util.ua.gecko) {
    setTimeout(function () {
      var iframe = document.createElement('iframe');
      document.body.appendChild(iframe);
      document.body.removeChild(iframe);
    }, 100);
  }
};

/**
 * Writes with a hidden iframe.
 *
 * @param {String} data to send
 * @param {Function} called upon flush.
 * @api private
 */

JSONPPolling.prototype.doWrite = function (data, fn) {
  var self = this

  if (!this.form) {
    var form = document.createElement('form')
      , area = document.createElement('textarea')
      , id = this.iframeId = 'eio_iframe_' + this.index
      , iframe;

    form.className = 'socketio';
    form.style.position = 'absolute';
    form.style.top = '-1000px';
    form.style.left = '-1000px';
    form.target = id;
    form.method = 'POST';
    form.setAttribute('accept-charset', 'utf-8');
    area.name = 'd';
    form.appendChild(area);
    document.body.appendChild(form);

    this.form = form;
    this.area = area;
  }

  this.form.action = this.uri();

  function complete () {
    initIframe();
    fn();
  };

  function initIframe () {
    if (self.iframe) {
      self.form.removeChild(self.iframe);
    }

    try {
      // ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
      iframe = document.createElement('<iframe name="'+ self.iframeId +'">');
    } catch (e) {
      iframe = document.createElement('iframe');
      iframe.name = self.iframeId;
    }

    iframe.id = self.iframeId;

    self.form.appendChild(iframe);
    self.iframe = iframe;
  };

  initIframe();

  // escape \n to prevent it from being converted into \r\n by some UAs
  this.area.value = data.replace(rNewline, '\\n');

  try {
    this.form.submit();
  } catch(e) {}

  if (this.iframe.attachEvent) {
    iframe.onreadystatechange = function () {
      if (self.iframe.readyState == 'complete') {
        complete();
      }
    };
  } else {
    this.iframe.onload = complete;
  }
};
<|endoftext|>


<commit_before>'use-strict'

var hookshot = require('hookshot'),
	fs         = require('fs'),
	sh         = require('execSync'),
	request    = require('request'),
	colors     = require('colors');

var config      = require('../config.json'),
		sh_commands = require('./sh-commands.js');

function verifyAccount(incoming_repo){
	if (incoming_repo == config.github_listener.account_name) return true;
	return false;
}
function checkIfCommitterIsDeployer(members, committer){
	return members.some(function(member){
		return member.login === committer;
	});
}
function verifyCommitter(last_commit, cb){
	// You only need to verify the deployer if you're using teams, otherwise disable it and always allow anyone pushing to that repo to deploy.
	if (!config.verify_committer.enabled){
		cb(true);
	}else{
		var committer = last_commit.committer.username;
		request({
			url: 'https://api.github.com/teams/' + config.verify_committer.team_id + '/members?access_token=' + config.verify_committer.access_token,
			headers: {
        'User-Agent': 'Kestrel-publisher'
    		}
    	}, function (error, response, body) {
		  if (!error) {
		  	var committer_is_deployer = checkIfCommitterIsDeployer(JSON.parse(body), committer);
		    cb(committer_is_deployer);
		  } else {
		  	console.log('Error verifying committer'.red, JSON.stringify(error))
		  }
		})
	}
}

function createDirGitInit(info){
	var repo_name = info.repository.name;

	fs.mkdirSync('./repositories/' + repo_name);

	var remote_url_arr = info.repository.url.split('//');
	var authenticated_remote_url = remote_url_arr[0] + '//' + config.verify_committer.access_token + '@' + remote_url_arr[1];
	var create_statement = sh_commands.createGitRepoAndRemotes(repo_name, authenticated_remote_url);
  sh.run(create_statement);
}
function pullLatest(info){
	var repo_name = info.repository.name,
		branch_name = info.ref.split('/')[2], // `ref: "refs/heads/<branchname>` => `branchname`
		delete_branch;

	if (!fs.existsSync('./repositories/' + repo_name)){
		createDirGitInit(info);
	}

	// Download latest data
	var fetch_statement = sh_commands.fetchLatest(repo_name);
	sh.run(fetch_statement);

	// If it's deleted, delete it!
	if (info.deleted) {
		delete_branch = sh_commands.deleteBranch(repo_name, branch_name);
		sh.run(delete_branch);
	}

	// Update all branches
	var track_all_branches = sh_commands.trackAllBranches(repo_name);
	sh.run(track_all_branches);

	// Put the working tree back on to master
	var checkout_master = sh_commands.checkoutMaster(repo_name);
	sh.run(checkout_master);
}
function checkForDeployMsg(last_commit){
	var commit_trigger = last_commit.message.split('::')[1], // 'bucket_environment::trigger::local_path::remote_path' -> "trigger"
	    cp_deploy_regx   = new RegExp(config.s3.hard_deploy.trigger),
	    sync_deploy_regx = new RegExp(config.s3.sync_deploy_trigger);

	if (config.s3.hard_deploy.enabled && cp_deploy_regx.exec(commit_trigger)) return 'hard';
	if (sync_deploy_regx.exec(commit_trigger)) return 'sync';
	return false;
}
function deployToS3(deploy_type, info, most_recent_commit){
	var repo_name   = info.repository.name,
			commit_parts = most_recent_commit.split('::'), // 'bucket_environment::trigger::local_path::remote_path' -> [bucket_environment, trigger, local_path, remote_path]
			bucket_environment  = commit_parts[0], // Either `prod` or `staging`
			local_path  = commit_parts[2], // Either the repo_name or the repo_name/sub-directory
	    remote_path = commit_parts[3] // Usually a year, e.g. 2014. The folder we'll be writing into

	var deploy_statement = sh_commands.deploy(deploy_type, repo_name, config.s3.buckets[bucket_environment], local_path, remote_path, config.s3.exclude);
	var deploy_result = sh.exec(deploy_statement);
	// Log deployment result
	console.log('Deployed!'.green, deploy_result.stdout);
}

hookshot(function(info){
	// Is this request coming from the specified GitHub Account?
	var is_account_verified = verifyAccount(info.repository.owner.name);
	// Is there a deploy message present?
	var most_recent_commit,
			deploy_status;
	// The last commit in the array is the most recent
	// But `info.commits` will be an empty array if you pushed a new branch with no commits
	if (info.commits.length) {
		most_recent_commit  = info.commits[info.commits.length - 1];
		deploy_status       = checkForDeployMsg(most_recent_commit);
	}
	// Is this coming from the whitelisted GitHub account?
	if (is_account_verified){
		pullLatest(info);

		// Are we deploying? Has that option been enabled and does the commit have the appropriate message?
		if (config.s3.enabled && deploy_status){
			verifyCommitter(most_recent_commit, function(committer_approved){

				// Does the committer have deploy? privileges?
				if (committer_approved) {
					deployToS3(deploy_status, info, most_recent_commit.message);
				} else {
					console.log('Unapproved committer attempted deployment.'.red)
				}

			});
		}
	}
}).listen(config.github_listener.port);

console.log('Listening on port... ' + config.github_listener.port);	<commit_msg>more logging<commit_after>'use-strict'

var hookshot = require('hookshot'),
	fs         = require('fs'),
	sh         = require('execSync'),
	request    = require('request'),
	colors     = require('colors');

var config      = require('../config.json'),
		sh_commands = require('./sh-commands.js');

function verifyAccount(incoming_repo){
	if (incoming_repo == config.github_listener.account_name) return true;
	return false;
}
function checkIfCommitterIsDeployer(members, committer){
	return members.some(function(member){
		return member.login === committer;
	});
}
function verifyCommitter(last_commit, cb){
	// You only need to verify the deployer if you're using teams, otherwise disable it and always allow anyone pushing to that repo to deploy.
	if (!config.verify_committer.enabled){
		cb(true);
	}else{
		var committer = last_commit.committer.username;
		request({
			url: 'https://api.github.com/teams/' + config.verify_committer.team_id + '/members?access_token=' + config.verify_committer.access_token,
			headers: {
        'User-Agent': 'Kestrel-publisher'
    		}
    	}, function (error, response, body) {
		  if (!error) {
		  	var committer_is_deployer = checkIfCommitterIsDeployer(JSON.parse(body), committer);
		    cb(committer_is_deployer);
		  } else {
		  	console.log('Error verifying committer'.red, JSON.stringify(error))
		  }
		})
	}
}

function createDirGitInit(info){
	console.log('Creating git repository...'.green)
	var repo_name = info.repository.name;

	fs.mkdirSync('./repositories/' + repo_name);

	var remote_url_arr = info.repository.url.split('//');
	var authenticated_remote_url = remote_url_arr[0] + '//' + config.verify_committer.access_token + '@' + remote_url_arr[1];
	var create_statement = sh_commands.createGitRepoAndRemotes(repo_name, authenticated_remote_url);
	console.log(create_statement)
  sh.run(create_statement);
}
function pullLatest(info){
	var repo_name = info.repository.name,
		branch_name = info.ref.split('/')[2], // `ref: "refs/heads/<branchname>` => `branchname`
		delete_branch;

	if (!fs.existsSync('./repositories/' + repo_name)){
		createDirGitInit(info);
	}

	// Download latest data
	var fetch_statement = sh_commands.fetchLatest(repo_name);
	sh.run(fetch_statement);

	// If it's deleted, delete it!
	if (info.deleted) {
		delete_branch = sh_commands.deleteBranch(repo_name, branch_name);
		sh.run(delete_branch);
	}

	// Update all branches
	var track_all_branches = sh_commands.trackAllBranches(repo_name);
	sh.run(track_all_branches);

	// Put the working tree back on to master
	var checkout_master = sh_commands.checkoutMaster(repo_name);
	sh.run(checkout_master);
}
function checkForDeployMsg(last_commit){
	var commit_trigger = last_commit.message.split('::')[1], // 'bucket_environment::trigger::local_path::remote_path' -> "trigger"
	    cp_deploy_regx   = new RegExp(config.s3.hard_deploy.trigger),
	    sync_deploy_regx = new RegExp(config.s3.sync_deploy_trigger);

	if (config.s3.hard_deploy.enabled && cp_deploy_regx.exec(commit_trigger)) return 'hard';
	if (sync_deploy_regx.exec(commit_trigger)) return 'sync';
	return false;
}
function deployToS3(deploy_type, info, most_recent_commit){
	var repo_name   = info.repository.name,
			commit_parts = most_recent_commit.split('::'), // 'bucket_environment::trigger::local_path::remote_path' -> [bucket_environment, trigger, local_path, remote_path]
			bucket_environment  = commit_parts[0], // Either `prod` or `staging`
			local_path  = commit_parts[2], // Either the repo_name or the repo_name/sub-directory
	    remote_path = commit_parts[3] // Usually a year, e.g. 2014. The folder we'll be writing into

	var deploy_statement = sh_commands.deploy(deploy_type, repo_name, config.s3.buckets[bucket_environment], local_path, remote_path, config.s3.exclude);
	var deploy_result = sh.exec(deploy_statement);
	// Log deployment result
	console.log('Deployed!'.green, deploy_result.stdout);
}

hookshot(function(info){
	// Is this request coming from the specified GitHub Account?
	var is_account_verified = verifyAccount(info.repository.owner.name);
	// Is there a deploy message present?
	var most_recent_commit,
			deploy_status;
	// The last commit in the array is the most recent
	// But `info.commits` will be an empty array if you pushed a new branch with no commits
	if (info.commits.length) {
		most_recent_commit  = info.commits[info.commits.length - 1];
		deploy_status       = checkForDeployMsg(most_recent_commit);
	}
	// Is this coming from the whitelisted GitHub account?
	if (is_account_verified){
		pullLatest(info);

		// Are we deploying? Has that option been enabled and does the commit have the appropriate message?
		if (config.s3.enabled && deploy_status){
			verifyCommitter(most_recent_commit, function(committer_approved){

				// Does the committer have deploy? privileges?
				if (committer_approved) {
					deployToS3(deploy_status, info, most_recent_commit.message);
				} else {
					console.log('Unapproved committer attempted deployment.'.red)
				}

			});
		}
	}
}).listen(config.github_listener.port);

console.log('Listening on port... ' + config.github_listener.port);	<|endoftext|>


<commit_before>/* global document */
/* global window */

import React from 'react'
import ReactDOM from 'react-dom'
import 'normalize.css'
import mitt from 'mitt'

import Init from './components/Init'
import Api from './api'
import { getTitle } from './common'
import './styles/main.pcss'

(function () {

  const renderApp = (state, emitter) => {

    document.title = getTitle(state.data)

    ReactDOM.render(
      <Init {...state} emitter={emitter} />,
      document.getElementById('root')
    )
  }

  document.addEventListener('DOMContentLoaded', () => {

    const api = new Api(window.__APP_INITIAL_STATE__.apiConfig)

    const emitter = mitt()
    // Log all emissions
    emitter.on('*', (type, e) => console.info(type, e))
    // Save data to the API
    emitter.on('save', data => api.save(data, response => {
      const state = window.__APP_INITIAL_STATE__
      state.data = response
      renderApp(state, emitter)
    }))
    // Read data from the API
    emitter.on('load', url => {
      const parser = document.createElement('a')
      parser.href = url
      window.location.hash = parser.hash
      window.history.pushState(null, null, url)
      window.dispatchEvent(new window.PopStateEvent('popstate'))
    })
    emitter.on('getOptions', ({term, types, callback}) => api.find(term, types, callback))

    let currentPathname = window.location.pathname + window.location.search
    window.addEventListener('popstate', () => {
      const url = window.location.pathname + window.location.search
      if (currentPathname === url) {
        return
      } else {
        currentPathname = url
      }
      api.load(url, response => {
        const state = window.__APP_INITIAL_STATE__
        state.data = response
        renderApp(state, emitter)
      })
    })

    renderApp(window.__APP_INITIAL_STATE__, emitter)

  })

})()
<commit_msg>Prevent triggering unnecessary popstate events<commit_after>/* global document */
/* global window */

import React from 'react'
import ReactDOM from 'react-dom'
import 'normalize.css'
import mitt from 'mitt'

import Init from './components/Init'
import Api from './api'
import { getTitle } from './common'
import './styles/main.pcss'

(function () {

  const renderApp = (state, emitter) => {

    document.title = getTitle(state.data)

    ReactDOM.render(
      <Init {...state} emitter={emitter} />,
      document.getElementById('root')
    )
  }

  document.addEventListener('DOMContentLoaded', () => {

    const api = new Api(window.__APP_INITIAL_STATE__.apiConfig)

    const emitter = mitt()
    // Log all emissions
    emitter.on('*', (type, e) => console.info(type, e))
    // Save data to the API
    emitter.on('save', data => api.save(data, response => {
      const state = window.__APP_INITIAL_STATE__
      state.data = response
      renderApp(state, emitter)
    }))
    // Read data from the API
    emitter.on('load', url => {
      if (window.location.pathname + window.location.search !== url) {
        const parser = document.createElement('a')
        parser.href = url
        window.location.hash = parser.hash
        window.history.pushState(null, null, url)
        window.dispatchEvent(new window.PopStateEvent('popstate'))
      }
    })
    emitter.on('getOptions', ({term, types, callback}) => api.find(term, types, callback))

    window.addEventListener('popstate', () => {
      const url = window.location.pathname + window.location.search
      api.load(url, response => {
        const state = window.__APP_INITIAL_STATE__
        state.data = response
        renderApp(state, emitter)
      })
    })

    renderApp(window.__APP_INITIAL_STATE__, emitter)

  })

})()
<|endoftext|>


<commit_before>'use strict';

const skeleton = require('swagger-service-skeleton');

const instanceGenerator = () => skeleton({
  ioc: {
    /*
       This path is relative to *this* file, which is in the ./src directory, thus it is:
       ./src/services/*.js
    */
    autoRegister: { pattern: './services/*.js',
                    rootDirectory: __dirname },
  },
  codegen: {
    /*
       This is a generated directory - this is where all of the glue created by the skeleton lives.
       It is relative to the application (repository) root directory.
    */
    temporaryDirectory: './dist/codegen',
    /*
       This path is relative from the directory defined by temporaryDirectory, which resolves to:
       ./src/controllers
    */
    templateSettings: {
      implementationPath: '../../../src/controllers',
    },
  },
  service: {
    /*
       This is the path to your YAML file. It is relative to the application (repository) root
       directory.
    */
    swagger: './src/contracts/swagger.yaml',
    listenPort: 10010,
  },
});

module.exports = instanceGenerator;
<commit_msg>Restore config.<commit_after>'use strict';

const config = require('config').get('server');
const skeleton = require('swagger-service-skeleton');

const instanceGenerator = () => skeleton({
  ioc: {
    /*
       This path is relative to *this* file, which is in the ./src directory, thus it is:
       ./src/services/*.js
    */
    autoRegister: { pattern: './services/*.js',
                    rootDirectory: __dirname },
  },
  codegen: {
    /*
       This is a generated directory - this is where all of the glue created by the skeleton lives.
       It is relative to the application (repository) root directory.
    */
    temporaryDirectory: './dist/codegen',
    /*
       This path is relative from the directory defined by temporaryDirectory, which resolves to:
       ./src/controllers
    */
    templateSettings: {
      implementationPath: '../../../src/controllers',
    },
  },
  service: {
    /*
       This is the path to your YAML file. It is relative to the application (repository) root
       directory.
    */
    swagger: './src/contracts/swagger.yaml',
    listenPort: config.listenPort,
  },
});

module.exports = instanceGenerator;
<|endoftext|>


<commit_before>module.exports = (client) => {
    // Listener para cuando se viene alguien nuevo
    client.on('guildMemberAdd', member => {
        // El mensaje se manda al canal por defecto (boop)
        member.guild.textChannels:toArray[0].send(`Bienvenido a nuestro servidor, ${member}.\nEs un lugar bonito y lleno de personas amables.\nQuédate si no maineas ni Bastion, ni Yasuo ni Symmetra.\nSi necesitas ayuda escribe '!halpmepls'`).catch(console.log);
    })

    // Listener para cuando alguien se pira o lo echamos (Aunque eso es poco probable)
    client.on('guildMemberRemove', member => {
        // El mensaje se manda al canal por defecto (boop)
        member.guild.defaultChannel.send(`Nuestro querido miembro, ${member}, se ha ido para siempre.\nSe ruega una oración por su alma y la asistencia a la conducción`);
        if(member.roles.length > 0){
            member.guild.textChannels:toArray[0].send('Sus roles eran:').catch(console.log)
            // WIP--------------  TODO TODO
            for(var x in member.roles){
                member.guild.textChannels:toArray[0].send(member.roles[x][role].name)
            }
            member.guild.textChannels:toArray[0].send('Le echaremos de menos. O no.').catch(console.log)
            // WIP--------------  TODO TODO
        }
    })
}
<commit_msg>Update final<commit_after>module.exports = (client) => {
    // Listener para cuando se viene alguien nuevo
    client.on('guildMemberAdd', member => {
        // El mensaje se manda al canal por defecto (boop)
        member.guild.defaultChannel.send(`Bienvenido a nuestro servidor, ${member}.\nEs un lugar bonito y lleno de personas amables.\nQuédate si no maineas ni Bastion, ni Yasuo ni Symmetra.\nSi necesitas ayuda escribe '!halpmepls'`).catch(console.log);
    })

    // Listener para cuando alguien se pira o lo echamos (Aunque eso es poco probable)
    client.on('guildMemberRemove', member => {
        // El mensaje se manda al canal por defecto (boop)
        member.guild.defaultChannel.send(`Nuestro querido miembro, ${member}, se ha ido para siempre.\nSe ruega una oración por su alma y la asistencia a la conducción`);
        if(member.roles.length > 0){
            member.guild.defaultChannel.send('Sus roles eran:').catch(console.log)
            // WIP--------------  TODO TODO
            for(var x in member.roles){
                member.guild.defaultChannel.send(member.roles[x][role].name)
            }
            member.guild.defaultChannel.send('Le echaremos de menos. O no.').catch(console.log)
            // WIP--------------  TODO TODO
        }
    })
}
<|endoftext|>