<commit_before>'use strict';

var React = require('./util/React');
var t = require('tcomb-validation');
var humanize = require('./util/humanize');
var merge = require('./util/merge');
var getTypeInfo = require('./util/getTypeInfo');
var getOptionsOfEnum = require('./util/getOptionsOfEnum');

var SOURCE = 'tcomb-form-native';
var nooptions = Object.freeze({});
var noop = function () {};

function getComponent(type, options) {
  if (options.factory) {
    return options.factory;
  }
  var name = t.getTypeName(type);
  switch (type.meta.kind) {
    case 'irreducible' :
      return type === t.Bool ? Checkbox :
        type === t.Dat ? DatePicker : Textbox;
    case 'struct' :
      return Struct;
    case 'enums' :
      return Select;
    case 'maybe' :
    case 'subtype' :
      return getComponent(type.meta.type, options);
    default :
      t.fail(`[${SOURCE}] unsupported type ${name}`);
  }
}

function getDefaultLabel(ctx, typeInfo) {
  return ctx.label + (typeInfo.isMaybe ? ctx.i18n.optional : '');
}

function sortByText(a, b) {
  return a.text < b.text ? -1 : a.text > b.text ? 1 : 0;
}

function getComparator(order) {
  return {
    asc: sortByText,
    desc: (a, b) => -sortByText(a, b)
  }[order];
}

class Component extends React.Component {

  constructor(props) {
    super(props);
    this.typeInfo = getTypeInfo(props.type);
    this.state = {
      hasError: false,
      value: this.getTransformer().format(props.value)
    };
  }

  getTransformer() {
    if (this.props.options.transformer) {
      return this.props.options.transformer;
    }
    return Form.transformers.defaultTransformer;
  }

  shouldComponentUpdate(nextProps, nextState) {
    return nextState.value !== this.state.value ||
      nextState.hasError !== this.state.hasError ||
      nextProps.value !== this.props.value ||
      nextProps.options !== this.props.options ||
      nextProps.type !== this.props.type;
  }

  componentWillReceiveProps(props) {
    var value = this.getTransformer().format(props.value);
    if (props.type !== this.props.type) {
      this.typeInfo = getTypeInfo(props.type);
    }
    this.setState({value});
  }

  onChange(value) {
    this.setState({value}, function () {
      this.props.onChange(value, this.props.ctx.path);
    }.bind(this));
  }

  getValue() {
    var result = this.validate();
    this.setState({hasError: !result.isValid()});
    return result;
  }

  validate() {
    var value = this.getTransformer().parse(this.state.value);
    return t.validate(value, this.props.type, this.props.ctx.path);
  }

  getLocals() {
    t.fail(`[${SOURCE}] unimplemented method getLocals() of component ${this.constructor.name}`);
  }

  render() {
    var locals = this.getLocals();
    return locals.template(locals);
  }

}

class Textbox extends Component {

  constructor(props) {
    super(props);
  }

  getTransformer() {
    if (this.props.options.transformer) {
      return this.props.options.transformer;
    }
    if (this.typeInfo.innerType === t.Num) {
      return Form.transformers.defaultNumberTransformer;
    }
    return Form.transformers.defaultTextboxTransformer;
  }

  getLocals() {

    var { ctx, options } = this.props;

    var defaultLabel = getDefaultLabel(ctx, this.typeInfo);
    var label = options.label;
    if (!label && ctx.auto === 'labels' && ctx.label) {
      label = defaultLabel;
    }
    var placeholder = options.placeholder;
    if (!label && !placeholder && ctx.auto === 'placeholders') {
      placeholder = defaultLabel;
    }
    var value = this.state.value;
    var error = t.Func.is(options.error) ? options.error(value) : options.error;
    var template = options.template || ctx.templates.textbox;
    var stylesheet = options.stylesheet || ctx.stylesheet;

    var locals = {
      error,
      hasError: options.hasError || this.state.hasError,
      label,
      onChange: this.onChange.bind(this),
      placeholder: placeholder,
      stylesheet,
      template,
      value
    };

    [
      'help',
      'autoCapitalize',
      'autoCorrect',
      'autoFocus',
      'bufferDelay',
      'clearButtonMode',
      'editable',
      'enablesReturnKeyAutomatically',
      'keyboardType',
      'multiline',
      'onBlur',
      'onEndEditing',
      'onFocus',
      'onSubmitEditing',
      'password',
      'placeholderTextColor',
      'returnKeyType',
      'secureTextEntry',
      'selectionState'
    ].forEach((name) => locals[name] = options[name]);

    return locals;
  }

}

class Checkbox extends Component {

  getTransformer() {
    if (this.props.options.transformer) {
      return this.props.options.transformer;
    }
    return Form.transformers.defaultCheckboxTransformer;
  }

  getLocals() {

    var { ctx, options } = this.props;

    var label = options.label;
    if (!label && ctx.label) {
      label = getDefaultLabel(ctx, this.typeInfo);
    }
    var value = this.state.value;
    var error = t.Func.is(options.error) ? options.error(value) : options.error;
    var template = options.template || ctx.templates.checkbox;
    var stylesheet = options.stylesheet || ctx.stylesheet;

    var locals = {
      error,
      hasError: options.hasError || this.state.hasError,
      label,
      onChange: this.onChange.bind(this),
      stylesheet,
      template,
      value
    };

    [
      'help',
      'disabled',
      'onTintColor',
      'thumbTintColor',
      'tintColor'
    ].forEach((name) => locals[name] = options[name]);

    return locals;
  }

}

class Select extends Component {

  getNullOption() {
    return this.props.options.nullOption || {value: '', text: '-'};
  }

  getLocals() {

    var { ctx, options } = this.props;

    var label = options.label;
    if (!label && ctx.label) {
      label = getDefaultLabel(ctx, this.typeInfo);
    }
    var value = this.state.value;
    var error = t.Func.is(options.error) ? options.error(value) : options.error;
    var template = options.template || ctx.templates.select;
    var stylesheet = options.stylesheet || ctx.stylesheet;

    var items = options.options ? options.options.slice() : getOptionsOfEnum(this.typeInfo.innerType);
    if (options.order) {
      items.sort(getComparator(options.order));
    }
    var nullOption = this.getNullOption();
    if (options.nullOption !== false) {
      if (t.Nil.is(value)) { value = nullOption.value; }
      items.unshift(nullOption);
    }

    var locals = {
      error,
      hasError: options.hasError || this.state.hasError,
      options: items,
      label,
      onChange: this.onChange.bind(this),
      stylesheet,
      template,
      value
    };

    [
      'help'
    ].forEach((name) => locals[name] = options[name]);

    return locals;
  }

}

class DatePicker extends Component {

  constructor(props) {
    super(props);
  }

  getLocals() {

    var { ctx, options } = this.props;

    var label = options.label;
    if (!label && ctx.auto === 'labels' && ctx.label) {
      label = getDefaultLabel(ctx, this.typeInfo);
    }
    var value = this.state.value;

    var error = t.Func.is(options.error) ? options.error(value) : options.error;
    var template = options.template || ctx.templates.datepicker;
    var stylesheet = options.stylesheet || ctx.stylesheet;

    var locals = {
      error,
      hasError: options.hasError || this.state.hasError,
      label,
      onChange: this.onChange.bind(this),
      stylesheet,
      template,
      value
    };

    [
      'help',
      'maximumDate',
      'minimumDate',
      'minuteInterval',
      'mode',
      'timeZoneOffsetInMinutes'
    ].forEach((name) => locals[name] = options[name]);

    return locals;
  }

}

class Struct extends Component {

  constructor(props) {
    super(props);
  }

  validate() {

    var value = {};
    var errors = [];
    var hasError = false;
    var result;

    for (var ref in this.refs) {
      if (this.refs.hasOwnProperty(ref)) {
        result = this.refs[ref].getValue();
        errors = errors.concat(result.errors);
        value[ref] = result.value;
      }
    }

    if (errors.length === 0) {
      value = new this.typeInfo.innerType(value);
      if (this.typeInfo.isSubtype && errors.length === 0) {
        result = t.validate(value, this.props.type, this.props.ctx.path);
        hasError = !result.isValid();
        errors = errors.concat(result.errors);
      }
    }

    return new t.ValidationResult({errors, value});
  }

  onChange(fieldName, fieldValue, path) {
    var value = t.mixin({}, this.state.value);
    value[fieldName] = fieldValue;
    this.setState({value}, function () {
      this.props.onChange(value, path);
    }.bind(this));
  }

  getLocals() {

    var { ctx, options } = this.props;

    var props = this.typeInfo.innerType.meta.props;
    var order = options.order || Object.keys(props);
    var auto = options.auto || ctx.auto;
    var i18n =  options.i18n || ctx.i18n;
    var label = options.label;
    if (!label && auto === 'labels' && ctx.label) {
      label = ctx.label + (this.typeInfo.isMaybe ? i18n.optional : '');
    }
    var value = this.state.value || {};
    var templates = merge(ctx.templates, options.templates);
    var stylesheet = options.stylesheet || ctx.stylesheet;

    var inputs = {};
    for (var prop in props) {
      if (props.hasOwnProperty(prop)) {
        var propType = props[prop];
        var propOptions = options.fields && options.fields[prop] ? options.fields[prop] : nooptions;
        inputs[prop] = React.createElement(getComponent(propType, propOptions), {
          key: prop,
          ref: prop,
          type: propType,
          options: propOptions,
          value: value[prop],
          onChange: this.onChange.bind(this, prop),
          ctx: {
            auto,
            label: humanize(prop),
            i18n,
            stylesheet,
            templates,
            path: this.props.ctx.path.concat(prop)
          }
        });
      }
    }

    return {
      order,
      label,
      inputs,
      stylesheet,
      template: templates.struct
    };
  }

}

class Form {

  getValue(raw) {
    var result = this.refs.input.getValue();
    if (raw === true) { return result; }
    if (result.isValid()) { return result.value; }
    return null;
  }

  render() {

    var type = this.props.type;
    var options = this.props.options || nooptions;
    var stylesheet = Form.stylesheet;
    var templates = Form.templates;
    var i18n = Form.i18n;

    t.assert(t.Type.is(type), `[${SOURCE}] missing required prop type`);
    t.assert(t.Obj.is(options), `[${SOURCE}] prop options must be an object`);
    t.assert(t.Obj.is(stylesheet), `[${SOURCE}] missing stylesheet config`);
    t.assert(t.Obj.is(templates), `[${SOURCE}] missing templates config`);
    t.assert(t.Obj.is(i18n), `[${SOURCE}] missing i18n config`);

    var Component = getComponent(type, options);

    return React.createElement(Component, {
      ref: 'input',
      type: type,
      options: options,
      value: this.props.value,
      onChange: this.props.onChange || noop,
      ctx: {
        auto: 'labels',
        stylesheet,
        templates,
        i18n,
        path: []
      }
    });
  }

}

Form.transformers = {

  defaultTransformer: {
    format: value => t.Nil.is(value) ? null : value,
    parse: value => value
  },

  defaultNumberTransformer: {
    format: value => t.Nil.is(value) ? value : String(value),
    parse: value => {
      var n = parseFloat(value);
      var isNumeric = (value - n + 1) >= 0;
      return isNumeric ? n : value;
    }
  },

  defaultTextboxTransformer: {
    format: value => t.Nil.is(value) ? null : value,
    parse: value => (t.Str.is(value) && value.trim() === '') || t.Nil.is(value) ? null : value
  },

  defaultCheckboxTransformer: {
    format: value => t.Nil.is(value) ? false : value,
    parse: value => t.Nil.is(value) ? false : value
  }

};

module.exports = {
  Component,
  Textbox,
  Checkbox,
  Select,
  DatePicker,
  Struct,
  Form
};<commit_msg>preventing state reset<commit_after>'use strict';

var React = require('./util/React');
var t = require('tcomb-validation');
var humanize = require('./util/humanize');
var merge = require('./util/merge');
var getTypeInfo = require('./util/getTypeInfo');
var getOptionsOfEnum = require('./util/getOptionsOfEnum');

var SOURCE = 'tcomb-form-native';
var nooptions = Object.freeze({});
var noop = function () {};

function getComponent(type, options) {
  if (options.factory) {
    return options.factory;
  }
  var name = t.getTypeName(type);
  switch (type.meta.kind) {
    case 'irreducible' :
      return type === t.Bool ? Checkbox :
        type === t.Dat ? DatePicker : Textbox;
    case 'struct' :
      return Struct;
    case 'enums' :
      return Select;
    case 'maybe' :
    case 'subtype' :
      return getComponent(type.meta.type, options);
    default :
      t.fail(`[${SOURCE}] unsupported type ${name}`);
  }
}

function getDefaultLabel(ctx, typeInfo) {
  return ctx.label + (typeInfo.isMaybe ? ctx.i18n.optional : '');
}

function sortByText(a, b) {
  return a.text < b.text ? -1 : a.text > b.text ? 1 : 0;
}

function getComparator(order) {
  return {
    asc: sortByText,
    desc: (a, b) => -sortByText(a, b)
  }[order];
}

class Component extends React.Component {

  constructor(props) {
    super(props);
    this.typeInfo = getTypeInfo(props.type);
    this.state = {
      hasError: false,
      value: this.getTransformer().format(props.value)
    };
  }

  getTransformer() {
    if (this.props.options.transformer) {
      return this.props.options.transformer;
    }
    return Form.transformers.defaultTransformer;
  }

  shouldComponentUpdate(nextProps, nextState) {
    return nextState.value !== this.state.value ||
      nextState.hasError !== this.state.hasError ||
      nextProps.value !== this.props.value ||
      nextProps.options !== this.props.options ||
      nextProps.type !== this.props.type;
  }

  componentWillReceiveProps(props) {
    var value = this.getTransformer().format(props.value);
    if (props.type !== this.props.type) {
      this.typeInfo = getTypeInfo(props.type);
    }

    if (value) {
      this.setState({value});
    }
  }

  onChange(value) {
    this.setState({value}, function () {
      this.props.onChange(value, this.props.ctx.path);
    }.bind(this));
  }

  getValue() {
    var result = this.validate();
    this.setState({hasError: !result.isValid()});
    return result;
  }

  validate() {
    var value = this.getTransformer().parse(this.state.value);
    return t.validate(value, this.props.type, this.props.ctx.path);
  }

  getLocals() {
    t.fail(`[${SOURCE}] unimplemented method getLocals() of component ${this.constructor.name}`);
  }

  render() {
    var locals = this.getLocals();
    return locals.template(locals);
  }

}

class Textbox extends Component {

  constructor(props) {
    super(props);
  }

  getTransformer() {
    if (this.props.options.transformer) {
      return this.props.options.transformer;
    }
    if (this.typeInfo.innerType === t.Num) {
      return Form.transformers.defaultNumberTransformer;
    }
    return Form.transformers.defaultTextboxTransformer;
  }

  getLocals() {

    var { ctx, options } = this.props;

    var defaultLabel = getDefaultLabel(ctx, this.typeInfo);
    var label = options.label;
    if (!label && ctx.auto === 'labels' && ctx.label) {
      label = defaultLabel;
    }
    var placeholder = options.placeholder;
    if (!label && !placeholder && ctx.auto === 'placeholders') {
      placeholder = defaultLabel;
    }
    var value = this.state.value;
    var error = t.Func.is(options.error) ? options.error(value) : options.error;
    var template = options.template || ctx.templates.textbox;
    var stylesheet = options.stylesheet || ctx.stylesheet;

    var locals = {
      error,
      hasError: options.hasError || this.state.hasError,
      label,
      onChange: this.onChange.bind(this),
      placeholder: placeholder,
      stylesheet,
      template,
      value
    };

    [
      'help',
      'autoCapitalize',
      'autoCorrect',
      'autoFocus',
      'bufferDelay',
      'clearButtonMode',
      'editable',
      'enablesReturnKeyAutomatically',
      'keyboardType',
      'multiline',
      'onBlur',
      'onEndEditing',
      'onFocus',
      'onSubmitEditing',
      'password',
      'placeholderTextColor',
      'returnKeyType',
      'secureTextEntry',
      'selectionState'
    ].forEach((name) => locals[name] = options[name]);

    return locals;
  }

}

class Checkbox extends Component {

  getTransformer() {
    if (this.props.options.transformer) {
      return this.props.options.transformer;
    }
    return Form.transformers.defaultCheckboxTransformer;
  }

  getLocals() {

    var { ctx, options } = this.props;

    var label = options.label;
    if (!label && ctx.label) {
      label = getDefaultLabel(ctx, this.typeInfo);
    }
    var value = this.state.value;
    var error = t.Func.is(options.error) ? options.error(value) : options.error;
    var template = options.template || ctx.templates.checkbox;
    var stylesheet = options.stylesheet || ctx.stylesheet;

    var locals = {
      error,
      hasError: options.hasError || this.state.hasError,
      label,
      onChange: this.onChange.bind(this),
      stylesheet,
      template,
      value
    };

    [
      'help',
      'disabled',
      'onTintColor',
      'thumbTintColor',
      'tintColor'
    ].forEach((name) => locals[name] = options[name]);

    return locals;
  }

}

class Select extends Component {

  getNullOption() {
    return this.props.options.nullOption || {value: '', text: '-'};
  }

  getLocals() {

    var { ctx, options } = this.props;

    var label = options.label;
    if (!label && ctx.label) {
      label = getDefaultLabel(ctx, this.typeInfo);
    }
    var value = this.state.value;
    var error = t.Func.is(options.error) ? options.error(value) : options.error;
    var template = options.template || ctx.templates.select;
    var stylesheet = options.stylesheet || ctx.stylesheet;

    var items = options.options ? options.options.slice() : getOptionsOfEnum(this.typeInfo.innerType);
    if (options.order) {
      items.sort(getComparator(options.order));
    }
    var nullOption = this.getNullOption();
    if (options.nullOption !== false) {
      if (t.Nil.is(value)) { value = nullOption.value; }
      items.unshift(nullOption);
    }

    var locals = {
      error,
      hasError: options.hasError || this.state.hasError,
      options: items,
      label,
      onChange: this.onChange.bind(this),
      stylesheet,
      template,
      value
    };

    [
      'help'
    ].forEach((name) => locals[name] = options[name]);

    return locals;
  }

}

class DatePicker extends Component {

  constructor(props) {
    super(props);
  }

  getLocals() {

    var { ctx, options } = this.props;

    var label = options.label;
    if (!label && ctx.auto === 'labels' && ctx.label) {
      label = getDefaultLabel(ctx, this.typeInfo);
    }
    var value = this.state.value;

    var error = t.Func.is(options.error) ? options.error(value) : options.error;
    var template = options.template || ctx.templates.datepicker;
    var stylesheet = options.stylesheet || ctx.stylesheet;

    var locals = {
      error,
      hasError: options.hasError || this.state.hasError,
      label,
      onChange: this.onChange.bind(this),
      stylesheet,
      template,
      value
    };

    [
      'help',
      'maximumDate',
      'minimumDate',
      'minuteInterval',
      'mode',
      'timeZoneOffsetInMinutes'
    ].forEach((name) => locals[name] = options[name]);

    return locals;
  }

}

class Struct extends Component {

  constructor(props) {
    super(props);
  }

  validate() {

    var value = {};
    var errors = [];
    var hasError = false;
    var result;

    for (var ref in this.refs) {
      if (this.refs.hasOwnProperty(ref)) {
        result = this.refs[ref].getValue();
        errors = errors.concat(result.errors);
        value[ref] = result.value;
      }
    }

    if (errors.length === 0) {
      value = new this.typeInfo.innerType(value);
      if (this.typeInfo.isSubtype && errors.length === 0) {
        result = t.validate(value, this.props.type, this.props.ctx.path);
        hasError = !result.isValid();
        errors = errors.concat(result.errors);
      }
    }

    return new t.ValidationResult({errors, value});
  }

  onChange(fieldName, fieldValue, path) {
    var value = t.mixin({}, this.state.value);
    value[fieldName] = fieldValue;
    this.setState({value}, function () {
      this.props.onChange(value, path);
    }.bind(this));
  }

  getLocals() {

    var { ctx, options } = this.props;

    var props = this.typeInfo.innerType.meta.props;
    var order = options.order || Object.keys(props);
    var auto = options.auto || ctx.auto;
    var i18n =  options.i18n || ctx.i18n;
    var label = options.label;
    if (!label && auto === 'labels' && ctx.label) {
      label = ctx.label + (this.typeInfo.isMaybe ? i18n.optional : '');
    }
    var value = this.state.value || {};
    var templates = merge(ctx.templates, options.templates);
    var stylesheet = options.stylesheet || ctx.stylesheet;

    var inputs = {};
    for (var prop in props) {
      if (props.hasOwnProperty(prop)) {
        var propType = props[prop];
        var propOptions = options.fields && options.fields[prop] ? options.fields[prop] : nooptions;
        inputs[prop] = React.createElement(getComponent(propType, propOptions), {
          key: prop,
          ref: prop,
          type: propType,
          options: propOptions,
          value: value[prop],
          onChange: this.onChange.bind(this, prop),
          ctx: {
            auto,
            label: humanize(prop),
            i18n,
            stylesheet,
            templates,
            path: this.props.ctx.path.concat(prop)
          }
        });
      }
    }

    return {
      order,
      label,
      inputs,
      stylesheet,
      template: templates.struct
    };
  }

}

class Form {

  getValue(raw) {
    var result = this.refs.input.getValue();
    if (raw === true) { return result; }
    if (result.isValid()) { return result.value; }
    return null;
  }

  render() {

    var type = this.props.type;
    var options = this.props.options || nooptions;
    var stylesheet = Form.stylesheet;
    var templates = Form.templates;
    var i18n = Form.i18n;

    t.assert(t.Type.is(type), `[${SOURCE}] missing required prop type`);
    t.assert(t.Obj.is(options), `[${SOURCE}] prop options must be an object`);
    t.assert(t.Obj.is(stylesheet), `[${SOURCE}] missing stylesheet config`);
    t.assert(t.Obj.is(templates), `[${SOURCE}] missing templates config`);
    t.assert(t.Obj.is(i18n), `[${SOURCE}] missing i18n config`);

    var Component = getComponent(type, options);

    return React.createElement(Component, {
      ref: 'input',
      type: type,
      options: options,
      value: this.props.value,
      onChange: this.props.onChange || noop,
      ctx: {
        auto: 'labels',
        stylesheet,
        templates,
        i18n,
        path: []
      }
    });
  }

}

Form.transformers = {

  defaultTransformer: {
    format: value => t.Nil.is(value) ? null : value,
    parse: value => value
  },

  defaultNumberTransformer: {
    format: value => t.Nil.is(value) ? value : String(value),
    parse: value => {
      var n = parseFloat(value);
      var isNumeric = (value - n + 1) >= 0;
      return isNumeric ? n : value;
    }
  },

  defaultTextboxTransformer: {
    format: value => t.Nil.is(value) ? null : value,
    parse: value => (t.Str.is(value) && value.trim() === '') || t.Nil.is(value) ? null : value
  },

  defaultCheckboxTransformer: {
    format: value => t.Nil.is(value) ? false : value,
    parse: value => t.Nil.is(value) ? false : value
  }

};

module.exports = {
  Component,
  Textbox,
  Checkbox,
  Select,
  DatePicker,
  Struct,
  Form
};<|endoftext|>


<commit_before>// Google Closure Compiler will output a wrapping function here.

  // A few optimizations for Google Closure Compiler will save us a couple kb in the release script.
  var object = Object, array = Array, regexp = RegExp, date = Date, string = String, number = Number, math = Math, Undefined;

  // The global context
  var globalContext = typeof global !== 'undefined' ? global : this;

  // defineProperty exists in IE8 but will error when trying to define a property on
  // native objects. IE8 does not have defineProperies, however, so this check saves a try/catch block.
  var definePropertySupport = object.defineProperty && object.defineProperties;

  // Class extending methods

  function extend(klass, instance, override, methods) {
    var extendee = instance ? klass.prototype : klass, original;
    iterateOverObject(methods, function(name, method) {
      original = extendee[name];
      if(typeof override === 'function') {
        method = wrapNative(extendee[name], method, override);
      }
      if(override !== false || !extendee[name]) {
        defineProperty(extendee, name, method);
      }
      // If the method is internal to Sugar, then store a reference so it can be restored later.
      klass['SugarMethods'][name] = { instance: instance, method: method, original: original };
    });
  }

  function initializeClass(klass) {
    if(klass['SugarMethods']) return;
    defineProperty(klass, 'SugarMethods', {});
    extend(klass, false, false, {
      'restore': function() {
        var all = arguments.length === 0, methods = getArgs(arguments);
        iterateOverObject(klass['SugarMethods'], function(name, m) {
          if(all || methods.indexOf(name) > -1) {
            defineProperty(m.instance ? klass.prototype : klass, name, m.method);
          }
        });
      },
      'extend': function(methods, override, instance) {
        extend(klass, instance !== false, override, methods);
      }
    });
  }

  function wrapNative(nativeFn, extendedFn, condition) {
    return function() {
      if(nativeFn && (condition === true || !condition.apply(this, arguments))) {
        return nativeFn.apply(this, arguments);
      } else {
        return extendedFn.apply(this, arguments);
      }
    }
  }

  function defineProperty(target, name, method) {
    if(definePropertySupport) {
      object.defineProperty(target, name, { 'value': method, 'configurable': true, 'enumerable': false, 'writable': true });
    } else {
      target[name] = method;
    }
  }

  function extendSimilar(klass, instance, set, fn) {
    var methods = {};
    set = isString(set) ? set.split(',') : set;
    simpleArrayEach(set, function(name) {
      fn(name, methods);
    });
    extend(klass, instance, false, methods);
  }

  // Argument helpers

  function getArgs(args, index) {
    return array.prototype.slice.call(args, index);
  }

  function multiArgs(args, fn) {
    simpleArrayEach(getArgs(args), fn);
  }

  // Used for both arrays and strings

  function entryAtIndex(arr, args, str) {
    var result = [], length = arr.length, loop = args[args.length - 1] !== false, r;
    multiArgs(args, function(index) {
      if(isBoolean(index)) return false;
      if(loop) {
        index = index % length;
        if(index < 0) index = length + index;
      }
      r = str ? arr.charAt(index) || '' : arr[index];
      result.push(r);
    });
    return result.length < 2 ? result[0] : result;
  }

  // General helpers

  function isDefined(o) {
    return o !== Undefined;
  }

  function isUndefined(o) {
    return o === Undefined;
  }

  function isClass(obj, str) {
    return object.prototype.toString.call(obj) === '[object '+str+']';
  }

  function isObject(obj) {
    // === on the constructor is not safe across iframes
    return !!obj && isClass(obj, 'Object') && string(obj.constructor) === string(object);
  }

  function isObjectPrimitive(obj) {
    // Check for null
    return obj && typeof obj === 'object';
  }

  function hasOwnProperty(obj, key) {
    return object.prototype.hasOwnProperty.call(obj, key);
  }

  /***
   * Object module
   *
   ***/

  // Object helpers

  function iterateOverObject(obj, fn) {
    var key;
    for(key in obj) {
      if(!hasOwnProperty(obj, key)) continue;
      if(fn.call(obj, key, obj[key]) === false) break;
    }
  }

  function commaSeparatedEach(str, fn) {
    str.split(',').forEach(fn);
  }

  function simpleArrayEach(arr, fn) {
    arr.forEach(fn);
  }

  function simpleMerge(target, source) {
    iterateOverObject(source, function(key) {
      target[key] = source[key];
    });
  }

  function simpleCapitalize(str) {
    return str.slice(0,1).toUpperCase() + str.slice(1);
  }

  function stringify(thing, stack) {
    var value, klass, isObject, isArray, arr, i, key, type = typeof thing;

    // Return quickly if string to save cycles
    if(type === 'string') return thing;

    klass    = object.prototype.toString.call(thing)
    isObject = klass === '[object Object]';
    isArray  = klass === '[object Array]';

    if(thing != null && isObject || isArray) {
      // This method for checking for cyclic structures was egregiously stolen from
      // the ingenious method by @kitcambridge from the Underscore script:
      // https://github.com/documentcloud/underscore/issues/240
      if(!stack) stack = [];
      // Allowing a step into the structure before triggering this
      // script to save cycles on standard JSON structures and also to
      // try as hard as possible to catch basic properties that may have
      // been modified.
      if(stack.length > 1) {
        i = stack.length;
        while (i--) {
          if (stack[i] === thing) {
            return 'CYC';
          }
        }
      }
      stack.push(thing);
      value = string(thing.constructor);
      arr = isArray ? thing : object.keys(thing).sort();
      for(i = 0; i < arr.length; i++) {
        key = isArray ? i : arr[i];
        value += key + stringify(thing[key], stack);
      }
      stack.pop();
    } else if(1 / thing === -Infinity) {
      value = '-0';
    } else {
      value = string(thing && thing.valueOf());
    }
    return type + klass + value;
  }

  var ClassNames = 'Array,Boolean,Date,Function,Number,String,RegExp'.split(',');

  var isArray    = buildClassCheck(ClassNames[0]);
  var isBoolean  = buildClassCheck(ClassNames[1]);
  var isDate     = buildClassCheck(ClassNames[2]);
  var isFunction = buildClassCheck(ClassNames[3]);
  var isNumber   = buildClassCheck(ClassNames[4]);
  var isString   = buildClassCheck(ClassNames[5]);
  var isRegExp   = buildClassCheck(ClassNames[6]);

  function buildClassCheck(type) {
    return function(obj) {
      return isClass(obj, type);
    }
  }

  function initializeClasses() {
    initializeClass(object);
    simpleArrayEach(ClassNames, function(name) {
      initializeClass(globalContext[name]);
    });
  }
  initializeClasses();

  /***
   * Array module
   *
   ***/

  /***
   * Number module
   *
   ***/

  function getRange(start, stop, fn, step) {
    var arr = [], i = parseInt(start), down = step < 0;
    while((!down && i <= stop) || (down && i >= stop)) {
      arr.push(i);
      if(fn) fn.call(this, i);
      i += step || 1;
    }
    return arr;
  }

  function round(val, precision, method) {
    var fn = math[method || 'round'];
    var multiplier = math.pow(10, math.abs(precision || 0));
    if(precision < 0) multiplier = 1 / multiplier;
    return fn(val * multiplier) / multiplier;
  }

  function ceil(val, precision) {
    return round(val, precision, 'ceil');
  }

  function floor(val, precision) {
    return round(val, precision, 'floor');
  }

  /***
   * String module
   *
   ***/

  // WhiteSpace/LineTerminator as defined in ES5.1 plus Unicode characters in the Space, Separator category.
  var getTrimmableCharacters = function() {
    return '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u2028\u2029\u3000\uFEFF';
  }

  function repeatString(times, str) {
    return array(math.max(0, isDefined(times) ? times : 1) + 1).join(str || '');
  }

  function padNumber(num, place, sign, base) {
    var str = math.abs(num).toString(base || 10);
    str = repeatString(place - str.replace(/\.\d+/, '').length, '0') + str;
    if(sign || num < 0) {
      str = (num < 0 ? '-' : '+') + str;
    }
    return str;
  }

  function getOrdinalizedSuffix(num) {
    if(num >= 11 && num <= 13) {
      return 'th';
    } else {
      switch(num % 10) {
        case 1:  return 'st';
        case 2:  return 'nd';
        case 3:  return 'rd';
        default: return 'th';
      }
    }
  }

  function buildTrim() {
    var support = getTrimmableCharacters().match(/^\s+$/);
    try { string.prototype.trim.call([1]); } catch(e) { support = false; }
    var trimL = regexp('^['+getTrimmableCharacters()+']+');
    var trimR = regexp('['+getTrimmableCharacters()+']+$');
    extend(string, true, !support, {

      /***
       * @method trim[Side]()
       * @returns String
       * @short Removes leading and/or trailing whitespace from the string.
       * @extra Whitespace is defined as line breaks, tabs, and any character in the "Space, Separator" Unicode category, conforming to the the ES5 spec. The standard %trim% method is only added when not fully supported natively.
       * @example
       *
       *   '   wasabi   '.trim()      -> 'wasabi'
       *   '   wasabi   '.trimLeft()  -> 'wasabi   '
       *   '   wasabi   '.trimRight() -> '   wasabi'
       *
       ***
       * @method trim()
       * @set trimSide
       ***/
      'trim': function() {
        return this.toString().trimLeft().trimRight();
      },

      /***
       * @method trimLeft()
       * @set trimSide
       ***/
      'trimLeft': function() {
        return this.replace(trimL, '');
      },

      /***
       * @method trimRight()
       * @set trimSide
       ***/
      'trimRight': function() {
        return this.replace(trimR, '');
      }
    });
  }

  /***
   * RegExp module
   *
   * Note here that methods on the RegExp class like .exec and .test will fail in the current version of SpiderMonkey being
   * used by CouchDB when using shorthand regex notation like /foo/. This is the reason for the intermixed use of shorthand
   * and compiled regexes here. If you're using JS in CouchDB, it is safer to ALWAYS compile your regexes from a string.
   *
   ***/

  regexp.NPCGSupport = isUndefined(regexp('()??').exec('')[1]); // NPCG: nonparticipating capturing group

  function getFlags(reg, flag) {
    var flags = '';
    if(flag == 'g' || reg.global)     flags += 'g';
    if(flag == 'i' || reg.ignoreCase) flags += 'i';
    if(flag == 'm' || reg.multiline)  flags += 'm';
    if(flag == 'y' || reg.sticky)     flags += 'y';
    return flags;
  }

  extend(regexp, false, false, {

   /***
    * @method RegExp.escape(<str> = '')
    * @returns String
    * @short Escapes all RegExp tokens in a string.
    * @example
    *
    *   RegExp.escape('really?')      -> 'really\?'
    *   RegExp.escape('yes.')         -> 'yes\.'
    *   RegExp.escape('(not really)') -> '\(not really\)'
    *
    ***/
    'escape': function(str) {
      if(!isString(str)) str = String(str);
      return str.replace(/([\\/'*+?|()\[\]{}.^$])/g,'\\$1');
    }

  });

  extend(regexp, true, false, {

   /***
    * @method getFlags()
    * @returns String
    * @short Returns the flags of the regex as a string.
    * @example
    *
    *   /texty/gim.getFlags('testy') -> 'gim'
    *
    ***/
    'getFlags': function() {
      return getFlags(this);
    },

   /***
    * @method setFlags(<flags>)
    * @returns RegExp
    * @short Sets the flags on a regex and retuns a copy.
    * @example
    *
    *   /texty/.setFlags('gim') -> now has global, ignoreCase, and multiline set
    *
    ***/
    'setFlags': function(flags) {
      return regexp(this.source, flags);
    },

   /***
    * @method addFlag(<flag>)
    * @returns RegExp
    * @short Adds <flag> to the regex.
    * @example
    *
    *   /texty/.addFlag('g') -> now has global flag set
    *
    ***/
    'addFlag': function(flag) {
      return this.setFlags(getFlags(this, flag));
    },

   /***
    * @method removeFlag(<flag>)
    * @returns RegExp
    * @short Removes <flag> from the regex.
    * @example
    *
    *   /texty/g.removeFlag('g') -> now has global flag removed
    *
    ***/
    'removeFlag': function(flag) {
      return this.setFlags(getFlags(this).replace(flag, ''));
    }

  });

  /***
   * Function module
   *
   ***/

  function buildFunction() {
    var support = false;
    if(Function.prototype.bind) {
      function F() {};
      var B = F.bind();
      support = (new B instanceof B) && !(new F instanceof B);
    }
    extend(Function, true, !support, {

       /***
       * @method bind(<scope>, [arg1], ...)
       * @returns Function
       * @short Binds <scope> as the %this% object for the function when it is called. Also allows currying an unlimited number of parameters.
       * @extra "currying" means setting parameters ([arg1], [arg2], etc.) ahead of time so that they are passed when the function is called later. If you pass additional parameters when the function is actually called, they will be added will be added to the end of the curried parameters.
       * @example
       *
       +   (function() {
       *     return this;
       *   }).bind('woof')(); -> returns 'woof'; function is bound with 'woof' as the this object.
       *   (function(a) {
       *     return a;
       *   }).bind(1, 2)();   -> returns 2; function is bound with 1 as the this object and 2 curried as the first parameter
       *   (function(a, b) {
       *     return a + b;
       *   }).bind(1, 2)(3);  -> returns 5; function is bound with 1 as the this object, 2 curied as the first parameter and 3 passed as the second when calling the function
       *
       ***/
      'bind': function(scope) {
        var fn = this, args = getArgs(arguments, 1), nop, bound;
        if(!isFunction(this)) {
          throw new TypeError('Function.prototype.bind called on a non-function');
        }
        bound = function() {
          return fn.apply(fn.prototype && this instanceof fn ? this : scope, args.concat(getArgs(arguments)));
        }
        nop = function() {};
        nop.prototype = this.prototype;
        bound.prototype = new nop();
        return bound;
      }

    });
  }

  // Initialize
  buildTrim();
  buildFunction();

<commit_msg>removing simpleArrayEach<commit_after>// Google Closure Compiler will output a wrapping function here.

  // A few optimizations for Google Closure Compiler will save us a couple kb in the release script.
  var object = Object, array = Array, regexp = RegExp, date = Date, string = String, number = Number, math = Math, Undefined;

  // The global context
  var globalContext = typeof global !== 'undefined' ? global : this;

  // defineProperty exists in IE8 but will error when trying to define a property on
  // native objects. IE8 does not have defineProperies, however, so this check saves a try/catch block.
  var definePropertySupport = object.defineProperty && object.defineProperties;

  // Class extending methods

  function extend(klass, instance, override, methods) {
    var extendee = instance ? klass.prototype : klass, original;
    initializeClass(klass);
    iterateOverObject(methods, function(name, method) {
      original = extendee[name];
      if(typeof override === 'function') {
        method = wrapNative(extendee[name], method, override);
      }
      if(override !== false || !extendee[name]) {
        defineProperty(extendee, name, method);
      }
      // If the method is internal to Sugar, then store a reference so it can be restored later.
      klass['SugarMethods'][name] = { instance: instance, method: method, original: original };
    });
  }

  function initializeClass(klass) {
    if(klass['SugarMethods']) return;
    defineProperty(klass, 'SugarMethods', {});
    extend(klass, false, false, {
      'restore': function() {
        var all = arguments.length === 0, methods = getArgs(arguments);
        iterateOverObject(klass['SugarMethods'], function(name, m) {
          if(all || methods.indexOf(name) > -1) {
            defineProperty(m.instance ? klass.prototype : klass, name, m.method);
          }
        });
      },
      'extend': function(methods, override, instance) {
        extend(klass, instance !== false, override, methods);
      }
    });
  }

  function wrapNative(nativeFn, extendedFn, condition) {
    return function() {
      if(nativeFn && (condition === true || !condition.apply(this, arguments))) {
        return nativeFn.apply(this, arguments);
      } else {
        return extendedFn.apply(this, arguments);
      }
    }
  }

  function defineProperty(target, name, method) {
    if(definePropertySupport) {
      object.defineProperty(target, name, { 'value': method, 'configurable': true, 'enumerable': false, 'writable': true });
    } else {
      target[name] = method;
    }
  }

  function extendSimilar(klass, instance, set, fn) {
    var methods = {};
    set = isString(set) ? set.split(',') : set;
    set.forEach(function(name) {
      fn(name, methods);
    });
    extend(klass, instance, false, methods);
  }

  // Argument helpers

  function getArgs(args, index) {
    return array.prototype.slice.call(args, index);
  }

  function multiArgs(args, fn) {
    getArgs(args).forEach(fn);
  }

  // Used for both arrays and strings

  function entryAtIndex(arr, args, str) {
    var result = [], length = arr.length, loop = args[args.length - 1] !== false, r;
    multiArgs(args, function(index) {
      if(isBoolean(index)) return false;
      if(loop) {
        index = index % length;
        if(index < 0) index = length + index;
      }
      r = str ? arr.charAt(index) || '' : arr[index];
      result.push(r);
    });
    return result.length < 2 ? result[0] : result;
  }

  // General helpers

  function isDefined(o) {
    return o !== Undefined;
  }

  function isUndefined(o) {
    return o === Undefined;
  }

  function isClass(obj, str) {
    return object.prototype.toString.call(obj) === '[object '+str+']';
  }

  function isObject(obj) {
    // === on the constructor is not safe across iframes
    return !!obj && isClass(obj, 'Object') && string(obj.constructor) === string(object);
  }

  function isObjectPrimitive(obj) {
    // Check for null
    return obj && typeof obj === 'object';
  }

  function hasOwnProperty(obj, key) {
    return object.prototype.hasOwnProperty.call(obj, key);
  }

  /***
   * Object module
   *
   ***/

  // Object helpers

  function iterateOverObject(obj, fn) {
    var key;
    for(key in obj) {
      if(!hasOwnProperty(obj, key)) continue;
      if(fn.call(obj, key, obj[key]) === false) break;
    }
  }

  function commaSeparatedEach(str, fn) {
    str.split(',').forEach(fn);
  }

  function simpleMerge(target, source) {
    iterateOverObject(source, function(key) {
      target[key] = source[key];
    });
  }

  function simpleCapitalize(str) {
    return str.slice(0,1).toUpperCase() + str.slice(1);
  }

  function stringify(thing, stack) {
    var value, klass, isObject, isArray, arr, i, key, type = typeof thing;

    // Return quickly if string to save cycles
    if(type === 'string') return thing;

    klass    = object.prototype.toString.call(thing)
    isObject = klass === '[object Object]';
    isArray  = klass === '[object Array]';

    if(thing != null && isObject || isArray) {
      // This method for checking for cyclic structures was egregiously stolen from
      // the ingenious method by @kitcambridge from the Underscore script:
      // https://github.com/documentcloud/underscore/issues/240
      if(!stack) stack = [];
      // Allowing a step into the structure before triggering this
      // script to save cycles on standard JSON structures and also to
      // try as hard as possible to catch basic properties that may have
      // been modified.
      if(stack.length > 1) {
        i = stack.length;
        while (i--) {
          if (stack[i] === thing) {
            return 'CYC';
          }
        }
      }
      stack.push(thing);
      value = string(thing.constructor);
      arr = isArray ? thing : object.keys(thing).sort();
      for(i = 0; i < arr.length; i++) {
        key = isArray ? i : arr[i];
        value += key + stringify(thing[key], stack);
      }
      stack.pop();
    } else if(1 / thing === -Infinity) {
      value = '-0';
    } else {
      value = string(thing && thing.valueOf());
    }
    return type + klass + value;
  }

  var ClassNames = 'Array,Boolean,Date,Function,Number,String,RegExp'.split(',');

  var isArray    = buildClassCheck(ClassNames[0]);
  var isBoolean  = buildClassCheck(ClassNames[1]);
  var isDate     = buildClassCheck(ClassNames[2]);
  var isFunction = buildClassCheck(ClassNames[3]);
  var isNumber   = buildClassCheck(ClassNames[4]);
  var isString   = buildClassCheck(ClassNames[5]);
  var isRegExp   = buildClassCheck(ClassNames[6]);

  function buildClassCheck(type) {
    return function(obj) {
      return isClass(obj, type);
    }
  }

  function initializeClasses() {
    initializeClass(object);
    iterateOverObject(ClassNames, function(i,name) {
      initializeClass(globalContext[name]);
    });
  }
  initializeClasses();

  /***
   * Array module
   *
   ***/

  /***
   * Number module
   *
   ***/

  function getRange(start, stop, fn, step) {
    var arr = [], i = parseInt(start), down = step < 0;
    while((!down && i <= stop) || (down && i >= stop)) {
      arr.push(i);
      if(fn) fn.call(this, i);
      i += step || 1;
    }
    return arr;
  }

  function round(val, precision, method) {
    var fn = math[method || 'round'];
    var multiplier = math.pow(10, math.abs(precision || 0));
    if(precision < 0) multiplier = 1 / multiplier;
    return fn(val * multiplier) / multiplier;
  }

  function ceil(val, precision) {
    return round(val, precision, 'ceil');
  }

  function floor(val, precision) {
    return round(val, precision, 'floor');
  }

  /***
   * String module
   *
   ***/

  // WhiteSpace/LineTerminator as defined in ES5.1 plus Unicode characters in the Space, Separator category.
  var getTrimmableCharacters = function() {
    return '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u2028\u2029\u3000\uFEFF';
  }

  function repeatString(times, str) {
    return array(math.max(0, isDefined(times) ? times : 1) + 1).join(str || '');
  }

  function padNumber(num, place, sign, base) {
    var str = math.abs(num).toString(base || 10);
    str = repeatString(place - str.replace(/\.\d+/, '').length, '0') + str;
    if(sign || num < 0) {
      str = (num < 0 ? '-' : '+') + str;
    }
    return str;
  }

  function getOrdinalizedSuffix(num) {
    if(num >= 11 && num <= 13) {
      return 'th';
    } else {
      switch(num % 10) {
        case 1:  return 'st';
        case 2:  return 'nd';
        case 3:  return 'rd';
        default: return 'th';
      }
    }
  }

  function buildTrim() {
    var support = getTrimmableCharacters().match(/^\s+$/);
    try { string.prototype.trim.call([1]); } catch(e) { support = false; }
    var trimL = regexp('^['+getTrimmableCharacters()+']+');
    var trimR = regexp('['+getTrimmableCharacters()+']+$');
    extend(string, true, !support, {

      /***
       * @method trim[Side]()
       * @returns String
       * @short Removes leading and/or trailing whitespace from the string.
       * @extra Whitespace is defined as line breaks, tabs, and any character in the "Space, Separator" Unicode category, conforming to the the ES5 spec. The standard %trim% method is only added when not fully supported natively.
       * @example
       *
       *   '   wasabi   '.trim()      -> 'wasabi'
       *   '   wasabi   '.trimLeft()  -> 'wasabi   '
       *   '   wasabi   '.trimRight() -> '   wasabi'
       *
       ***
       * @method trim()
       * @set trimSide
       ***/
      'trim': function() {
        return this.toString().trimLeft().trimRight();
      },

      /***
       * @method trimLeft()
       * @set trimSide
       ***/
      'trimLeft': function() {
        return this.replace(trimL, '');
      },

      /***
       * @method trimRight()
       * @set trimSide
       ***/
      'trimRight': function() {
        return this.replace(trimR, '');
      }
    });
  }

  /***
   * RegExp module
   *
   * Note here that methods on the RegExp class like .exec and .test will fail in the current version of SpiderMonkey being
   * used by CouchDB when using shorthand regex notation like /foo/. This is the reason for the intermixed use of shorthand
   * and compiled regexes here. If you're using JS in CouchDB, it is safer to ALWAYS compile your regexes from a string.
   *
   ***/

  regexp.NPCGSupport = isUndefined(regexp('()??').exec('')[1]); // NPCG: nonparticipating capturing group

  function getFlags(reg, flag) {
    var flags = '';
    if(flag == 'g' || reg.global)     flags += 'g';
    if(flag == 'i' || reg.ignoreCase) flags += 'i';
    if(flag == 'm' || reg.multiline)  flags += 'm';
    if(flag == 'y' || reg.sticky)     flags += 'y';
    return flags;
  }

  extend(regexp, false, false, {

   /***
    * @method RegExp.escape(<str> = '')
    * @returns String
    * @short Escapes all RegExp tokens in a string.
    * @example
    *
    *   RegExp.escape('really?')      -> 'really\?'
    *   RegExp.escape('yes.')         -> 'yes\.'
    *   RegExp.escape('(not really)') -> '\(not really\)'
    *
    ***/
    'escape': function(str) {
      if(!isString(str)) str = String(str);
      return str.replace(/([\\/'*+?|()\[\]{}.^$])/g,'\\$1');
    }

  });

  extend(regexp, true, false, {

   /***
    * @method getFlags()
    * @returns String
    * @short Returns the flags of the regex as a string.
    * @example
    *
    *   /texty/gim.getFlags('testy') -> 'gim'
    *
    ***/
    'getFlags': function() {
      return getFlags(this);
    },

   /***
    * @method setFlags(<flags>)
    * @returns RegExp
    * @short Sets the flags on a regex and retuns a copy.
    * @example
    *
    *   /texty/.setFlags('gim') -> now has global, ignoreCase, and multiline set
    *
    ***/
    'setFlags': function(flags) {
      return regexp(this.source, flags);
    },

   /***
    * @method addFlag(<flag>)
    * @returns RegExp
    * @short Adds <flag> to the regex.
    * @example
    *
    *   /texty/.addFlag('g') -> now has global flag set
    *
    ***/
    'addFlag': function(flag) {
      return this.setFlags(getFlags(this, flag));
    },

   /***
    * @method removeFlag(<flag>)
    * @returns RegExp
    * @short Removes <flag> from the regex.
    * @example
    *
    *   /texty/g.removeFlag('g') -> now has global flag removed
    *
    ***/
    'removeFlag': function(flag) {
      return this.setFlags(getFlags(this).replace(flag, ''));
    }

  });

  /***
   * Function module
   *
   ***/

  function buildFunction() {
    var support = false;
    if(Function.prototype.bind) {
      function F() {};
      var B = F.bind();
      support = (new B instanceof B) && !(new F instanceof B);
    }
    extend(Function, true, !support, {

       /***
       * @method bind(<scope>, [arg1], ...)
       * @returns Function
       * @short Binds <scope> as the %this% object for the function when it is called. Also allows currying an unlimited number of parameters.
       * @extra "currying" means setting parameters ([arg1], [arg2], etc.) ahead of time so that they are passed when the function is called later. If you pass additional parameters when the function is actually called, they will be added will be added to the end of the curried parameters.
       * @example
       *
       +   (function() {
       *     return this;
       *   }).bind('woof')(); -> returns 'woof'; function is bound with 'woof' as the this object.
       *   (function(a) {
       *     return a;
       *   }).bind(1, 2)();   -> returns 2; function is bound with 1 as the this object and 2 curried as the first parameter
       *   (function(a, b) {
       *     return a + b;
       *   }).bind(1, 2)(3);  -> returns 5; function is bound with 1 as the this object, 2 curied as the first parameter and 3 passed as the second when calling the function
       *
       ***/
      'bind': function(scope) {
        var fn = this, args = getArgs(arguments, 1), nop, bound;
        if(!isFunction(this)) {
          throw new TypeError('Function.prototype.bind called on a non-function');
        }
        bound = function() {
          return fn.apply(fn.prototype && this instanceof fn ? this : scope, args.concat(getArgs(arguments)));
        }
        nop = function() {};
        nop.prototype = this.prototype;
        bound.prototype = new nop();
        return bound;
      }

    });
  }

  // Initialize
  buildTrim();
  buildFunction();

<|endoftext|>


<commit_before>/* TODO: BfA Edition!
 * Rising Mist - Poor use suggestions
 * Upwelling - Additional healing added from channel, missed healing from channel?
 * Mana Tea vs SotC - Potentially compare common output of each talent.
 *    Suggest using one over the other?
 * Vivify or REM - Missed Vivify healing from less than 2 REMs out
 * Azerite Bonus Placeholders
 */

import React from 'react';

import CoreCombatLogParser from 'parser/core/CombatLogParser';

import Panel from 'interface/others/Panel';
import LowHealthHealing from 'parser/shared/modules/features/LowHealthHealing';
import ManaLevelChart from 'parser/shared/modules/resources/mana/ManaLevelChart';
import ManaUsageChart from 'parser/shared/modules/resources/mana/ManaUsageChart';

import GlobalCooldown from './modules/core/GlobalCooldown';
import CoreChanneling from './modules/core/Channeling';
import HotTracker from './modules/core/HotTracker';
import SpellUsable from './modules/core/SpellUsable';

// Normalizers
import HotApplicationNormalizer from './normalizers/HotApplicationNormalizer';
import HotRemovalNormalizer from './normalizers/HotRemovalNormalizer';

// Features
import Abilities from './modules/features/Abilities';
import CooldownThroughputTracker from './modules/features/CooldownThroughputTracker';
import AlwaysBeCasting from './modules/features/AlwaysBeCasting';
import EssenceFontMastery from './modules/features/EssenceFontMastery';
import Checklist from './modules/features/Checklist/Module';
import StatValues from './modules/features/StatValues';
import EvmVivCastRatio from './modules/features/EvmVivCastRatio';
import MasteryStats from './modules/features/MasteryStats';
import Buffs from './modules/features/Buffs';

// Spells
import ThunderFocusTea from './modules/spells/ThunderFocusTea';
import EssenceFont from './modules/spells/EssenceFont';
import EnvelopingMists from './modules/spells/EnvelopingMists';
import SoothingMist from './modules/spells/SoothingMist';
import Vivify from './modules/spells/Vivify';
import LifeCocoon from './modules/spells/LifeCocoon';
import SpinningCraneKick from './modules/spells/SpinningCraneKick';
import RenewingMist from './modules/spells/RenewingMist';

// Talents
import JadeSerpentStatue from './modules/talents/JadeSerpentStatue';
import ChiJi from './modules/talents/ChiJi';
import ChiBurst from './modules/talents/ChiBurst';
import ManaTea from './modules/talents/ManaTea';
import RefreshingJadeWind from './modules/talents/RefreshingJadeWind';
import Lifecycles from './modules/talents/Lifecycles';
import SpiritOfTheCrane from './modules/talents/SpiritOfTheCrane';
import RisingMist from './modules/talents/RisingMist';
import RenewingMistDuringManaTea from './modules/talents/RenewingMistDuringManaTea';

// Azerite Traits
import FontOfLife from './modules/spells/azeritetraits/FontOfLife';
import UpliftedSpirits from './modules/spells/azeritetraits/UpliftedSpirits';
import SecretInfusion from './modules/spells/azeritetraits/SecretInfusion';

// Mana Tracker
import MistweaverHealingEfficiencyDetails from './modules/features/MistweaverHealingEfficiencyDetails';
// import HealingEfficiencyDetails from '../../core/healingEfficiency/HealingEfficiencyDetails';
import HealingEfficiencyTracker from './modules/features/MistweaverHealingEfficiencyTracker';
import ManaTracker from '../../core/healingEfficiency/ManaTracker';

import { ABILITIES_AFFECTED_BY_HEALING_INCREASES } from './constants';

class CombatLogParser extends CoreCombatLogParser {
  static abilitiesAffectedByHealingIncreases = ABILITIES_AFFECTED_BY_HEALING_INCREASES;

  static specModules = {
    // Normalizer
    hotApplicationNormalizer: HotApplicationNormalizer,
    hotRemovalNormalizer: HotRemovalNormalizer,

    // Core
    lowHealthHealing: LowHealthHealing,
    channeling: CoreChanneling,
    globalCooldown: GlobalCooldown,
    hotTracker: HotTracker,
    spellUsable: SpellUsable,

    // Generic healer things
    manaLevelChart: ManaLevelChart,
    manaUsageChart: ManaUsageChart,

    // Features
    alwaysBeCasting: AlwaysBeCasting,
    abilities: Abilities,
    cooldownThroughputTracker: CooldownThroughputTracker,
    essenceFontMastery: EssenceFontMastery,
    checklist: Checklist,
    statValues: StatValues,
    evmVivCastRatio: EvmVivCastRatio,
    masteryStats: MasteryStats,
    buffs: Buffs,

    // Spells
    essenceFont: EssenceFont,
    thunderFocusTea: ThunderFocusTea,
    envelopingMists: EnvelopingMists,
    soothingMist: SoothingMist, // Removed as this needs to be reworked with updated Soothing Mist Spell in BfA
    spinningCraneKick: SpinningCraneKick,
    vivify: Vivify,
    renewingMist: RenewingMist,
    lifeCocoon: LifeCocoon,

    // Talents
    chiBurst: ChiBurst,
    chiJi: ChiJi,
    manaTea: ManaTea,
    refreshingJadeWind: RefreshingJadeWind,
    lifecycles: Lifecycles,
    spiritOfTheCrane: SpiritOfTheCrane,
    risingMist: RisingMist,
    jadeSerpentStatue: JadeSerpentStatue,
    renewingMistDuringManaTea: RenewingMistDuringManaTea,

    // Azerite Traits
    fontOfLife: FontOfLife,
    upliftedSpirits: UpliftedSpirits,
    secretInfusion: SecretInfusion,

    // Mana Tab
    manaTracker: ManaTracker,
    hpmDetails: MistweaverHealingEfficiencyDetails,
    hpmTracker: HealingEfficiencyTracker,
  };
}

export default CombatLogParser;
<commit_msg>Removed unneeded imports<commit_after>/* TODO: BfA Edition!
 * Rising Mist - Poor use suggestions
 * Upwelling - Additional healing added from channel, missed healing from channel?
 * Mana Tea vs SotC - Potentially compare common output of each talent.
 *    Suggest using one over the other?
 * Vivify or REM - Missed Vivify healing from less than 2 REMs out
 * Azerite Bonus Placeholders
 */
import CoreCombatLogParser from 'parser/core/CombatLogParser';

import LowHealthHealing from 'parser/shared/modules/features/LowHealthHealing';
import ManaLevelChart from 'parser/shared/modules/resources/mana/ManaLevelChart';
import ManaUsageChart from 'parser/shared/modules/resources/mana/ManaUsageChart';

import GlobalCooldown from './modules/core/GlobalCooldown';
import CoreChanneling from './modules/core/Channeling';
import HotTracker from './modules/core/HotTracker';
import SpellUsable from './modules/core/SpellUsable';

// Normalizers
import HotApplicationNormalizer from './normalizers/HotApplicationNormalizer';
import HotRemovalNormalizer from './normalizers/HotRemovalNormalizer';

// Features
import Abilities from './modules/features/Abilities';
import CooldownThroughputTracker from './modules/features/CooldownThroughputTracker';
import AlwaysBeCasting from './modules/features/AlwaysBeCasting';
import EssenceFontMastery from './modules/features/EssenceFontMastery';
import Checklist from './modules/features/Checklist/Module';
import StatValues from './modules/features/StatValues';
import EvmVivCastRatio from './modules/features/EvmVivCastRatio';
import MasteryStats from './modules/features/MasteryStats';
import Buffs from './modules/features/Buffs';

// Spells
import ThunderFocusTea from './modules/spells/ThunderFocusTea';
import EssenceFont from './modules/spells/EssenceFont';
import EnvelopingMists from './modules/spells/EnvelopingMists';
import SoothingMist from './modules/spells/SoothingMist';
import Vivify from './modules/spells/Vivify';
import LifeCocoon from './modules/spells/LifeCocoon';
import SpinningCraneKick from './modules/spells/SpinningCraneKick';
import RenewingMist from './modules/spells/RenewingMist';

// Talents
import JadeSerpentStatue from './modules/talents/JadeSerpentStatue';
import ChiJi from './modules/talents/ChiJi';
import ChiBurst from './modules/talents/ChiBurst';
import ManaTea from './modules/talents/ManaTea';
import RefreshingJadeWind from './modules/talents/RefreshingJadeWind';
import Lifecycles from './modules/talents/Lifecycles';
import SpiritOfTheCrane from './modules/talents/SpiritOfTheCrane';
import RisingMist from './modules/talents/RisingMist';
import RenewingMistDuringManaTea from './modules/talents/RenewingMistDuringManaTea';

// Azerite Traits
import FontOfLife from './modules/spells/azeritetraits/FontOfLife';
import UpliftedSpirits from './modules/spells/azeritetraits/UpliftedSpirits';
import SecretInfusion from './modules/spells/azeritetraits/SecretInfusion';

// Mana Tracker
import MistweaverHealingEfficiencyDetails from './modules/features/MistweaverHealingEfficiencyDetails';
// import HealingEfficiencyDetails from '../../core/healingEfficiency/HealingEfficiencyDetails';
import HealingEfficiencyTracker from './modules/features/MistweaverHealingEfficiencyTracker';
import ManaTracker from '../../core/healingEfficiency/ManaTracker';

import { ABILITIES_AFFECTED_BY_HEALING_INCREASES } from './constants';

class CombatLogParser extends CoreCombatLogParser {
  static abilitiesAffectedByHealingIncreases = ABILITIES_AFFECTED_BY_HEALING_INCREASES;

  static specModules = {
    // Normalizer
    hotApplicationNormalizer: HotApplicationNormalizer,
    hotRemovalNormalizer: HotRemovalNormalizer,

    // Core
    lowHealthHealing: LowHealthHealing,
    channeling: CoreChanneling,
    globalCooldown: GlobalCooldown,
    hotTracker: HotTracker,
    spellUsable: SpellUsable,

    // Generic healer things
    manaLevelChart: ManaLevelChart,
    manaUsageChart: ManaUsageChart,

    // Features
    alwaysBeCasting: AlwaysBeCasting,
    abilities: Abilities,
    cooldownThroughputTracker: CooldownThroughputTracker,
    essenceFontMastery: EssenceFontMastery,
    checklist: Checklist,
    statValues: StatValues,
    evmVivCastRatio: EvmVivCastRatio,
    masteryStats: MasteryStats,
    buffs: Buffs,

    // Spells
    essenceFont: EssenceFont,
    thunderFocusTea: ThunderFocusTea,
    envelopingMists: EnvelopingMists,
    soothingMist: SoothingMist, // Removed as this needs to be reworked with updated Soothing Mist Spell in BfA
    spinningCraneKick: SpinningCraneKick,
    vivify: Vivify,
    renewingMist: RenewingMist,
    lifeCocoon: LifeCocoon,

    // Talents
    chiBurst: ChiBurst,
    chiJi: ChiJi,
    manaTea: ManaTea,
    refreshingJadeWind: RefreshingJadeWind,
    lifecycles: Lifecycles,
    spiritOfTheCrane: SpiritOfTheCrane,
    risingMist: RisingMist,
    jadeSerpentStatue: JadeSerpentStatue,
    renewingMistDuringManaTea: RenewingMistDuringManaTea,

    // Azerite Traits
    fontOfLife: FontOfLife,
    upliftedSpirits: UpliftedSpirits,
    secretInfusion: SecretInfusion,

    // Mana Tab
    manaTracker: ManaTracker,
    hpmDetails: MistweaverHealingEfficiencyDetails,
    hpmTracker: HealingEfficiencyTracker,
  };
}

export default CombatLogParser;
<|endoftext|>


<commit_before>module.exports = (api, options, rootOptions) => {
  let version = '*'
  const mainVersion = require('./package.json').version
  if (mainVersion.indexOf('alpha') !== -1) {
    version = '^' + mainVersion
  }
  api.extendPackage(pkg => {
    delete pkg.postcss
    delete pkg.browserslist
    return {
      scripts: {
        'info': 'node node_modules/@dcloudio/vue-cli-plugin-uni/commands/info.js',
        'serve': 'npm run dev:h5',
        'build': 'npm run build:h5',
        'dev:h5': 'cross-env NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve',
        'dev:mp-qq': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-qq vue-cli-service uni-build --watch',
        'dev:mp-weixin': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch',
        'dev:mp-baidu': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-baidu vue-cli-service uni-build --watch',
        'dev:mp-alipay': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-alipay vue-cli-service uni-build --watch',
        'dev:mp-toutiao': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-toutiao vue-cli-service uni-build --watch',
        'build:h5': 'cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build',
        'build:mp-qq': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-qq vue-cli-service uni-build',
        'build:mp-weixin': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build',
        'build:mp-baidu': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-baidu vue-cli-service uni-build',
        'build:mp-alipay': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-alipay vue-cli-service uni-build',
        'build:mp-toutiao': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-toutiao vue-cli-service uni-build',
        'dev:custom': 'cross-env NODE_ENV=development uniapp-cli custom',
        'build:custom': 'cross-env NODE_ENV=production uniapp-cli custom'
      },
      'uni-app': {
        'scripts': {}
      },
      dependencies: {
        '@dcloudio/uni-app-plus': version,
        '@dcloudio/uni-h5': version,
        '@dcloudio/uni-mp-qq': version,
        '@dcloudio/uni-mp-weixin': version,
        '@dcloudio/uni-mp-baidu': version,
        '@dcloudio/uni-mp-alipay': version,
        '@dcloudio/uni-mp-toutiao': version,
        '@dcloudio/uni-stat': version,
        'flyio': '^0.6.2',
        'vuex': '^3.0.1'
      },
      devDependencies: {
        '@dcloudio/uni-cli-shared': version,
        '@dcloudio/uni-template-compiler': version,
        '@dcloudio/webpack-uni-mp-loader': version,
        '@dcloudio/webpack-uni-pages-loader': version,
        'babel-plugin-import': '^1.11.0'
      },
      browserslist: [
        'Android >= 4.4',
        'ios >= 8'
      ]
    }
  })
}
<commit_msg>fix(cli): vue-cli-plugin-* version<commit_after>module.exports = (api, options, rootOptions) => {
  let version = '*'
  const mainVersion = require('./package.json').version
  if (mainVersion.indexOf('alpha') !== -1) {
    version = '^' + mainVersion
  }
  api.extendPackage(pkg => {
    delete pkg.postcss
    delete pkg.browserslist
    return {
      scripts: {
        'info': 'node node_modules/@dcloudio/vue-cli-plugin-uni/commands/info.js',
        'serve': 'npm run dev:h5',
        'build': 'npm run build:h5',
        'dev:h5': 'cross-env NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve',
        'dev:mp-qq': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-qq vue-cli-service uni-build --watch',
        'dev:mp-weixin': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch',
        'dev:mp-baidu': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-baidu vue-cli-service uni-build --watch',
        'dev:mp-alipay': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-alipay vue-cli-service uni-build --watch',
        'dev:mp-toutiao': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-toutiao vue-cli-service uni-build --watch',
        'build:h5': 'cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build',
        'build:mp-qq': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-qq vue-cli-service uni-build',
        'build:mp-weixin': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build',
        'build:mp-baidu': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-baidu vue-cli-service uni-build',
        'build:mp-alipay': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-alipay vue-cli-service uni-build',
        'build:mp-toutiao': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-toutiao vue-cli-service uni-build',
        'dev:custom': 'cross-env NODE_ENV=development uniapp-cli custom',
        'build:custom': 'cross-env NODE_ENV=production uniapp-cli custom'
      },
      'uni-app': {
        'scripts': {}
      },
      dependencies: {
        '@dcloudio/uni-app-plus': version,
        '@dcloudio/uni-h5': version,
        '@dcloudio/uni-mp-qq': version,
        '@dcloudio/uni-mp-weixin': version,
        '@dcloudio/uni-mp-baidu': version,
        '@dcloudio/uni-mp-alipay': version,
        '@dcloudio/uni-mp-toutiao': version,
        '@dcloudio/uni-stat': version,
        'flyio': '^0.6.2',
        'vuex': '^3.0.1'
      },
      devDependencies: {
        '@dcloudio/uni-cli-shared': version,
        '@dcloudio/uni-template-compiler': version,
        '@dcloudio/vue-cli-plugin-hbuilderx': version,
        '@dcloudio/vue-cli-plugin-uni': version,
        '@dcloudio/vue-cli-plugin-uni-optimize': version,
        '@dcloudio/webpack-uni-mp-loader': version,
        '@dcloudio/webpack-uni-pages-loader': version,
        'babel-plugin-import': '^1.11.0'
      },
      browserslist: [
        'Android >= 4.4',
        'ios >= 8'
      ]
    }
  })
}
<|endoftext|>


<commit_before><commit_msg>简化进程间通信的语法<commit_after><|endoftext|>


<commit_before>const libob = require('libobject');

exports.module = (loader, subject, predicate, object) => {
    //console.log('Load module:', object, '\n');
};

exports.instance = (loader, subject, predicate, object) => {
    //console.log('Create and load instance:', object, '\n');
};

exports.listener = (loader, subject, predicate, object) => {
    //console.log('Create event', object, '\n');
};

exports.sequence = (loader, subject, predicate, object) => {
    //console.log('Create new sequence', object, '\n');
};

exports.handler = (loader, subject, predicate, object) => {
    //console.log('Create handler and add to seqence', object, '\n');
};

exports.event = (loader, subject, predicate, object) => {
    // check if sequence exists
    // 0 -> wait for sequence
    // 1 -> check if handler exists
    //      0 -> wait for handler
    //      1 -> emit flow event and pass it to handler
    //console.log('Get event stream and pipe to sequence', object, '\n');
};

exports.method = (loader, subject, predicate, object) => {
    // check if seqence exists
    // 0 -> wait for sequence
    // 1 -> check if handler exists
    //      0 -> wait for handler
    //      1 -> check if instance exists
    //           0 -> wait and try again on instance ready
    //           1 -> get method ref and pass it to handler
    //console.log('Load instance, get method ref', object, '\n');
};

exports.object = (loader, subject, predicate, object) => {
    //console.log('Build object', object, 'of type', predicate, 'attach to', subject, '\n');
};
        /*if (err || (!composition || !composition.module) || !roleAccess(composition, options.session)) {
            return loader.emit('error', err || new Error('Flow.load: No access or invalid composition'));
        }

        // emit flow events on load
        if (composition.load) {
            composition.load.forEach((event) => {
                scope.flow(event).end(options);
            });
        }

        // get cached module
        if (scope.modules[composition.module]) {
            build(scope, loader, composition, scope.modules[composition.module]);
            return;
        }

        loader.once('module', (module) => {
            scope.modules[composition.module] = module;
            build(scope, loader, composition, module);
        });

        if (scope.modules[composition.module] === null) {
            return;
        }

        scope.modules[composition.module] = null;
        scope.mod(composition.module, options, (err, module) => {

            if (err) {
                return loader.emit('error', err);
            }

            loader.emit('module', module);
        });
    });
}

function roleAccess (item, role) {

    var roles = item && (item._roles || item.roles || {}) || {};
    role = role && role.role ? role.role : role;

    if (roles['*'] || (typeof role === 'string' && roles[role])) {
        return true;
    }
}

function build (scope, loader, config, module) {

    // create new flow emitter
    var instance = Object.create(module);
    instance.flow = scope.flow.bind(null, config.name);
    instance._name = config.name;
    instance._reset = scope.reset;
    instance._config = config.config || {};

    // extend loader
    loader.module = config.module;
    loader.name = config.name;
    loader.roles = config.roles || {};
    loader.flow = config.flow || {};
    loader.parsed = {};

    var ready = function (err, data) {

        if (err) {
            return loader.emit('error', err);
        }

        // mark instance as ready
        loader.inst = instance;
        loader.ready = true;
        loader.emit('ready', loader);
    };

    // init loader instance
    instance.init ? instance.init(config.config || {}, ready) : ready();
}*/

function parse (scope, event, event_id, options, instance) {

    var sequence = scope.events[event_id];

    if (!instance.flow || !instance.flow[event]) {
        return sequence.emit('error', new Error('Flow.parse: Event "' + event + '" not found on instance "' + instance.name + '".'));
    }

    if (!instance.flow[event].d) {
        return sequence.emit('error', new Error('Flow.parse: No data handlers.'));
    }

    var parsedEvent = parseEvent(scope, instance, instance.flow[event].d);
    var count = 0;
    var check = function () {
        if (++count === parsedEvent.l.length) {
            parseSequence(scope, sequence, parsedEvent.s);
        }
    };

    // set instance ref
    sequence.i = instance;

    // set end and error events
    sequence.e = instance.flow[event].e;
    sequence.r = instance.flow[event].r;

    if (parsedEvent.l.length > 0) {
        parsedEvent.l.forEach(function (instName) {
            Load(scope, sequence, instName, options, check);
        });

    } else {
        parseSequence(scope, sequence, parsedEvent.s);
    }
}

function parseEvent (scope, instance, config) {

    var instances = {};
    var sequences = [];
    var pointer = 0;

    config.forEach(function (handler) {

        // resolve handler
        var path = handler;
        var args = {};

        if (handler.constructor === Array) {
            path = handler[0];
            args = handler[1] || {};
        }

        let type = path.substr(0, 1);
        path = path.substr(1);

        // parse path
        let instance_name = instance.name;
        if (path.indexOf('/') > 0) {
            path = path.split('/', 2);
            instance_name = path[0];
            path = path[1];
        }

        if (!scope.instances[instance_name] || !scope.instances[instance_name].ready) {
            instances[instance_name] = 1;
        }

        switch (type) {

            // data handlers
            case ':':
            case '.':

                // create new section if current is a even/stream handler
                if (sequences[pointer] && sequences[pointer][0] > 0) {
                    ++pointer;
                }

                sequences[pointer] = sequences[pointer] || [0, []];
                sequences[pointer][1].push([instance_name, path, args, (type === '.')]);
                return;

            // stream handlers
            case '>':
            case '*':

                sequences.push([(type === '*' ? 1 : 2), [instance_name, path, args]]);

                ++pointer;
                return;
        }

        sequence.emit('error', new Error('Flow.parse: Invalid handler type:', type));
    });

    return {
        l: Object.keys(instances),
        s: sequences
    };
}

// update sequences with method refs
function parseSequence (scope, event, sequences) {

    var getMethodRef = function (handler) {
        handler[0] = scope.instances[handler[0]].inst;

        if (!(handler[1] = libob.path(handler[1], handler[0]))) {
            return event.emit('error', new Error('Flow.parse: Method on instance "' + handler[0]._name + '" not found.'));
        }
    };

    for (var i = 0, l = sequences.length, sequence; i < l; ++i) {
        sequence = sequences[i];

        switch (sequence[0]) {
            case 0:
                sequence[1].forEach(getMethodRef);
                break;
            case 1:
                getMethodRef(sequence[1]);
                break;
            case 2:
                sequence[1][0] = scope.instances[sequence[1][0]].inst;
        }
    }

    event.s = sequences;
    event.ready = true;
    event.emit('ready', event);
}
<commit_msg>add some comments<commit_after>const libob = require('libobject');

exports.module = (loader, subject, predicate, object) => {
    console.log('Load module:', object, '\n');
    //loader.scope.mod(object, (err, module) => {
    //    console.log(err, module);
    //});
};

exports.instance = (loader, subject, predicate, object) => {
    //console.log('Create and load instance:', object, '\n');
    // check if instance is cached
    // load instance
};

exports.listener = (loader, subject, predicate, object) => {
    //console.log('Create event', object, '\n');
};

exports.sequence = (loader, subject, predicate, object) => {
    //console.log('Create new sequence', object, '\n');
};

exports.handler = (loader, subject, predicate, object) => {
    //console.log('Create handler and add to seqence', object, '\n');
};

exports.event = (loader, subject, predicate, object) => {
    // check if sequence exists
    // 0 -> wait for sequence
    // 1 -> check if handler exists
    //      0 -> wait for handler
    //      1 -> emit flow event and pass it to handler
    //console.log('Get event stream and pipe to sequence', object, '\n');
};

exports.method = (loader, subject, predicate, object) => {
    // check if seqence exists
    // 0 -> wait for sequence
    // 1 -> check if handler exists
    //      0 -> wait for handler
    //      1 -> check if instance exists
    //           0 -> wait and try again on instance ready
    //           1 -> get method ref and pass it to handler
    //console.log('Load instance, get method ref', object, '\n');
};

exports.object = (loader, subject, predicate, object) => {
    //console.log('Build object', object, 'of type', predicate, 'attach to', subject, '\n');
};
        /*if (err || (!composition || !composition.module) || !roleAccess(composition, options.session)) {
            return loader.emit('error', err || new Error('Flow.load: No access or invalid composition'));
        }

        // emit flow events on load
        if (composition.load) {
            composition.load.forEach((event) => {
                scope.flow(event).end(options);
            });
        }

        // get cached module
        if (scope.modules[composition.module]) {
            build(scope, loader, composition, scope.modules[composition.module]);
            return;
        }

        loader.once('module', (module) => {
            scope.modules[composition.module] = module;
            build(scope, loader, composition, module);
        });

        if (scope.modules[composition.module] === null) {
            return;
        }

        scope.modules[composition.module] = null;
        scope.mod(composition.module, options, (err, module) => {

            if (err) {
                return loader.emit('error', err);
            }

            loader.emit('module', module);
        });
    });
}

function roleAccess (item, role) {

    var roles = item && (item._roles || item.roles || {}) || {};
    role = role && role.role ? role.role : role;

    if (roles['*'] || (typeof role === 'string' && roles[role])) {
        return true;
    }
}

function build (scope, loader, config, module) {

    // create new flow emitter
    var instance = Object.create(module);
    instance.flow = scope.flow.bind(null, config.name);
    instance._name = config.name;
    instance._reset = scope.reset;
    instance._config = config.config || {};

    // extend loader
    loader.module = config.module;
    loader.name = config.name;
    loader.roles = config.roles || {};
    loader.flow = config.flow || {};
    loader.parsed = {};

    var ready = function (err, data) {

        if (err) {
            return loader.emit('error', err);
        }

        // mark instance as ready
        loader.inst = instance;
        loader.ready = true;
        loader.emit('ready', loader);
    };

    // init loader instance
    instance.init ? instance.init(config.config || {}, ready) : ready();
}*/

function parse (scope, event, event_id, options, instance) {

    var sequence = scope.events[event_id];

    if (!instance.flow || !instance.flow[event]) {
        return sequence.emit('error', new Error('Flow.parse: Event "' + event + '" not found on instance "' + instance.name + '".'));
    }

    if (!instance.flow[event].d) {
        return sequence.emit('error', new Error('Flow.parse: No data handlers.'));
    }

    var parsedEvent = parseEvent(scope, instance, instance.flow[event].d);
    var count = 0;
    var check = function () {
        if (++count === parsedEvent.l.length) {
            parseSequence(scope, sequence, parsedEvent.s);
        }
    };

    // set instance ref
    sequence.i = instance;

    // set end and error events
    sequence.e = instance.flow[event].e;
    sequence.r = instance.flow[event].r;

    if (parsedEvent.l.length > 0) {
        parsedEvent.l.forEach(function (instName) {
            Load(scope, sequence, instName, options, check);
        });

    } else {
        parseSequence(scope, sequence, parsedEvent.s);
    }
}

function parseEvent (scope, instance, config) {

    var instances = {};
    var sequences = [];
    var pointer = 0;

    config.forEach(function (handler) {

        // resolve handler
        var path = handler;
        var args = {};

        if (handler.constructor === Array) {
            path = handler[0];
            args = handler[1] || {};
        }

        let type = path.substr(0, 1);
        path = path.substr(1);

        // parse path
        let instance_name = instance.name;
        if (path.indexOf('/') > 0) {
            path = path.split('/', 2);
            instance_name = path[0];
            path = path[1];
        }

        if (!scope.instances[instance_name] || !scope.instances[instance_name].ready) {
            instances[instance_name] = 1;
        }

        switch (type) {

            // data handlers
            case ':':
            case '.':

                // create new section if current is a even/stream handler
                if (sequences[pointer] && sequences[pointer][0] > 0) {
                    ++pointer;
                }

                sequences[pointer] = sequences[pointer] || [0, []];
                sequences[pointer][1].push([instance_name, path, args, (type === '.')]);
                return;

            // stream handlers
            case '>':
            case '*':

                sequences.push([(type === '*' ? 1 : 2), [instance_name, path, args]]);

                ++pointer;
                return;
        }

        sequence.emit('error', new Error('Flow.parse: Invalid handler type:', type));
    });

    return {
        l: Object.keys(instances),
        s: sequences
    };
}

// update sequences with method refs
function parseSequence (scope, event, sequences) {

    var getMethodRef = function (handler) {
        handler[0] = scope.instances[handler[0]].inst;

        if (!(handler[1] = libob.path(handler[1], handler[0]))) {
            return event.emit('error', new Error('Flow.parse: Method on instance "' + handler[0]._name + '" not found.'));
        }
    };

    for (var i = 0, l = sequences.length, sequence; i < l; ++i) {
        sequence = sequences[i];

        switch (sequence[0]) {
            case 0:
                sequence[1].forEach(getMethodRef);
                break;
            case 1:
                getMethodRef(sequence[1]);
                break;
            case 2:
                sequence[1][0] = scope.instances[sequence[1][0]].inst;
        }
    }

    event.s = sequences;
    event.ready = true;
    event.emit('ready', event);
}
<|endoftext|>