<commit_before>import Ember from 'ember-metal/core'; // Ember.assert
import dictionary from 'ember-metal/dictionary';
import Container from 'container/container';

var VALID_FULL_NAME_REGEXP = /^[^:]+.+:[^:]+$/;

/**
 A lightweight registry used to store factory and option information keyed
 by type.

 A `Registry` stores the factory and option information needed by a
 `Container` to instantiate and cache objects.

 The public API for `Registry` is still in flux and should not be considered
 stable.

 @private
 @class Registry
*/
function Registry(options) {
  options = options || {};

  this.resolver = options.resolver || function() {};

  this.registrations  = dictionary(options.registrations || null);
  this.typeInjections = dictionary(options.typeInjections || null);
  this.injections     = dictionary(null);
  this.factoryTypeInjections = dictionary(null);
  this.factoryInjections     = dictionary(null);

  this._normalizeCache = dictionary(null);
  this._resolveCache   = dictionary(null);

  this._options     = dictionary(options.options || null);
  this._typeOptions = dictionary(options.typeOptions || null);
}

Registry.prototype = {
  /**
   @property resolver
   @type function
   */
  resolver: null,

  /**
   @property registrations
   @type InheritingDict
   */
  registrations: null,

  /**
   @property typeInjections
   @type InheritingDict
   */
  typeInjections: null,

  /**
   @property injections
   @type InheritingDict
   */
  injections: null,

  /**
   @property factoryTypeInjections
   @type InheritingDict
   */
  factoryTypeInjections: null,

  /**
   @property factoryInjections
   @type InheritingDict
   */
  factoryInjections: null,

  /**
   @private

   @property _normalizeCache
   @type InheritingDict
   */
  _normalizeCache: null,

  /**
   @private

   @property _resolveCache
   @type InheritingDict
   */
  _resolveCache: null,

  /**
   @private

   @property _options
   @type InheritingDict
   */
  _options: null,

  /**
   @private

   @property _typeOptions
   @type InheritingDict
   */
  _typeOptions: null,

  /**
   The first container created for this registry.

   This allows deprecated access to `lookup` and `lookupFactory` to avoid
   breaking compatibility for Ember 1.x initializers.

   @private
   @property _defaultContainer
   @type Container
   */
   _defaultContainer: null,

  /**
   Creates a container based on this registry.

   @method container
   @param {Object} options
   @return {Container} created container
   */
  container: function(options) {
    var container = new Container(this, options);

    // Allow deprecated access to the first child container's `lookup` and
    // `lookupFactory` methods to avoid breaking compatibility for Ember 1.x
    // initializers.
    if (!this._defaultContainer) {
      this._defaultContainer = container;
    }

    return container;
  },

  lookup: function(fullName, options) {
    Ember.assert('Create a container on the registry (with `registry.container()`) before calling `lookup`.', this._defaultContainer);
    Ember.deprecate('`lookup` should not be called on a Registry. Call `lookup` directly on an associated Container instead.');
    return this._defaultContainer.lookup(fullName, options);
  },

  lookupFactory: function(fullName) {
    Ember.assert('Create a container on the registry (with `registry.container()`) before calling `lookupFactory`.', this._defaultContainer);
    Ember.deprecate('`lookupFactory` should not be called on a Registry. Call `lookupFactory` directly on an associated Container instead.');
    return this._defaultContainer.lookupFactory(fullName);
  },

  /**
   Registers a factory for later injection.

   Example:

   ```javascript
   var registry = new Registry();

   registry.register('model:user', Person, {singleton: false });
   registry.register('fruit:favorite', Orange);
   registry.register('communication:main', Email, {singleton: false});
   ```

   @method register
   @param {String} fullName
   @param {Function} factory
   @param {Object} options
   */
  register: function(fullName, factory, options) {
    Ember.assert('fullName must be a proper full name', this.validateFullName(fullName));

    if (factory === undefined) {
      throw new TypeError('Attempting to register an unknown factory: `' + fullName + '`');
    }

    var normalizedName = this.normalize(fullName);

    if (this._resolveCache[normalizedName]) {
      throw new Error('Cannot re-register: `' + fullName +'`, as it has already been resolved.');
    }

    this.registrations[normalizedName] = factory;
    this._options[normalizedName] = (options || {});
  },

  /**
   Unregister a fullName

   ```javascript
   var registry = new Registry();
   registry.register('model:user', User);

   registry.resolve('model:user').create() instanceof User //=> true

   registry.unregister('model:user')
   registry.resolve('model:user') === undefined //=> true
   ```

   @method unregister
   @param {String} fullName
   */
  unregister: function(fullName) {
    Ember.assert('fullName must be a proper full name', this.validateFullName(fullName));

    var normalizedName = this.normalize(fullName);

    delete this.registrations[normalizedName];
    delete this._resolveCache[normalizedName];
    delete this._options[normalizedName];
  },

  /**
   Given a fullName return the corresponding factory.

   By default `resolve` will retrieve the factory from
   the registry.

   ```javascript
   var registry = new Registry();
   registry.register('api:twitter', Twitter);

   registry.resolve('api:twitter') // => Twitter
   ```

   Optionally the registry can be provided with a custom resolver.
   If provided, `resolve` will first provide the custom resolver
   the opportunity to resolve the fullName, otherwise it will fallback
   to the registry.

   ```javascript
   var registry = new Registry();
   registry.resolver = function(fullName) {
      // lookup via the module system of choice
    };

   // the twitter factory is added to the module system
   registry.resolve('api:twitter') // => Twitter
   ```

   @method resolve
   @param {String} fullName
   @return {Function} fullName's factory
   */
  resolve: function(fullName) {
    Ember.assert('fullName must be a proper full name', this.validateFullName(fullName));
    return resolve(this, this.normalize(fullName));
  },

  /**
   A hook that can be used to describe how the resolver will
   attempt to find the factory.

   For example, the default Ember `.describe` returns the full
   class name (including namespace) where Ember's resolver expects
   to find the `fullName`.

   @method describe
   @param {String} fullName
   @return {string} described fullName
   */
  describe: function(fullName) {
    return fullName;
  },

  /**
   A hook to enable custom fullName normalization behaviour

   @method normalizeFullName
   @param {String} fullName
   @return {string} normalized fullName
   */
  normalizeFullName: function(fullName) {
    return fullName;
  },

  /**
   normalize a fullName based on the applications conventions

   @method normalize
   @param {String} fullName
   @return {string} normalized fullName
   */
  normalize: function(fullName) {
    return this._normalizeCache[fullName] || (
        this._normalizeCache[fullName] = this.normalizeFullName(fullName)
      );
  },

  /**
   @method makeToString

   @param {any} factory
   @param {string} fullName
   @return {function} toString function
   */
  makeToString: function(factory, fullName) {
    return factory.toString();
  },

  /**
   Given a fullName check if the container is aware of its factory
   or singleton instance.

   @method has
   @param {String} fullName
   @return {Boolean}
   */
  has: function(fullName) {
    Ember.assert('fullName must be a proper full name', this.validateFullName(fullName));
    return has(this, this.normalize(fullName));
  },

  /**
   Allow registering options for all factories of a type.

   ```javascript
   var registry = new Registry();
   var container = registry.container();

   // if all of type `connection` must not be singletons
   registry.optionsForType('connection', { singleton: false });

   registry.register('connection:twitter', TwitterConnection);
   registry.register('connection:facebook', FacebookConnection);

   var twitter = container.lookup('connection:twitter');
   var twitter2 = container.lookup('connection:twitter');

   twitter === twitter2; // => false

   var facebook = container.lookup('connection:facebook');
   var facebook2 = container.lookup('connection:facebook');

   facebook === facebook2; // => false
   ```

   @method optionsForType
   @param {String} type
   @param {Object} options
   */
  optionsForType: function(type, options) {
    this._typeOptions[type] = options;
  },

  getOptionsForType: function(type) {
    return this._typeOptions[type];
  },

  /**
   @method options
   @param {String} fullName
   @param {Object} options
   */
  options: function(fullName, options) {
    options = options || {};
    var normalizedName = this.normalize(fullName);
    this._options[normalizedName] = options;
  },

  getOptions: function(fullName) {
    var normalizedName = this.normalize(fullName);
    return this._options[normalizedName];
  },

  getOption: function(fullName, optionName) {
    var options = this._options[fullName];

    if (options && options[optionName] !== undefined) {
      return options[optionName];
    }

    var type = fullName.split(':')[0];
    options = this._typeOptions[type];

    if (options) {
      return options[optionName];
    }
  },

  option: function(fullName, optionName) {
    Ember.deprecate('`Registry.option()` has been deprecated. Call `Registry.getOption()` instead.');
    return this.getOption(fullName, optionName);
  },

  /**
   Used only via `injection`.

   Provides a specialized form of injection, specifically enabling
   all objects of one type to be injected with a reference to another
   object.

   For example, provided each object of type `controller` needed a `router`.
   one would do the following:

   ```javascript
   var registry = new Registry();
   var container = registry.container();

   registry.register('router:main', Router);
   registry.register('controller:user', UserController);
   registry.register('controller:post', PostController);

   registry.typeInjection('controller', 'router', 'router:main');

   var user = container.lookup('controller:user');
   var post = container.lookup('controller:post');

   user.router instanceof Router; //=> true
   post.router instanceof Router; //=> true

   // both controllers share the same router
   user.router === post.router; //=> true
   ```

   @private
   @method typeInjection
   @param {String} type
   @param {String} property
   @param {String} fullName
   */
  typeInjection: function(type, property, fullName) {
    Ember.assert('fullName must be a proper full name', this.validateFullName(fullName));

    var fullNameType = fullName.split(':')[0];
    if (fullNameType === type) {
      throw new Error('Cannot inject a `' + fullName +
      '` on other ' + type +
      '(s). Register the `' + fullName +
      '` as a different type and perform the typeInjection.');
    }

    addTypeInjection(this.typeInjections, type, property, fullName);
  },

  /**
   Defines injection rules.

   These rules are used to inject dependencies onto objects when they
   are instantiated.

   Two forms of injections are possible:

   * Injecting one fullName on another fullName
   * Injecting one fullName on a type

   Example:

   ```javascript
   var registry = new Registry();
   var container = registry.container();

   registry.register('source:main', Source);
   registry.register('model:user', User);
   registry.register('model:post', Post);

   // injecting one fullName on another fullName
   // eg. each user model gets a post model
   registry.injection('model:user', 'post', 'model:post');

   // injecting one fullName on another type
   registry.injection('model', 'source', 'source:main');

   var user = container.lookup('model:user');
   var post = container.lookup('model:post');

   user.source instanceof Source; //=> true
   post.source instanceof Source; //=> true

   user.post instanceof Post; //=> true

   // and both models share the same source
   user.source === post.source; //=> true
   ```

   @method injection
   @param {String} factoryName
   @param {String} property
   @param {String} injectionName
   */
  injection: function(fullName, property, injectionName) {
    this.validateFullName(injectionName);
    var normalizedInjectionName = this.normalize(injectionName);

    if (fullName.indexOf(':') === -1) {
      return this.typeInjection(fullName, property, normalizedInjectionName);
    }

    Ember.assert('fullName must be a proper full name', this.validateFullName(fullName));
    var normalizedName = this.normalize(fullName);

    addInjection(initRules(this.injections, normalizedName), property, normalizedInjectionName);
  },

  /**
   Used only via `factoryInjection`.

   Provides a specialized form of injection, specifically enabling
   all factory of one type to be injected with a reference to another
   object.

   For example, provided each factory of type `model` needed a `store`.
   one would do the following:

   ```javascript
   var registry = new Registry();

   registry.register('store:main', SomeStore);

   registry.factoryTypeInjection('model', 'store', 'store:main');

   var store = registry.lookup('store:main');
   var UserFactory = registry.lookupFactory('model:user');

   UserFactory.store instanceof SomeStore; //=> true
   ```

   @private
   @method factoryTypeInjection
   @param {String} type
   @param {String} property
   @param {String} fullName
   */
  factoryTypeInjection: function(type, property, fullName) {
    addTypeInjection(this.factoryTypeInjections, type, property, this.normalize(fullName));
  },

  /**
   Defines factory injection rules.

   Similar to regular injection rules, but are run against factories, via
   `Registry#lookupFactory`.

   These rules are used to inject objects onto factories when they
   are looked up.

   Two forms of injections are possible:

   * Injecting one fullName on another fullName
   * Injecting one fullName on a type

   Example:

   ```javascript
   var registry = new Registry();
   var container = registry.container();

   registry.register('store:main', Store);
   registry.register('store:secondary', OtherStore);
   registry.register('model:user', User);
   registry.register('model:post', Post);

   // injecting one fullName on another type
   registry.factoryInjection('model', 'store', 'store:main');

   // injecting one fullName on another fullName
   registry.factoryInjection('model:post', 'secondaryStore', 'store:secondary');

   var UserFactory = container.lookupFactory('model:user');
   var PostFactory = container.lookupFactory('model:post');
   var store = container.lookup('store:main');

   UserFactory.store instanceof Store; //=> true
   UserFactory.secondaryStore instanceof OtherStore; //=> false

   PostFactory.store instanceof Store; //=> true
   PostFactory.secondaryStore instanceof OtherStore; //=> true

   // and both models share the same source instance
   UserFactory.store === PostFactory.store; //=> true
   ```

   @method factoryInjection
   @param {String} factoryName
   @param {String} property
   @param {String} injectionName
   */
  factoryInjection: function(fullName, property, injectionName) {
    var normalizedName = this.normalize(fullName);
    var normalizedInjectionName = this.normalize(injectionName);

    this.validateFullName(injectionName);

    if (fullName.indexOf(':') === -1) {
      return this.factoryTypeInjection(normalizedName, property, normalizedInjectionName);
    }

    addInjection(initRules(this.factoryInjections, normalizedName), property, normalizedInjectionName);
  },

  validateFullName: function(fullName) {
    if (!VALID_FULL_NAME_REGEXP.test(fullName)) {
      throw new TypeError('Invalid Fullname, expected: `type:name` got: ' + fullName);
    }
    return true;
  },

  validateInjections: function(injections) {
    if (!injections) { return; }

    var fullName;

    for (var i = 0, length = injections.length; i < length; i++) {
      fullName = injections[i].fullName;

      if (!this.has(fullName)) {
        throw new Error('Attempting to inject an unknown injection: `' + fullName + '`');
      }
    }
  },

  normalizeInjectionsHash: function(hash) {
    var injections = [];

    for (var key in hash) {
      if (hash.hasOwnProperty(key)) {
        Ember.assert("Expected a proper full name, given '" + hash[key] + "'", this.validateFullName(hash[key]));

        addInjection(injections, key, hash[key]);
      }
    }

    return injections;
  }
};

function resolve(registry, normalizedName) {
  var cached = registry._resolveCache[normalizedName];
  if (cached) { return cached; }

  var resolved = registry.resolver(normalizedName) || registry.registrations[normalizedName];
  registry._resolveCache[normalizedName] = resolved;

  return resolved;
}

function has(registry, fullName){
  return registry.resolve(fullName) !== undefined;
}

function addInjection(injections, property, injectionName) {
  injections.push({
    property: property,
    fullName: injectionName
  });
}

function addTypeInjection(rules, type, property, fullName) {
  var injections = rules[type];

  if (!injections) {
    injections = [];
    rules[type] = injections;
  }

  injections.push({
    property: property,
    fullName: fullName
  });
}

function initRules(rules, factoryName) {
  return rules[factoryName] || (rules[factoryName] = []);
}

export default Registry;
<commit_msg>Replace some helper methods with inline implementations.<commit_after>import Ember from 'ember-metal/core'; // Ember.assert
import dictionary from 'ember-metal/dictionary';
import Container from 'container/container';

var VALID_FULL_NAME_REGEXP = /^[^:]+.+:[^:]+$/;

/**
 A lightweight registry used to store factory and option information keyed
 by type.

 A `Registry` stores the factory and option information needed by a
 `Container` to instantiate and cache objects.

 The public API for `Registry` is still in flux and should not be considered
 stable.

 @private
 @class Registry
*/
function Registry(options) {
  options = options || {};

  this.resolver = options.resolver || function() {};

  this.registrations  = dictionary(options.registrations || null);
  this.typeInjections = dictionary(options.typeInjections || null);
  this.injections     = dictionary(null);
  this.factoryTypeInjections = dictionary(null);
  this.factoryInjections     = dictionary(null);

  this._normalizeCache = dictionary(null);
  this._resolveCache   = dictionary(null);

  this._options     = dictionary(options.options || null);
  this._typeOptions = dictionary(options.typeOptions || null);
}

Registry.prototype = {
  /**
   @property resolver
   @type function
   */
  resolver: null,

  /**
   @property registrations
   @type InheritingDict
   */
  registrations: null,

  /**
   @property typeInjections
   @type InheritingDict
   */
  typeInjections: null,

  /**
   @property injections
   @type InheritingDict
   */
  injections: null,

  /**
   @property factoryTypeInjections
   @type InheritingDict
   */
  factoryTypeInjections: null,

  /**
   @property factoryInjections
   @type InheritingDict
   */
  factoryInjections: null,

  /**
   @private

   @property _normalizeCache
   @type InheritingDict
   */
  _normalizeCache: null,

  /**
   @private

   @property _resolveCache
   @type InheritingDict
   */
  _resolveCache: null,

  /**
   @private

   @property _options
   @type InheritingDict
   */
  _options: null,

  /**
   @private

   @property _typeOptions
   @type InheritingDict
   */
  _typeOptions: null,

  /**
   The first container created for this registry.

   This allows deprecated access to `lookup` and `lookupFactory` to avoid
   breaking compatibility for Ember 1.x initializers.

   @private
   @property _defaultContainer
   @type Container
   */
   _defaultContainer: null,

  /**
   Creates a container based on this registry.

   @method container
   @param {Object} options
   @return {Container} created container
   */
  container: function(options) {
    var container = new Container(this, options);

    // Allow deprecated access to the first child container's `lookup` and
    // `lookupFactory` methods to avoid breaking compatibility for Ember 1.x
    // initializers.
    if (!this._defaultContainer) {
      this._defaultContainer = container;
    }

    return container;
  },

  lookup: function(fullName, options) {
    Ember.assert('Create a container on the registry (with `registry.container()`) before calling `lookup`.', this._defaultContainer);
    Ember.deprecate('`lookup` should not be called on a Registry. Call `lookup` directly on an associated Container instead.');
    return this._defaultContainer.lookup(fullName, options);
  },

  lookupFactory: function(fullName) {
    Ember.assert('Create a container on the registry (with `registry.container()`) before calling `lookupFactory`.', this._defaultContainer);
    Ember.deprecate('`lookupFactory` should not be called on a Registry. Call `lookupFactory` directly on an associated Container instead.');
    return this._defaultContainer.lookupFactory(fullName);
  },

  /**
   Registers a factory for later injection.

   Example:

   ```javascript
   var registry = new Registry();

   registry.register('model:user', Person, {singleton: false });
   registry.register('fruit:favorite', Orange);
   registry.register('communication:main', Email, {singleton: false});
   ```

   @method register
   @param {String} fullName
   @param {Function} factory
   @param {Object} options
   */
  register: function(fullName, factory, options) {
    Ember.assert('fullName must be a proper full name', this.validateFullName(fullName));

    if (factory === undefined) {
      throw new TypeError('Attempting to register an unknown factory: `' + fullName + '`');
    }

    var normalizedName = this.normalize(fullName);

    if (this._resolveCache[normalizedName]) {
      throw new Error('Cannot re-register: `' + fullName +'`, as it has already been resolved.');
    }

    this.registrations[normalizedName] = factory;
    this._options[normalizedName] = (options || {});
  },

  /**
   Unregister a fullName

   ```javascript
   var registry = new Registry();
   registry.register('model:user', User);

   registry.resolve('model:user').create() instanceof User //=> true

   registry.unregister('model:user')
   registry.resolve('model:user') === undefined //=> true
   ```

   @method unregister
   @param {String} fullName
   */
  unregister: function(fullName) {
    Ember.assert('fullName must be a proper full name', this.validateFullName(fullName));

    var normalizedName = this.normalize(fullName);

    delete this.registrations[normalizedName];
    delete this._resolveCache[normalizedName];
    delete this._options[normalizedName];
  },

  /**
   Given a fullName return the corresponding factory.

   By default `resolve` will retrieve the factory from
   the registry.

   ```javascript
   var registry = new Registry();
   registry.register('api:twitter', Twitter);

   registry.resolve('api:twitter') // => Twitter
   ```

   Optionally the registry can be provided with a custom resolver.
   If provided, `resolve` will first provide the custom resolver
   the opportunity to resolve the fullName, otherwise it will fallback
   to the registry.

   ```javascript
   var registry = new Registry();
   registry.resolver = function(fullName) {
      // lookup via the module system of choice
    };

   // the twitter factory is added to the module system
   registry.resolve('api:twitter') // => Twitter
   ```

   @method resolve
   @param {String} fullName
   @return {Function} fullName's factory
   */
  resolve: function(fullName) {
    Ember.assert('fullName must be a proper full name', this.validateFullName(fullName));
    return resolve(this, this.normalize(fullName));
  },

  /**
   A hook that can be used to describe how the resolver will
   attempt to find the factory.

   For example, the default Ember `.describe` returns the full
   class name (including namespace) where Ember's resolver expects
   to find the `fullName`.

   @method describe
   @param {String} fullName
   @return {string} described fullName
   */
  describe: function(fullName) {
    return fullName;
  },

  /**
   A hook to enable custom fullName normalization behaviour

   @method normalizeFullName
   @param {String} fullName
   @return {string} normalized fullName
   */
  normalizeFullName: function(fullName) {
    return fullName;
  },

  /**
   normalize a fullName based on the applications conventions

   @method normalize
   @param {String} fullName
   @return {string} normalized fullName
   */
  normalize: function(fullName) {
    return this._normalizeCache[fullName] || (
        this._normalizeCache[fullName] = this.normalizeFullName(fullName)
      );
  },

  /**
   @method makeToString

   @param {any} factory
   @param {string} fullName
   @return {function} toString function
   */
  makeToString: function(factory, fullName) {
    return factory.toString();
  },

  /**
   Given a fullName check if the container is aware of its factory
   or singleton instance.

   @method has
   @param {String} fullName
   @return {Boolean}
   */
  has: function(fullName) {
    Ember.assert('fullName must be a proper full name', this.validateFullName(fullName));
    return has(this, this.normalize(fullName));
  },

  /**
   Allow registering options for all factories of a type.

   ```javascript
   var registry = new Registry();
   var container = registry.container();

   // if all of type `connection` must not be singletons
   registry.optionsForType('connection', { singleton: false });

   registry.register('connection:twitter', TwitterConnection);
   registry.register('connection:facebook', FacebookConnection);

   var twitter = container.lookup('connection:twitter');
   var twitter2 = container.lookup('connection:twitter');

   twitter === twitter2; // => false

   var facebook = container.lookup('connection:facebook');
   var facebook2 = container.lookup('connection:facebook');

   facebook === facebook2; // => false
   ```

   @method optionsForType
   @param {String} type
   @param {Object} options
   */
  optionsForType: function(type, options) {
    this._typeOptions[type] = options;
  },

  getOptionsForType: function(type) {
    return this._typeOptions[type];
  },

  /**
   @method options
   @param {String} fullName
   @param {Object} options
   */
  options: function(fullName, options) {
    options = options || {};
    var normalizedName = this.normalize(fullName);
    this._options[normalizedName] = options;
  },

  getOptions: function(fullName) {
    var normalizedName = this.normalize(fullName);
    return this._options[normalizedName];
  },

  getOption: function(fullName, optionName) {
    var options = this._options[fullName];

    if (options && options[optionName] !== undefined) {
      return options[optionName];
    }

    var type = fullName.split(':')[0];
    options = this._typeOptions[type];

    if (options) {
      return options[optionName];
    }
  },

  option: function(fullName, optionName) {
    Ember.deprecate('`Registry.option()` has been deprecated. Call `Registry.getOption()` instead.');
    return this.getOption(fullName, optionName);
  },

  /**
   Used only via `injection`.

   Provides a specialized form of injection, specifically enabling
   all objects of one type to be injected with a reference to another
   object.

   For example, provided each object of type `controller` needed a `router`.
   one would do the following:

   ```javascript
   var registry = new Registry();
   var container = registry.container();

   registry.register('router:main', Router);
   registry.register('controller:user', UserController);
   registry.register('controller:post', PostController);

   registry.typeInjection('controller', 'router', 'router:main');

   var user = container.lookup('controller:user');
   var post = container.lookup('controller:post');

   user.router instanceof Router; //=> true
   post.router instanceof Router; //=> true

   // both controllers share the same router
   user.router === post.router; //=> true
   ```

   @private
   @method typeInjection
   @param {String} type
   @param {String} property
   @param {String} fullName
   */
  typeInjection: function(type, property, fullName) {
    Ember.assert('fullName must be a proper full name', this.validateFullName(fullName));

    var fullNameType = fullName.split(':')[0];
    if (fullNameType === type) {
      throw new Error('Cannot inject a `' + fullName +
      '` on other ' + type +
      '(s). Register the `' + fullName +
      '` as a different type and perform the typeInjection.');
    }

    var injections = this.typeInjections[type] ||
                     (this.typeInjections[type] = []);

    injections.push({
      property: property,
      fullName: fullName
    });
  },

  /**
   Defines injection rules.

   These rules are used to inject dependencies onto objects when they
   are instantiated.

   Two forms of injections are possible:

   * Injecting one fullName on another fullName
   * Injecting one fullName on a type

   Example:

   ```javascript
   var registry = new Registry();
   var container = registry.container();

   registry.register('source:main', Source);
   registry.register('model:user', User);
   registry.register('model:post', Post);

   // injecting one fullName on another fullName
   // eg. each user model gets a post model
   registry.injection('model:user', 'post', 'model:post');

   // injecting one fullName on another type
   registry.injection('model', 'source', 'source:main');

   var user = container.lookup('model:user');
   var post = container.lookup('model:post');

   user.source instanceof Source; //=> true
   post.source instanceof Source; //=> true

   user.post instanceof Post; //=> true

   // and both models share the same source
   user.source === post.source; //=> true
   ```

   @method injection
   @param {String} factoryName
   @param {String} property
   @param {String} injectionName
   */
  injection: function(fullName, property, injectionName) {
    this.validateFullName(injectionName);
    var normalizedInjectionName = this.normalize(injectionName);

    if (fullName.indexOf(':') === -1) {
      return this.typeInjection(fullName, property, normalizedInjectionName);
    }

    Ember.assert('fullName must be a proper full name', this.validateFullName(fullName));
    var normalizedName = this.normalize(fullName);

    var injections = this.injections[normalizedName] ||
                     (this.injections[normalizedName] = []);

    injections.push({
      property: property,
      fullName: normalizedInjectionName
    });
  },

  /**
   Used only via `factoryInjection`.

   Provides a specialized form of injection, specifically enabling
   all factory of one type to be injected with a reference to another
   object.

   For example, provided each factory of type `model` needed a `store`.
   one would do the following:

   ```javascript
   var registry = new Registry();

   registry.register('store:main', SomeStore);

   registry.factoryTypeInjection('model', 'store', 'store:main');

   var store = registry.lookup('store:main');
   var UserFactory = registry.lookupFactory('model:user');

   UserFactory.store instanceof SomeStore; //=> true
   ```

   @private
   @method factoryTypeInjection
   @param {String} type
   @param {String} property
   @param {String} fullName
   */
  factoryTypeInjection: function(type, property, fullName) {
    var injections = this.factoryTypeInjections[type] ||
                     (this.factoryTypeInjections[type] = []);

    injections.push({
      property: property,
      fullName: this.normalize(fullName)
    });
  },

  /**
   Defines factory injection rules.

   Similar to regular injection rules, but are run against factories, via
   `Registry#lookupFactory`.

   These rules are used to inject objects onto factories when they
   are looked up.

   Two forms of injections are possible:

   * Injecting one fullName on another fullName
   * Injecting one fullName on a type

   Example:

   ```javascript
   var registry = new Registry();
   var container = registry.container();

   registry.register('store:main', Store);
   registry.register('store:secondary', OtherStore);
   registry.register('model:user', User);
   registry.register('model:post', Post);

   // injecting one fullName on another type
   registry.factoryInjection('model', 'store', 'store:main');

   // injecting one fullName on another fullName
   registry.factoryInjection('model:post', 'secondaryStore', 'store:secondary');

   var UserFactory = container.lookupFactory('model:user');
   var PostFactory = container.lookupFactory('model:post');
   var store = container.lookup('store:main');

   UserFactory.store instanceof Store; //=> true
   UserFactory.secondaryStore instanceof OtherStore; //=> false

   PostFactory.store instanceof Store; //=> true
   PostFactory.secondaryStore instanceof OtherStore; //=> true

   // and both models share the same source instance
   UserFactory.store === PostFactory.store; //=> true
   ```

   @method factoryInjection
   @param {String} factoryName
   @param {String} property
   @param {String} injectionName
   */
  factoryInjection: function(fullName, property, injectionName) {
    var normalizedName = this.normalize(fullName);
    var normalizedInjectionName = this.normalize(injectionName);

    this.validateFullName(injectionName);

    if (fullName.indexOf(':') === -1) {
      return this.factoryTypeInjection(normalizedName, property, normalizedInjectionName);
    }

    var injections = this.factoryInjections[normalizedName] || (this.factoryInjections[normalizedName] = []);

    injections.push({
      property: property,
      fullName: normalizedInjectionName
    });
  },

  validateFullName: function(fullName) {
    if (!VALID_FULL_NAME_REGEXP.test(fullName)) {
      throw new TypeError('Invalid Fullname, expected: `type:name` got: ' + fullName);
    }
    return true;
  },

  validateInjections: function(injections) {
    if (!injections) { return; }

    var fullName;

    for (var i = 0, length = injections.length; i < length; i++) {
      fullName = injections[i].fullName;

      if (!this.has(fullName)) {
        throw new Error('Attempting to inject an unknown injection: `' + fullName + '`');
      }
    }
  },

  normalizeInjectionsHash: function(hash) {
    var injections = [];

    for (var key in hash) {
      if (hash.hasOwnProperty(key)) {
        Ember.assert("Expected a proper full name, given '" + hash[key] + "'", this.validateFullName(hash[key]));

        injections.push({
          property: key,
          fullName: hash[key]
        });
      }
    }

    return injections;
  }
};

function resolve(registry, normalizedName) {
  var cached = registry._resolveCache[normalizedName];
  if (cached) { return cached; }

  var resolved = registry.resolver(normalizedName) || registry.registrations[normalizedName];
  registry._resolveCache[normalizedName] = resolved;

  return resolved;
}

function has(registry, fullName){
  return registry.resolve(fullName) !== undefined;
}

export default Registry;
<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

// -- Fields ---
// title
//created  date
//code-googleDrive

/**
 * Doc Schema
 */
 var DocSchema = new Schema({
 	created: {
 		type: Date,
 		default: Date.now
  	},
  	title: {
  		type: String,
  		default: '',
  		trim: true
  	},
  	code:{
  		type: String,
  		default: '',
  		trim: true
  	},
  	user: {
  		type: Schema.ObjectId,
  		ref: 'User'
  	}

 });

 /**
 *Validations
 */
 DocSchema.path('title').validate(function (title) {
 	return title.length;
 }, 'Este campo es obligatorio');
  DocSchema.path('code').validate(function (code) {
 	return code.length;
 }, 'Este campo es obligatorio');

 /**
 * Statics
*/
DocSchema.statics.load = function (id, cb) {
	this.findOne({
		_id: id
	}).populate('user', 'name username').exec(cb);
};
mongoose.model('Doc', DocSchema);<commit_msg>Agregated student and area fields in docs model<commit_after>'use strict';

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

// -- Fields ---
// title
//created  date
//code-googleDrive

/**
 * Doc Schema
 */
 var DocSchema = new Schema({
 	created: {
 		type: Date,
 		default: Date.now
  	},
  	title: {
  		type: String,
  		default: '',
  		trim: true
  	},
  	code:{
  		type: String,
  		default: '',
  		trim: true
  	},
    area:{
      type: String,
      default: '',
      trim: true
    },
    student: {
      type: Schema.ObjectId,
      ref: 'Student'
    },
  	user: {
  		type: Schema.ObjectId,
  		ref: 'User'
  	}

 });

 /**
 *Validations
 */
 DocSchema.path('title').validate(function (title) {
 	return title.length;
 }, 'Este campo es obligatorio');
  DocSchema.path('code').validate(function (code) {
 	return code.length;
 }, 'Este campo es obligatorio');

 /**
 * Statics
*/
DocSchema.statics.load = function (id, cb) {
	this.findOne({
		_id: id
	}).populate('user', 'name username').exec(cb);
};
mongoose.model('Doc', DocSchema);<|endoftext|>


<commit_before>import React, { Children, cloneElement } from 'react';
import PropTypes from 'prop-types';
import { createComponent } from 'react-fela';

const Layout = createComponent(
  ({ fullHeight, affix }) => ({
    display: 'flex',
    alignItems: 'stretch',
    height: fullHeight || affix ? '100vh' : '100%',
    minHeight: '100%',
    maxHeight: affix && '100vh',
    flexDirection: 'column',
  }),
  ({ children, affix, ...rest }) =>
    (<div {...rest}>
      {Children.map(children, child => cloneElement(child, { affix }))}
    </div>),
  ({ fullHeight, ...p }) => Object.keys(p)
);
Layout.displayName = 'Layout';
Layout.propTypes = {
  fullHeight: PropTypes.bool,
  affix: PropTypes.bool,
};
Layout.defaultProps = {
  fullHeight: false,
  affix: false,
};

export default Layout;
<commit_msg>fix layout<commit_after>import React, { Children, cloneElement } from 'react';
import PropTypes from 'prop-types';
import { createComponent } from 'react-fela';

const Layout = createComponent(
  ({ fullHeight, affix }) => ({
    display: 'flex',
    alignItems: 'stretch',
    height: fullHeight || affix ? '100vh' : '100%',
    minHeight: '100%',
    maxHeight: affix && '100vh',
    flexDirection: 'column',
  }),
  ({ children, affix, ...rest }) =>
    (<div {...rest}>
      {Children.map(children, child => child && cloneElement(child, { affix }))}
    </div>),
  ({ fullHeight, ...p }) => Object.keys(p)
);
Layout.displayName = 'Layout';
Layout.propTypes = {
  fullHeight: PropTypes.bool,
  affix: PropTypes.bool,
};
Layout.defaultProps = {
  fullHeight: false,
  affix: false,
};

export default Layout;
<|endoftext|>


<commit_before><commit_msg>remove doctype fix<commit_after><|endoftext|>


<commit_before>import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import redux from 'redux';
import {Provider} from 'react-redux';
import configStore from './store/configStore';
import App from './components/App';
import Home from './components/Home';

const store = configStore();

ReactDOM.render(
  <Provider store={store}>
    <App/>
  </Provider>,
  document.getElementById('app'));
<commit_msg>feat: edit file paths<commit_after>import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import redux from 'redux';
import {Provider} from 'react-redux';
import configStore from './store/configStore';
import App from './components/app';
import Home from './components/home';

const store = configStore();

ReactDOM.render(
  <Provider store={store}>
    <App/>
  </Provider>,
  document.getElementById('app'));
<|endoftext|>


<commit_before>chai.config.showDiff = true;
var assert = chai.assert;
var Fusion = require("Fusion");

describe("Fusion Client Library", function() {

//Doesn't actually do anything for now, need `isConnected` callback
describe("Make a connection to the database", function() {
  it("new Fusion(...)", function(done) {
    var fusion = new Fusion("localhost:8181", {secure: false});
    assert.notEqual(fusion, undefined);
    fusion.toPromise('connected').then(function(){done()}, done)
  });
});

describe("Collections methods", function(done) {

  var testDoc = {
    id: "test",
    obj: {},
    array: [],
    string: "",
    int: 42,
    float: 42.0
  };

  var fusion = new Fusion("localhost:8181", {secure: false});
  var tests = fusion("tests");

  it("#.store(...)", function(done) {
    tests.store(testDoc)
      .then(function(result) {
        assert.deepEqual(result, testDoc);
        done();
      })
      .catch(function(err) {
        done(err);
      });
  });

  it("#.findOne(...)", function(done) {
    tests.findOne(testDoc.id)
      .value()
      .then(function(result) {
        assert.deepEqual(result, testDoc);
        done();
      })
      .catch(function(err) {
        done(err);
      });
>>>>>>> 377faf8b022613ef0ce3d2cad5dc9d86fe892687
  });

  describe("Collections", function(done) {

    var testDoc = {
      id: "test",
      obj: {},
      array: [],
      string: "",
      int: 42,
      float: 42.0
    };

    var fusion = new Fusion("localhost:8181", false);
    var tests = fusion("tests");

    it("#.store(...)", function(done) {
      tests.store(testDoc)
        .then(function(result) {
          assert.deepEqual(result.new_val, testDoc);
          done();
        })
        .catch(function(err) {
          done(err);
        });
    });

    it("#.findOne(...)", function(done) {
      tests.findOne(testDoc.id)
        .value()
        .then(function(result) {
          assert.deepEqual(result, testDoc);
          done();
        })
        .catch(function(err) {
          done(err);
        });
    });

    it("#.find(...)", function(done) {
      tests.find("id", "test")
        .value()
        .then(function(result) {
          assert.deepEqual(result[0], testDoc);
          done();
        })
        .catch(function(err) {
          done(err);
        })
    });

    it("#.update(...)", function() {
      var testUpdateDoc = {
        id: "test",
        obj: {},
        array: [],
        string: "",
        int: 43,
        float: 43.0
      };
      tests.update(testUpdateDoc)
        .catch(function(err) {
          done(err);
        });
      tests.findOne(testUpdateDoc.id)
        .value()
        .then(function(result) {
          assert.deepEqual(result, testUpdateDoc);
        })
        .catch(function(err) {
          done(err);
        })
    });

    it("#.update(...)", function() {
      var testUpdateDoc = {
        id: "test",
        obj: {},
        array: [],
        string: "",
        int: 43,
        float: 43.0
      };
      tests.update(testUpdateDoc)
        .then(function(result) {
          return tests.findOne(testUpdateDoc.id).value();
        })
        .then(function(result) {
          assert.deepEqual(result, testUpdateDoc);
        })
        .catch(function(err) {
          done(err);
        })
    });

  });
});
<commit_msg>Fixing auto merge errors<commit_after>chai.config.showDiff = true;
var assert = chai.assert;
var Fusion = require("Fusion");

describe("Fusion Client Library", function() {

  //Doesn't actually do anything for now, need `isConnected` callback
  describe("Make a connection to the database", function() {
    it("new Fusion(...)", function(done) {
      var fusion = new Fusion("localhost:8181", {
        secure: false
      });
      assert.notEqual(fusion, undefined);
      fusion.toPromise('connected').then(function() {
        done()
      }, done)
    });
  });

  describe("Collections methods", function(done) {

    var testDoc = {
      id: "test",
      obj: {},
      array: [],
      string: "",
      int: 42,
      float: 42.0
    };

    var fusion = new Fusion("localhost:8181", {
      secure: false
    });
    var tests = fusion("tests");

    it("#.store(...)", function(done) {
      tests.store(testDoc)
        .then(function(result) {
          assert.deepEqual(result, testDoc);
          done();
        })
        .catch(function(err) {
          done(err);
        });
    });

    it("#.findOne(...)", function(done) {
      tests.findOne(testDoc.id)
        .value()
        .then(function(result) {
          assert.deepEqual(result, testDoc);
          done();
        })
        .catch(function(err) {
          done(err);
        });
    });

    describe("Collections", function(done) {

      var testDoc = {
        id: "test",
        obj: {},
        array: [],
        string: "",
        int: 42,
        float: 42.0
      };

      var fusion = new Fusion("localhost:8181", false);
      var tests = fusion("tests");

      it("#.store(...)", function(done) {
        tests.store(testDoc)
          .then(function(result) {
            assert.deepEqual(result.new_val, testDoc);
            done();
          })
          .catch(function(err) {
            done(err);
          });
      });

      it("#.findOne(...)", function(done) {
        tests.findOne(testDoc.id)
          .value()
          .then(function(result) {
            assert.deepEqual(result, testDoc);
            done();
          })
          .catch(function(err) {
            done(err);
          });
      });

      it("#.find(...)", function(done) {
        tests.find("id", "test")
          .value()
          .then(function(result) {
            assert.deepEqual(result[0], testDoc);
            done();
          })
          .catch(function(err) {
            done(err);
          })
      });

      it("#.update(...)", function() {
        var testUpdateDoc = {
          id: "test",
          obj: {},
          array: [],
          string: "",
          int: 43,
          float: 43.0
        };
        tests.update(testUpdateDoc)
          .catch(function(err) {
            done(err);
          });
        tests.findOne(testUpdateDoc.id)
          .value()
          .then(function(result) {
            assert.deepEqual(result, testUpdateDoc);
          })
          .catch(function(err) {
            done(err);
          })
      });

      it("#.update(...)", function() {
        var testUpdateDoc = {
          id: "test",
          obj: {},
          array: [],
          string: "",
          int: 43,
          float: 43.0
        };
        tests.update(testUpdateDoc)
          .then(function(result) {
            return tests.findOne(testUpdateDoc.id).value();
          })
          .then(function(result) {
            assert.deepEqual(result, testUpdateDoc);
          })
          .catch(function(err) {
            done(err);
          })
      });

    });
  });
});
<|endoftext|>


<commit_before>import $ from 'jquery';

const api = {
  login(username, password) {
    const user = { username, password };
    return $.post('http://localhost:8080/login', user)
      .fail(() => {
        if (!$('#errorMsg').length) {
          return $('#accountLogin').append('
Incorrect username or password
');
        }
        return null;
      });
  },
  signup(username, password) {
    const user = { username, password };
    return $.post('http://localhost:8080/signup', user)
      .fail(() => {
        if (!$('#errorMsg').length) {
          return $('#createAccount').append('
User already exists
');
        }
        return null;
      });
  },
  changePassword(username, password, newPassword) {
    const user = { username, password, newPassword };
    return $.post('http://localhost:8080/changePassword', user);
  },
  changeUsername(username, newUsername) {
    const user = { username, newUsername };
    return $.post('http://localhost:8080/changeUsername', user);
  },
  checkJWT(JWT, callback) {
    const url = 'http://localhost:8080/checkJWT/' + JWT;
    return $.get(url, user, 'json')
      .done((data) => callback(data._bodyInit))
      .fail((err) => err);
  },
  getDefs(word, callback) {
    const url = 'http://localhost:8080/dictionary/' + word;

    return $.get(url, 'json')
      .done((data) => {
        return callback(null, data);
      })
      .fail((err) => {
        return callback(err);
      });
  },
  getSyns(word, callback) {
    const url = 'http://localhost:8080/thesaurus/' + word;

    return $.get(url, 'json')
      .done((data) => {
        return callback(null, data);
      })
      .fail((err) => {
        return callback(err);
      });
  },
};

module.exports = api;
<commit_msg>Fix linting erros<commit_after>import $ from 'jquery';

const api = {
  login(username, password) {
    const user = { username, password };
    return $.post('http://localhost:8080/login', user)
      .fail(() => {
        if (!$('#errorMsg').length) {
          return $('#accountLogin').append('
Incorrect username or password
');
        }
        return null;
      });
  },
  signup(username, password) {
    const user = { username, password };
    return $.post('http://localhost:8080/signup', user)
      .fail(() => {
        if (!$('#errorMsg').length) {
          return $('#createAccount').append('
User already exists
');
        }
        return null;
      });
  },
  changePassword(username, password, newPassword) {
    const user = { username, password, newPassword };
    return $.post('http://localhost:8080/changePassword', user);
  },
  changeUsername(username, newUsername) {
    const user = { username, newUsername };
    return $.post('http://localhost:8080/changeUsername', user);
  },
  getDefs(word, callback) {
    const url = `http://localhost:8080/dictionary/${word}`;

    return $.get(url, 'json')
      .done((data) =>
        callback(null, data)
      )
      .fail((err) =>
        callback(err)
      );
  },
  getSyns(word, callback) {
    const url = `http://localhost:8080/thesaurus/${word}`;

    return $.get(url, 'json')
      .done((data) =>
        callback(null, data)
      )
      .fail((err) =>
        callback(err)
      );
  },
};

module.exports = api;
<|endoftext|>


<commit_before><commit_msg>new way to create blob<commit_after><|endoftext|>


<commit_before>/* global Package Meteor Mongo LocalCollection CollectionHooks _ EJSON */
/* eslint-disable no-proto, no-native-reassign, no-global-assign */

// Relevant AOP terminology:
// Aspect: User code that runs before/after (hook)
// Advice: Wrapper code that knows when to call user code (aspects)
// Pointcut: before/after

var advices = {}
var Tracker = (Package.tracker && Package.tracker.Tracker) || Package.deps.Deps
var publishUserId = Meteor.isServer && new Meteor.EnvironmentVariable()

CollectionHooks = {
  defaults: {
    before: { insert: {}, update: {}, remove: {}, upsert: {}, find: {}, findOne: {}, all: {} },
    after: { insert: {}, update: {}, remove: {}, find: {}, findOne: {}, all: {} },
    all: { insert: {}, update: {}, remove: {}, find: {}, findOne: {}, all: {} }
  },
  directEnv: new Meteor.EnvironmentVariable(),
  directOp: function directOp(func) {
    return this.directEnv.withValue(true, func)
  },
  hookedOp: function hookedOp(func) {
    return this.directEnv.withValue(false, func)
  }
}

CollectionHooks.getUserId = function getUserId() {
  var userId

  if (Meteor.isClient) {
    Tracker.nonreactive(function () {
      userId = Meteor.userId && Meteor.userId()
    })
  }

  if (Meteor.isServer) {
    try {
      // Will throw an error unless within method call.
      // Attempt to recover gracefully by catching:
      userId = Meteor.userId && Meteor.userId()
    } catch (e) { }

    if (userId == null) {
      // Get the userId if we are in a publish function.
      userId = publishUserId.get()
    }
  }

  if (userId == null) {
    userId = CollectionHooks.defaultUserId
  }

  return userId
}

CollectionHooks.extendCollectionInstance = function extendCollectionInstance(self, constructor) {
  // Offer a public API to allow the user to define aspects
  // Example: collection.before.insert(func);
  _.each(['before', 'after'], function (pointcut) {
    _.each(advices, function (advice, method) {
      if (advice === 'upsert' && pointcut === 'after') return

      Meteor._ensure(self, pointcut, method)
      Meteor._ensure(self, '_hookAspects', method)

      self._hookAspects[method][pointcut] = []
      self[pointcut][method] = function (aspect, options) {
        var len = self._hookAspects[method][pointcut].push({
          aspect: aspect,
          options: CollectionHooks.initOptions(options, pointcut, method)
        })

        return {
          replace: function (aspect, options) {
            self._hookAspects[method][pointcut].splice(len - 1, 1, {
              aspect: aspect,
              options: CollectionHooks.initOptions(options, pointcut, method)
            })
          },
          remove: function () {
            self._hookAspects[method][pointcut].splice(len - 1, 1)
          }
        }
      }
    })
  })

  // Offer a publicly accessible object to allow the user to define
  // collection-wide hook options.
  // Example: collection.hookOptions.after.update = {fetchPrevious: false};
  self.hookOptions = EJSON.clone(CollectionHooks.defaults)

  // Wrap mutator methods, letting the defined advice do the work
  _.each(advices, function (advice, method) {
    var collection = Meteor.isClient || method === 'upsert' ? self : self._collection

    // Store a reference to the original mutator method
    var _super = collection[method]

    Meteor._ensure(self, 'direct', method)
    self.direct[method] = function () {
      var args = arguments
      return CollectionHooks.directOp(function () {
        return constructor.prototype[method].apply(self, args)
      })
    }

    collection[method] = function () {
      if (CollectionHooks.directEnv.get() === true) {
        return _super.apply(collection, arguments)
      }

      // NOTE: should we decide to force `update` with `{upsert:true}` to use
      // the `upsert` hooks, this is what will accomplish it. It's important to
      // realize that Meteor won't distinguish between an `update` and an
      // `insert` though, so we'll end up with `after.update` getting called
      // even on an `insert`. That's why we've chosen to disable this for now.
      // if (method === "update" && _.isObject(arguments[2]) && arguments[2].upsert) {
      //   method = "upsert";
      //   advice = CollectionHooks.getAdvice(method);
      // }

      return advice.call(this,
        CollectionHooks.getUserId(),
        _super,
        self,
        method === 'upsert' ? {
          insert: self._hookAspects.insert || {},
          update: self._hookAspects.update || {},
          upsert: self._hookAspects.upsert || {}
        } : self._hookAspects[method] || {},
        function (doc) {
          return (
            _.isFunction(self._transform)
              ? function (d) { return self._transform(d || doc) }
              : function (d) { return d || doc }
          )
        },
        _.toArray(arguments),
        false
      )
    }
  })
}

CollectionHooks.defineAdvice = function defineAdvice(method, advice) {
  advices[method] = advice
}

CollectionHooks.getAdvice = function getAdvice(method) {
  return advices[method]
}

CollectionHooks.initOptions = function initOptions(options, pointcut, method) {
  return CollectionHooks.extendOptions(CollectionHooks.defaults, options, pointcut, method)
}

CollectionHooks.extendOptions = function extendOptions(source, options, pointcut, method) {
  options = _.extend(options || {}, source.all.all)
  options = _.extend(options, source[pointcut].all)
  options = _.extend(options, source.all[method])
  options = _.extend(options, source[pointcut][method])
  return options
}

CollectionHooks.getDocs = function getDocs(collection, selector, options) {
  var findOptions = { transform: null, reactive: false } // added reactive: false

  /*
  // No "fetch" support at this time.
  if (!this._validators.fetchAllFields) {
    findOptions.fields = {};
    _.each(this._validators.fetch, function(fieldName) {
      findOptions.fields[fieldName] = 1;
    });
  }
  */

  // Bit of a magic condition here... only "update" passes options, so this is
  // only relevant to when update calls getDocs:
  if (options) {
    // This was added because in our case, we are potentially iterating over
    // multiple docs. If multi isn't enabled, force a limit (almost like
    // findOne), as the default for update without multi enabled is to affect
    // only the first matched document:
    if (!options.multi) {
      findOptions.limit = 1
    }

    _.extend(findOptions, _.omit(options, 'multi', 'upsert'))
  }

  // Unlike validators, we iterate over multiple docs, so use
  // find instead of findOne:
  return collection.find(selector, findOptions)
}

// This function normalizes the selector (converting it to an Object)
CollectionHooks.normalizeSelector = function (selector) {
  if (typeof selector === 'string' || selector.constructor === Mongo.ObjectID) {
    return {
      _id: selector
    }
  } else {
    return selector
  }
}

// This function contains a snippet of code pulled and modified from:
// ~/.meteor/packages/mongo-livedata/collection.js
// It's contained in these utility functions to make updates easier for us in
// case this code changes.
CollectionHooks.getFields = function getFields(mutator) {
  // compute modified fields
  var fields = []
  // ====ADDED START=======================
  var operators = [
    '$addToSet',
    '$bit',
    '$currentDate',
    '$inc',
    '$max',
    '$min',
    '$pop',
    '$pull',
    '$pullAll',
    '$push',
    '$rename',
    '$set',
    '$unset'
  ]
  // ====ADDED END=========================

  _.each(mutator, function (params, op) {
    // ====ADDED START=======================
    if (_.contains(operators, op)) {
      // ====ADDED END=========================
      _.each(_.keys(params), function (field) {
        // treat dotted fields as if they are replacing their
        // top-level part
        if (field.indexOf('.') !== -1) {
          field = field.substring(0, field.indexOf('.'))
        }

        // record the field we are trying to change
        if (!_.contains(fields, field)) {
          fields.push(field)
        }
      })
      // ====ADDED START=======================
    } else {
      fields.push(op)
    }
    // ====ADDED END=========================
  })

  return fields
}

CollectionHooks.reassignPrototype = function reassignPrototype(instance, constr) {
  var hasSetPrototypeOf = typeof Object.setPrototypeOf === 'function'

  if (!constr) constr = typeof Mongo !== 'undefined' ? Mongo.Collection : Meteor.Collection

  // __proto__ is not available in < IE11
  // Note: Assigning a prototype dynamically has performance implications
  if (hasSetPrototypeOf) {
    Object.setPrototypeOf(instance, constr.prototype)
  } else if (instance.__proto__) {
    instance.__proto__ = constr.prototype
  }
}

CollectionHooks.wrapCollection = function wrapCollection(ns, as) {
  if (!as._CollectionConstructor) as._CollectionConstructor = as.Collection
  if (!as._CollectionPrototype) as._CollectionPrototype = new as.Collection(null)

  var constructor = as._CollectionConstructor
  var proto = as._CollectionPrototype

  ns.Collection = function () {
    var ret = constructor.apply(this, arguments)
    CollectionHooks.extendCollectionInstance(this, constructor)
    return ret
  }

  ns.Collection.prototype = proto
  ns.Collection.prototype.constructor = ns.Collection

  for (var prop in constructor) {
    if (constructor.hasOwnProperty(prop)) {
      ns.Collection[prop] = constructor[prop]
    }
  }
}

CollectionHooks.modify = LocalCollection._modify

if (typeof Mongo !== 'undefined') {
  CollectionHooks.wrapCollection(Meteor, Mongo)
  CollectionHooks.wrapCollection(Mongo, Mongo)
} else {
  CollectionHooks.wrapCollection(Meteor, Meteor)
}

if (Meteor.isServer) {
  var _publish = Meteor.publish
  Meteor.publish = function (name, handler, options) {
    return _publish.call(this, name, function () {
      // This function is called repeatedly in publications
      var ctx = this
      var args = arguments
      return publishUserId.withValue(ctx && ctx.userId, function () {
        return handler.apply(ctx, args)
      })
    }, options)
  }

  // Make the above available for packages with hooks that want to determine
  // whether they are running inside a publish function or not.
  CollectionHooks.isWithinPublish = function isWithinPublish() {
    return publishUserId.get() !== undefined
  }
}
<commit_msg>master: Merged fix<commit_after>/* global Package Meteor Mongo LocalCollection CollectionHooks _ EJSON */
/* eslint-disable no-proto, no-native-reassign, no-global-assign */

// Relevant AOP terminology:
// Aspect: User code that runs before/after (hook)
// Advice: Wrapper code that knows when to call user code (aspects)
// Pointcut: before/after

var advices = {}
var Tracker = (Package.tracker && Package.tracker.Tracker) || Package.deps.Deps
var publishUserId = Meteor.isServer && new Meteor.EnvironmentVariable()

CollectionHooks = {
  defaults: {
    before: { insert: {}, update: {}, remove: {}, upsert: {}, find: {}, findOne: {}, all: {} },
    after: { insert: {}, update: {}, remove: {}, find: {}, findOne: {}, all: {} },
    all: { insert: {}, update: {}, remove: {}, find: {}, findOne: {}, all: {} }
  },
  directEnv: new Meteor.EnvironmentVariable(),
  directOp: function directOp(func) {
    return this.directEnv.withValue(true, func)
  },
  hookedOp: function hookedOp(func) {
    return this.directEnv.withValue(false, func)
  }
}

CollectionHooks.getUserId = function getUserId() {
  var userId

  if (Meteor.isClient) {
    Tracker.nonreactive(function () {
      userId = Meteor.userId && Meteor.userId()
    })
  }

  if (Meteor.isServer) {
    try {
      // Will throw an error unless within method call.
      // Attempt to recover gracefully by catching:
      userId = Meteor.userId && Meteor.userId()
    } catch (e) { }

    if (userId == null) {
      // Get the userId if we are in a publish function.
      userId = publishUserId.get()
    }
  }

  if (userId == null) {
    userId = CollectionHooks.defaultUserId
  }

  return userId
}

CollectionHooks.extendCollectionInstance = function extendCollectionInstance(self, constructor) {
  // Offer a public API to allow the user to define aspects
  // Example: collection.before.insert(func);
  _.each(['before', 'after'], function (pointcut) {
    _.each(advices, function (advice, method) {
      if (advice === 'upsert' && pointcut === 'after') return

      Meteor._ensure(self, pointcut, method)
      Meteor._ensure(self, '_hookAspects', method)

      self._hookAspects[method][pointcut] = []
      self[pointcut][method] = function (aspect, options) {
        var len = self._hookAspects[method][pointcut].push({
          aspect: aspect,
          options: CollectionHooks.initOptions(options, pointcut, method)
        })

        return {
          replace: function (aspect, options) {
            self._hookAspects[method][pointcut].splice(len - 1, 1, {
              aspect: aspect,
              options: CollectionHooks.initOptions(options, pointcut, method)
            })
          },
          remove: function () {
            self._hookAspects[method][pointcut].splice(len - 1, 1)
          }
        }
      }
    })
  })

  // Offer a publicly accessible object to allow the user to define
  // collection-wide hook options.
  // Example: collection.hookOptions.after.update = {fetchPrevious: false};
  self.hookOptions = EJSON.clone(CollectionHooks.defaults)

  // Wrap mutator methods, letting the defined advice do the work
  _.each(advices, function (advice, method) {
    var collection = Meteor.isClient || method === 'upsert' ? self : self._collection

    // Store a reference to the original mutator method
    var _super = collection[method]

    Meteor._ensure(self, 'direct', method)
    self.direct[method] = function () {
      var args = arguments
      return CollectionHooks.directOp(function () {
        return constructor.prototype[method].apply(self, args)
      })
    }

    collection[method] = function () {
      if (CollectionHooks.directEnv.get() === true) {
        return _super.apply(collection, arguments)
      }

      // NOTE: should we decide to force `update` with `{upsert:true}` to use
      // the `upsert` hooks, this is what will accomplish it. It's important to
      // realize that Meteor won't distinguish between an `update` and an
      // `insert` though, so we'll end up with `after.update` getting called
      // even on an `insert`. That's why we've chosen to disable this for now.
      // if (method === "update" && _.isObject(arguments[2]) && arguments[2].upsert) {
      //   method = "upsert";
      //   advice = CollectionHooks.getAdvice(method);
      // }

      return advice.call(this,
        CollectionHooks.getUserId(),
        _super,
        self,
        method === 'upsert' ? {
          insert: self._hookAspects.insert || {},
          update: self._hookAspects.update || {},
          upsert: self._hookAspects.upsert || {}
        } : self._hookAspects[method] || {},
        function (doc) {
          return (
            _.isFunction(self._transform)
              ? function (d) { return self._transform(d || doc) }
              : function (d) { return d || doc }
          )
        },
        _.toArray(arguments),
        false
      )
    }
  })
}

CollectionHooks.defineAdvice = function defineAdvice(method, advice) {
  advices[method] = advice
}

CollectionHooks.getAdvice = function getAdvice(method) {
  return advices[method]
}

CollectionHooks.initOptions = function initOptions(options, pointcut, method) {
  return CollectionHooks.extendOptions(CollectionHooks.defaults, options, pointcut, method)
}

CollectionHooks.extendOptions = function extendOptions(source, options, pointcut, method) {
  options = _.extend(options || {}, source.all.all)
  options = _.extend(options, source[pointcut].all)
  options = _.extend(options, source.all[method])
  options = _.extend(options, source[pointcut][method])
  return options
}

CollectionHooks.getDocs = function getDocs(collection, selector, options) {
  var findOptions = { transform: null, reactive: false } // added reactive: false

  /*
  // No "fetch" support at this time.
  if (!this._validators.fetchAllFields) {
    findOptions.fields = {};
    _.each(this._validators.fetch, function(fieldName) {
      findOptions.fields[fieldName] = 1;
    });
  }
  */

  // Bit of a magic condition here... only "update" passes options, so this is
  // only relevant to when update calls getDocs:
  if (options) {
    // This was added because in our case, we are potentially iterating over
    // multiple docs. If multi isn't enabled, force a limit (almost like
    // findOne), as the default for update without multi enabled is to affect
    // only the first matched document:
    if (!options.multi) {
      findOptions.limit = 1
    }

    _.extend(findOptions, _.omit(options, 'multi', 'upsert'))
  }

  // Unlike validators, we iterate over multiple docs, so use
  // find instead of findOne:
  return collection.find(selector, findOptions)
}

// This function normalizes the selector (converting it to an Object)
CollectionHooks.normalizeSelector = function (selector) {
  if (typeof selector === 'string' || (selector && selector.constructor === Mongo.ObjectID)) {
    return {
      _id: selector
    }
  } else {
    return selector
  }
}

// This function contains a snippet of code pulled and modified from:
// ~/.meteor/packages/mongo-livedata/collection.js
// It's contained in these utility functions to make updates easier for us in
// case this code changes.
CollectionHooks.getFields = function getFields(mutator) {
  // compute modified fields
  var fields = []
  // ====ADDED START=======================
  var operators = [
    '$addToSet',
    '$bit',
    '$currentDate',
    '$inc',
    '$max',
    '$min',
    '$pop',
    '$pull',
    '$pullAll',
    '$push',
    '$rename',
    '$set',
    '$unset'
  ]
  // ====ADDED END=========================

  _.each(mutator, function (params, op) {
    // ====ADDED START=======================
    if (_.contains(operators, op)) {
      // ====ADDED END=========================
      _.each(_.keys(params), function (field) {
        // treat dotted fields as if they are replacing their
        // top-level part
        if (field.indexOf('.') !== -1) {
          field = field.substring(0, field.indexOf('.'))
        }

        // record the field we are trying to change
        if (!_.contains(fields, field)) {
          fields.push(field)
        }
      })
      // ====ADDED START=======================
    } else {
      fields.push(op)
    }
    // ====ADDED END=========================
  })

  return fields
}

CollectionHooks.reassignPrototype = function reassignPrototype(instance, constr) {
  var hasSetPrototypeOf = typeof Object.setPrototypeOf === 'function'

  if (!constr) constr = typeof Mongo !== 'undefined' ? Mongo.Collection : Meteor.Collection

  // __proto__ is not available in < IE11
  // Note: Assigning a prototype dynamically has performance implications
  if (hasSetPrototypeOf) {
    Object.setPrototypeOf(instance, constr.prototype)
  } else if (instance.__proto__) {
    instance.__proto__ = constr.prototype
  }
}

CollectionHooks.wrapCollection = function wrapCollection(ns, as) {
  if (!as._CollectionConstructor) as._CollectionConstructor = as.Collection
  if (!as._CollectionPrototype) as._CollectionPrototype = new as.Collection(null)

  var constructor = as._CollectionConstructor
  var proto = as._CollectionPrototype

  ns.Collection = function () {
    var ret = constructor.apply(this, arguments)
    CollectionHooks.extendCollectionInstance(this, constructor)
    return ret
  }

  ns.Collection.prototype = proto
  ns.Collection.prototype.constructor = ns.Collection

  for (var prop in constructor) {
    if (constructor.hasOwnProperty(prop)) {
      ns.Collection[prop] = constructor[prop]
    }
  }
}

CollectionHooks.modify = LocalCollection._modify

if (typeof Mongo !== 'undefined') {
  CollectionHooks.wrapCollection(Meteor, Mongo)
  CollectionHooks.wrapCollection(Mongo, Mongo)
} else {
  CollectionHooks.wrapCollection(Meteor, Meteor)
}

if (Meteor.isServer) {
  var _publish = Meteor.publish
  Meteor.publish = function (name, handler, options) {
    return _publish.call(this, name, function () {
      // This function is called repeatedly in publications
      var ctx = this
      var args = arguments
      return publishUserId.withValue(ctx && ctx.userId, function () {
        return handler.apply(ctx, args)
      })
    }, options)
  }

  // Make the above available for packages with hooks that want to determine
  // whether they are running inside a publish function or not.
  CollectionHooks.isWithinPublish = function isWithinPublish() {
    return publishUserId.get() !== undefined
  }
}
<|endoftext|>


<commit_before>const Discord = require("discord.js"),
      Oxyl = require("../oxyl.js");

Oxyl.registerCommand("botinfo", "default", (message, bot) => {
  return "```" +
   "\nGuilds: " + Discord.guilds.length +
   "\nChannels: " + Discord.channels.length +
   "\nUsers:" + Discord.users.length +
   "\n" +
   "\nCreator: minemidnight#1537 & TonyMaster21#8175" +
   "\nWebsite: **N/A**" +
   "\nCommands: **N/A**" +
   "\nLibrary: Discord.JS" +
   "\nUptime: **N/A**" +
   "```";
}, [], "View lots of information about Oxyl", "[]");
<commit_msg>Updated botinfo<commit_after>const Discord = require("discord.js"),
      Oxyl = require("../oxyl.js");

Oxyl.registerCommand("botinfo", "default", (message, bot) => {
  return "```" +
   "\nGuilds: " + Discord.guilds.length +
   "\nChannels: " + Discord.channels.length +
   "\nUsers:" + Discord.users.length +
   "\n" +
   "\nCreator: minemidnight#1537 & TonyMaster21#8175" +
   "\nWebsite: **N/A**" +
   "\nGithub: https://github.com/minemidnight/oxyl" +
   "\nCommands: **N/A**" +
   "\nLibrary: Discord.JS" +
   "\nUptime: **N/A**" +
   "```";
}, [], "View lots of information about Oxyl", "[]");
<|endoftext|>


<commit_before>var child = require('child_process');
var path = require('path');
var os = require('os');
var fs = require('fs');
var Heroku = require('heroku-client');
var request = require('request');
var agent = require('superagent');
var cli = require('heroku-cli-util');
var directory = require('../lib/directory');
var docker = require('../lib/docker');
var safely = require('../lib/safely');

module.exports = function(topic) {
  return {
    topic: topic,
    command: 'release',
    description: 'create and release slug to app',
    help: 'Create slug tarball from Docker image and release it to Heroku app',
    needsApp: true,
    needsAuth: true,
    run: safely(release)
  };
};

function release(context) {
  var procfile = directory.readProcfile(context.cwd);

  var heroku = context.heroku || new Heroku({ token: context.auth.password });
  var app = context.heroku ? context.app : heroku.apps(context.app);
  request = context.request || request;

  if (!procfile) throw new Error('Procfile required. Aborting');

  return app.info()
    .then(createLocalSlug)
    .then(createRemoteSlug)
    .then(uploadSlug)
    .then(releaseSlug);

  function createLocalSlug() {
    cli.log('creating local slug...');
    try {
      var slugPath = os.tmpdir();
      var imageId = docker.ensureStartImage(context.cwd);
      if (!imageId) return Promise.reject(new Error('Unable to find a start image'));

      var containerId = child.execSync(`docker run -d ${imageId} tar cfvz /tmp/slug.tgz -C / --exclude=.git ./app`, {
        encoding: 'utf8'
      }).trim();
      child.execSync(`docker wait ${containerId}`);
      child.execSync(`docker cp ${containerId}:/tmp/slug.tgz ${slugPath}`);
      child.execSync(`docker rm -f ${containerId}`);
      return Promise.resolve(path.join(slugPath, 'slug.tgz'));
    }
    catch (e) {
      return Promise.reject(e);
    }
  }

  function createRemoteSlug(slugPath) {
    cli.log('creating remote slug...');
    var slugInfo = app.slugs().create({
      process_types: procfile
    });
    return Promise.all([slugPath, slugInfo])
  }

  function uploadSlug(slug) {
    cli.log('uploading slug...');
    var slugPath = slug[0];
    var slugInfo = slug[1];
    var size = fs.statSync(slugPath).size;

    return new Promise(function(resolve, reject) {
      var outStream = request({
        method: 'PUT',
        url: slugInfo.blob.url,
        headers: {
          'content-type': '',
          'content-length': size
        }
      });

      fs.createReadStream(slugPath)
        .on('error', reject)
        .pipe(outStream)
        .on('error', reject)
        .on('response', resolve.bind(this, slugInfo.id));
    });
  }

  function releaseSlug(id) {
    cli.log('releasing slug...');
    return app.releases().create({
      slug: id
    });
  }
}
<commit_msg>add tracking header and success message to :release<commit_after>var child = require('child_process');
var path = require('path');
var os = require('os');
var fs = require('fs');
var Heroku = require('heroku-client');
var request = require('request');
var agent = require('superagent');
var cli = require('heroku-cli-util');
var directory = require('../lib/directory');
var docker = require('../lib/docker');
var safely = require('../lib/safely');

module.exports = function(topic) {
  return {
    topic: topic,
    command: 'release',
    description: 'create and release slug to app',
    help: 'Create slug tarball from Docker image and release it to Heroku app',
    needsApp: true,
    needsAuth: true,
    run: safely(release)
  };
};

function release(context) {
  var procfile = directory.readProcfile(context.cwd);

  var heroku = context.heroku || new Heroku({ token: context.auth.password });
  var app = context.heroku ? context.app : heroku.apps(context.app);
  request = context.request || request;

  if (!procfile) throw new Error('Procfile required. Aborting');

  return app.info()
    .then(createLocalSlug)
    .then(createRemoteSlug)
    .then(uploadSlug)
    .then(releaseSlug)
    .then(showMessage);

  function createLocalSlug() {
    cli.log('creating local slug...');
    try {
      var slugPath = os.tmpdir();
      var imageId = docker.ensureStartImage(context.cwd);
      if (!imageId) return Promise.reject(new Error('Unable to find a start image'));

      var containerId = child.execSync(`docker run -d ${imageId} tar cfvz /tmp/slug.tgz -C / --exclude=.git ./app`, {
        encoding: 'utf8'
      }).trim();
      child.execSync(`docker wait ${containerId}`);
      child.execSync(`docker cp ${containerId}:/tmp/slug.tgz ${slugPath}`);
      child.execSync(`docker rm -f ${containerId}`);
      return Promise.resolve(path.join(slugPath, 'slug.tgz'));
    }
    catch (e) {
      return Promise.reject(e);
    }
  }

  function createRemoteSlug(slugPath) {
    cli.log('creating remote slug...');
    var slugInfo = app.slugs().create({
      process_types: procfile
    });
    return Promise.all([slugPath, slugInfo])
  }

  function uploadSlug(slug) {
    cli.log('uploading slug...');
    var slugPath = slug[0];
    var slugInfo = slug[1];
    var size = fs.statSync(slugPath).size;

    return new Promise(function(resolve, reject) {
      var outStream = request({
        method: 'PUT',
        url: slugInfo.blob.url,
        headers: {
          'content-type': '',
          'content-length': size
        }
      });

      fs.createReadStream(slugPath)
        .on('error', reject)
        .pipe(outStream)
        .on('error', reject)
        .on('response', resolve.bind(this, slugInfo.id));
    });
  }

  function releaseSlug(id) {
    cli.log('releasing slug...');

    return heroku.request({
      method: 'POST',
      path: `${ app.path }/releases`,
      headers: {
        'Heroku-Deploy-Type': 'heroku-docker'
      },
      body: {
        slug: id
      }
    });
  }

  function showMessage(results) {
    console.log(`Successfully released ${ results.app.name }!`);
  }
}
<|endoftext|>


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

'use strict';

var EventEmitter = require('./lib/event_emitter');
var inherits = require('util').inherits;

var errors = require('./errors');

function RelayRequest(channel, inreq, buildRes) {
    var self = this;
    EventEmitter.call(self);
    self.finishEvent = self.defineEvent('finish');

    self.channel = channel;
    self.inreq = inreq;
    self.inres = null;
    self.outres = null;
    self.outreq = null;
    self.buildRes = buildRes;
}
inherits(RelayRequest, EventEmitter);

RelayRequest.prototype.createOutRequest = function createOutRequest() {
    var self = this;

    if (self.outreq) {
        self.channel.logger.warn('relay request already started', {
            // TODO: better context
            remoteAddr: self.inreq.remoteAddr,
            id: self.inreq.id
        });
        return;
    }

    var elapsed = self.channel.timers.now() - self.inreq.start;
    self.outreq = self.channel.request({
        streamed: self.inreq.streamed,
        timeout: self.inreq.ttl - elapsed,
        serviceName: self.inreq.serviceName,
        headers: self.inreq.headers,
        retryFlags: self.inreq.retryFlags
    });
    self.outreq.responseEvent.on(onResponse);
    self.outreq.errorEvent.on(onError);

    if (self.outreq.streamed) {
        // TODO: frame-at-a-time rather than re-streaming?
        self.inreq.arg1.pipe(self.outreq.arg1);
        self.inreq.arg2.pipe(self.outreq.arg2);
        self.inreq.arg3.pipe(self.outreq.arg3);
    } else {
        self.outreq.send(self.inreq.arg1, self.inreq.arg2, self.inreq.arg3);
    }

    return self.outreq;

    function onResponse(res) {
        self.onResponse(res);
    }

    function onError(err) {
        self.onError(err);
    }
};

RelayRequest.prototype.createOutResponse = function createOutResponse(options) {
    var self = this;
    if (self.outres) {
        self.channel.logger.warn('relay request already responded', {
            // TODO: better context
            remoteAddr: self.inreq.remoteAddr,
            id: self.inreq.id
        });
        return;
    }
    self.outres = self.buildRes(options);
    self.outres.finishEvent.on(emitFinish);
    return self.outres;

    function emitFinish() {
        self.finishEvent.emit(self);
    }
};

RelayRequest.prototype.onResponse = function onResponse(res) {
    var self = this;

    if (self.inres) {
        self.channel.logger.warn('relay request got more than one response callback', {
            // TODO: better context
            remoteAddr: res.remoteAddr,
            id: res.id
        });
        return;
    }
    self.inres = res;

    if (!self.createOutResponse({
        streamed: self.inres.streamed,
        code: self.inres.code
    })) return;

    if (self.outres.streamed) {
        self.outres.arg1.end();
        self.inres.arg2.pipe(self.outres.arg2);
        self.inres.arg3.pipe(self.outres.arg3);
    } else {
        self.outres.send(self.inres.arg2, self.inres.arg3);
    }
};

RelayRequest.prototype.onError = function onError(err) {
    var self = this;
    if (!self.createOutResponse()) return;
    var codeName = errors.classify(err);
    if (codeName) {
        self.outres.sendError(codeName, err.message);
    } else {
        self.outres.sendError('UnexpectedError', err.message);
        self.logError(err);
    }

    // TODO: stat in some cases, e.g. declined / peer not available
};

RelayRequest.prototype.logError = function logError(err) {
    var self = this;

    var level = 'error';
    if (err.type === 'tchannel.connection.reset' &&
        (err.code === 'EPIPE' || err.code === 'ECONNRESET')
    ) {
        level = 'info';
    }

    self.channel.logger[level]('unexpected error while forwarding', {
        error: err,
        outRemoteAddr: self.outreq.remoteAddr,
        inRemoteAddr: self.inreq.remoteAddr,
        serviceName: self.outreq.serviceName,
        outArg1: String(self.outreq.arg1)
    });
};

function RelayHandler(channel) {
    var self = this;
    self.channel = channel;
    self.reqs = {};
}

RelayHandler.prototype.type = 'tchannel.relay-handler';

RelayHandler.prototype.handleRequest = function handleRequest(req, buildRes) {
    var self = this;

    var reqKey = getReqKey(req);
    var rereq = self.reqs[reqKey];

    if (rereq) {
        self.channel.logger.error('relay request already exists for incoming request', {
            inReqId: req.id,
            priorInResId: rereq.inres && rereq.inres.id,
            priorOutResId: rereq.outres && rereq.outres.id,
            priorOutReqId: rereq.outreq && rereq.outreq.id
            // TODO more context, like outreq remote addr
        });
        buildRes().sendError('UnexpectedError', 'request id exists in relay handler');
        return;
    }
    rereq = new RelayRequest(self.channel, req, buildRes);
    self.reqs[reqKey] = rereq;
    rereq.finishEvent.on(rereqFinished);
    rereq.createOutRequest();
    function rereqFinished() {
        delete self.reqs[reqKey];
    }
};

function getReqKey(req) {
    return req.connection.guid + '~' + req.id;
}

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

'use strict';

var EventEmitter = require('./lib/event_emitter');
var inherits = require('util').inherits;

var errors = require('./errors');

function RelayRequest(channel, inreq, buildRes) {
    var self = this;
    EventEmitter.call(self);
    self.finishEvent = self.defineEvent('finish');

    self.channel = channel;
    self.inreq = inreq;
    self.inres = null;
    self.outres = null;
    self.outreq = null;
    self.buildRes = buildRes;
}
inherits(RelayRequest, EventEmitter);

RelayRequest.prototype.createOutRequest = function createOutRequest() {
    var self = this;

    if (self.outreq) {
        self.channel.logger.warn('relay request already started', {
            // TODO: better context
            remoteAddr: self.inreq.remoteAddr,
            id: self.inreq.id
        });
        return;
    }

    var elapsed = self.channel.timers.now() - self.inreq.start;
    self.outreq = self.channel.request({
        streamed: self.inreq.streamed,
        timeout: self.inreq.ttl - elapsed,
        serviceName: self.inreq.serviceName,
        headers: self.inreq.headers,
        retryFlags: self.inreq.retryFlags
    });
    self.outreq.responseEvent.on(onResponse);
    self.outreq.errorEvent.on(onError);

    if (self.outreq.streamed) {
        // TODO: frame-at-a-time rather than re-streaming?
        self.inreq.arg1.pipe(self.outreq.arg1);
        self.inreq.arg2.pipe(self.outreq.arg2);
        self.inreq.arg3.pipe(self.outreq.arg3);
    } else {
        self.outreq.send(self.inreq.arg1, self.inreq.arg2, self.inreq.arg3);
    }

    return self.outreq;

    function onResponse(res) {
        self.onResponse(res);
    }

    function onError(err) {
        self.onError(err);
    }
};

RelayRequest.prototype.createOutResponse = function createOutResponse(options) {
    var self = this;
    if (self.outres) {
        self.channel.logger.warn('relay request already responded', {
            // TODO: better context
            remoteAddr: self.inreq.remoteAddr,
            id: self.inreq.id
        });
        return;
    }
    self.outres = self.buildRes(options);
    self.outres.finishEvent.on(emitFinish);
    return self.outres;

    function emitFinish() {
        self.finishEvent.emit(self);
    }
};

RelayRequest.prototype.onResponse = function onResponse(res) {
    var self = this;

    if (self.inres) {
        self.channel.logger.warn('relay request got more than one response callback', {
            // TODO: better context
            remoteAddr: res.remoteAddr,
            id: res.id
        });
        return;
    }
    self.inres = res;

    if (!self.createOutResponse({
        streamed: self.inres.streamed,
        code: self.inres.code
    })) return;

    if (self.outres.streamed) {
        self.outres.arg1.end();
        self.inres.arg2.pipe(self.outres.arg2);
        self.inres.arg3.pipe(self.outres.arg3);
    } else {
        self.outres.send(self.inres.arg2, self.inres.arg3);
    }
};

RelayRequest.prototype.onError = function onError(err) {
    var self = this;
    if (!self.createOutResponse()) return;
    var codeName = errors.classify(err) || 'UnexpectedError';

    self.outres.sendError(codeName, err.message);
    self.logError(err, codeName);
    // TODO: stat in some cases, e.g. declined / peer not available
};

RelayRequest.prototype.logError = function logError(err, codeName) {
    var self = this;

    var level = 'error';
    if (err.isErrorFrame) {
        level = 'warn';
    }
    if (codeName === 'NetworkError') {
        level = 'warn';
    }

    var logger = self.channel.logger;
    var logOptions = {
        error: err,
        outRemoteAddr: self.outreq.remoteAddr,
        inRemoteAddr: self.inreq.remoteAddr,
        serviceName: self.outreq.serviceName,
        outArg1: String(self.outreq.arg1)
    };

    if (level === 'error') {
        logger.error('unexpected error while forwarding', logOptions);
    } else if (level === 'warn') {
        logger.warn('expected error while forwarding', logOptions);
    }
};

function RelayHandler(channel) {
    var self = this;
    self.channel = channel;
    self.reqs = {};
}

RelayHandler.prototype.type = 'tchannel.relay-handler';

RelayHandler.prototype.handleRequest = function handleRequest(req, buildRes) {
    var self = this;

    var reqKey = getReqKey(req);
    var rereq = self.reqs[reqKey];

    if (rereq) {
        self.channel.logger.error('relay request already exists for incoming request', {
            inReqId: req.id,
            priorInResId: rereq.inres && rereq.inres.id,
            priorOutResId: rereq.outres && rereq.outres.id,
            priorOutReqId: rereq.outreq && rereq.outreq.id
            // TODO more context, like outreq remote addr
        });
        buildRes().sendError('UnexpectedError', 'request id exists in relay handler');
        return;
    }
    rereq = new RelayRequest(self.channel, req, buildRes);
    self.reqs[reqKey] = rereq;
    rereq.finishEvent.on(rereqFinished);
    rereq.createOutRequest();
    function rereqFinished() {
        delete self.reqs[reqKey];
    }
};

function getReqKey(req) {
    return req.connection.guid + '~' + req.id;
}

module.exports = RelayHandler;
<|endoftext|>


<commit_before>Accidents = {};

Accidents.Severity = {
    NoInjury: 0,
    Injury: 1,
    Fatal: 2
};

Accidents.data = function () {
    return [
        {
            lat: 40.6953767,
            lon: -73.9492066,
            weather: Weather.Type.Clear,
            severity: Accidents.Severity.NoInjury
        }
    ];
};<commit_msg>Add more mock data<commit_after>Accidents = {};

Accidents.Severity = {
    NoInjury: 0,
    Injury: 1,
    Fatal: 2
};

Accidents.data = function () {
    return [
        {
            lat: 40.6953767,
            lon: -73.9492066,
            weather: Weather.Type.Clear,
            severity: Accidents.Severity.NoInjury
        },
        {
            lat: 40.7754808,
            lon: -73.9802034,
            weather: Weather.Type.Rain,
            severity: Accidents.Severity.Injury
        },
        {
            lat: 40.7006658,
            lon: -73.8960971,
            weather: Weather.Type.Snow,
            severity: Accidents.Severity.Fatal
        },
        {
            lat: 40.5621305,
            lon: -74.1334081,
            weather: Weather.Type.Snow,
            severity: Accidents.Severity.Fatal
        },
        {
            lat: 40.7442447,
            lon: -73.8295324,
            weather: Weather.Type.Snow,
            severity: Accidents.Severity.NoInjury
        },
        {
            lat: 40.6656299,
            lon: -73.7392073,
            weather: Weather.Type.Rain,
            severity: Accidents.Severity.Injury
        },
        {
            lat: 40.6488983,
            lon: -73.9696713,
            weather: Weather.Type.Clear,
            severity: Accidents.Severity.Fatal
        },
        {
            lat: 40.6666971,
            lon: -73.7671284,
            weather: Weather.Type.Clear,
            severity: Accidents.Severity.Injury
        }
    ];
};<|endoftext|>