text: (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.algoliasearchHelper = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  /**
   */
  "use strict";
  var AlgoliaSearchHelper = require( "./src/algoliasearch.helper" );
  /**
   * The algoliasearch-helper module is a function that instanciate the helper.
   * @module algoliasearch-helper
   * @param  {AlgoliaSearch} client an AlgoliaSearch client
   * @param  {string} index the index name to query
   * @param  {SearchParameters | object} options an object defining the initial config of the search. It doesn't have to be a {SearchParamaters}, just an object containing the properties you need from it.
   * @return {AlgoliaSearchHelper}
   */
  function helper( client, index, opts ) {
    return new AlgoliaSearchHelper( client, index, opts );
  }
  
  /**
   * The version currently used
   * @member module:algoliasearch-helper.version
   */
  helper.version = "2.0.0-rc4";
  
  module.exports = helper;
  
  },{"./src/algoliasearch.helper":83}],2:[function(require,module,exports){
  // Copyright Joyent, Inc. and other Node contributors.
  //
  // 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.
  
  function EventEmitter() {
    this._events = this._events || {};
    this._maxListeners = this._maxListeners || undefined;
  }
  module.exports = EventEmitter;
  
  // Backwards-compat with node 0.10.x
  EventEmitter.EventEmitter = EventEmitter;
  
  EventEmitter.prototype._events = undefined;
  EventEmitter.prototype._maxListeners = undefined;
  
  // By default EventEmitters will print a warning if more than 10 listeners are
  // added to it. This is a useful default which helps finding memory leaks.
  EventEmitter.defaultMaxListeners = 10;
  
  // Obviously not all Emitters should be limited to 10. This function allows
  // that to be increased. Set to zero for unlimited.
  EventEmitter.prototype.setMaxListeners = function(n) {
    if (!isNumber(n) || n < 0 || isNaN(n))
      throw TypeError('n must be a positive number');
    this._maxListeners = n;
    return this;
  };
  
  EventEmitter.prototype.emit = function(type) {
    var er, handler, len, args, i, listeners;
  
    if (!this._events)
      this._events = {};
  
    // If there is no 'error' event listener then throw.
    if (type === 'error') {
      if (!this._events.error ||
          (isObject(this._events.error) && !this._events.error.length)) {
        er = arguments[1];
        if (er instanceof Error) {
          throw er; // Unhandled 'error' event
        }
        throw TypeError('Uncaught, unspecified "error" event.');
      }
    }
  
    handler = this._events[type];
  
    if (isUndefined(handler))
      return false;
  
    if (isFunction(handler)) {
      switch (arguments.length) {
        // fast cases
        case 1:
          handler.call(this);
          break;
        case 2:
          handler.call(this, arguments[1]);
          break;
        case 3:
          handler.call(this, arguments[1], arguments[2]);
          break;
        // slower
        default:
          len = arguments.length;
          args = new Array(len - 1);
          for (i = 1; i < len; i++)
            args[i - 1] = arguments[i];
          handler.apply(this, args);
      }
    } else if (isObject(handler)) {
      len = arguments.length;
      args = new Array(len - 1);
      for (i = 1; i < len; i++)
        args[i - 1] = arguments[i];
  
      listeners = handler.slice();
      len = listeners.length;
      for (i = 0; i < len; i++)
        listeners[i].apply(this, args);
    }
  
    return true;
  };
  
  EventEmitter.prototype.addListener = function(type, listener) {
    var m;
  
    if (!isFunction(listener))
      throw TypeError('listener must be a function');
  
    if (!this._events)
      this._events = {};
  
    // To avoid recursion in the case that type === "newListener"! Before
    // adding it to the listeners, first emit "newListener".
    if (this._events.newListener)
      this.emit('newListener', type,
                isFunction(listener.listener) ?
                listener.listener : listener);
  
    if (!this._events[type])
      // Optimize the case of one listener. Don't need the extra array object.
      this._events[type] = listener;
    else if (isObject(this._events[type]))
      // If we've already got an array, just append.
      this._events[type].push(listener);
    else
      // Adding the second element, need to change to array.
      this._events[type] = [this._events[type], listener];
  
    // Check for listener leak
    if (isObject(this._events[type]) && !this._events[type].warned) {
      var m;
      if (!isUndefined(this._maxListeners)) {
        m = this._maxListeners;
      } else {
        m = EventEmitter.defaultMaxListeners;
      }
  
      if (m && m > 0 && this._events[type].length > m) {
        this._events[type].warned = true;
        console.error('(node) warning: possible EventEmitter memory ' +
                      'leak detected. %d listeners added. ' +
                      'Use emitter.setMaxListeners() to increase limit.',
                      this._events[type].length);
        if (typeof console.trace === 'function') {
          // not supported in IE 10
          console.trace();
        }
      }
    }
  
    return this;
  };
  
  EventEmitter.prototype.on = EventEmitter.prototype.addListener;
  
  EventEmitter.prototype.once = function(type, listener) {
    if (!isFunction(listener))
      throw TypeError('listener must be a function');
  
    var fired = false;
  
    function g() {
      this.removeListener(type, g);
  
      if (!fired) {
        fired = true;
        listener.apply(this, arguments);
      }
    }
  
    g.listener = listener;
    this.on(type, g);
  
    return this;
  };
  
  // emits a 'removeListener' event iff the listener was removed
  EventEmitter.prototype.removeListener = function(type, listener) {
    var list, position, length, i;
  
    if (!isFunction(listener))
      throw TypeError('listener must be a function');
  
    if (!this._events || !this._events[type])
      return this;
  
    list = this._events[type];
    length = list.length;
    position = -1;
  
    if (list === listener ||
        (isFunction(list.listener) && list.listener === listener)) {
      delete this._events[type];
      if (this._events.removeListener)
        this.emit('removeListener', type, listener);
  
    } else if (isObject(list)) {
      for (i = length; i-- > 0;) {
        if (list[i] === listener ||
            (list[i].listener && list[i].listener === listener)) {
          position = i;
          break;
        }
      }
  
      if (position < 0)
        return this;
  
      if (list.length === 1) {
        list.length = 0;
        delete this._events[type];
      } else {
        list.splice(position, 1);
      }
  
      if (this._events.removeListener)
        this.emit('removeListener', type, listener);
    }
  
    return this;
  };
  
  EventEmitter.prototype.removeAllListeners = function(type) {
    var key, listeners;
  
    if (!this._events)
      return this;
  
    // not listening for removeListener, no need to emit
    if (!this._events.removeListener) {
      if (arguments.length === 0)
        this._events = {};
      else if (this._events[type])
        delete this._events[type];
      return this;
    }
  
    // emit removeListener for all listeners on all events
    if (arguments.length === 0) {
      for (key in this._events) {
        if (key === 'removeListener') continue;
        this.removeAllListeners(key);
      }
      this.removeAllListeners('removeListener');
      this._events = {};
      return this;
    }
  
    listeners = this._events[type];
  
    if (isFunction(listeners)) {
      this.removeListener(type, listeners);
    } else {
      // LIFO order
      while (listeners.length)
        this.removeListener(type, listeners[listeners.length - 1]);
    }
    delete this._events[type];
  
    return this;
  };
  
  EventEmitter.prototype.listeners = function(type) {
    var ret;
    if (!this._events || !this._events[type])
      ret = [];
    else if (isFunction(this._events[type]))
      ret = [this._events[type]];
    else
      ret = this._events[type].slice();
    return ret;
  };
  
  EventEmitter.listenerCount = function(emitter, type) {
    var ret;
    if (!emitter._events || !emitter._events[type])
      ret = 0;
    else if (isFunction(emitter._events[type]))
      ret = 1;
    else
      ret = emitter._events[type].length;
    return ret;
  };
  
  function isFunction(arg) {
    return typeof arg === 'function';
  }
  
  function isNumber(arg) {
    return typeof arg === 'number';
  }
  
  function isObject(arg) {
    return typeof arg === 'object' && arg !== null;
  }
  
  function isUndefined(arg) {
    return arg === void 0;
  }
  
  },{}],3:[function(require,module,exports){
  if (typeof Object.create === 'function') {
    // implementation from standard node.js 'util' module
    module.exports = function inherits(ctor, superCtor) {
      ctor.super_ = superCtor
      ctor.prototype = Object.create(superCtor.prototype, {
        constructor: {
          value: ctor,
          enumerable: false,
          writable: true,
          configurable: true
        }
      });
    };
  } else {
    // old school shim for old browsers
    module.exports = function inherits(ctor, superCtor) {
      ctor.super_ = superCtor
      var TempCtor = function () {}
      TempCtor.prototype = superCtor.prototype
      ctor.prototype = new TempCtor()
      ctor.prototype.constructor = ctor
    }
  }
  
  },{}],4:[function(require,module,exports){
  // shim for using process in browser
  
  var process = module.exports = {};
  var queue = [];
  var draining = false;
  
  function drainQueue() {
      if (draining) {
          return;
      }
      draining = true;
      var currentQueue;
      var len = queue.length;
      while(len) {
          currentQueue = queue;
          queue = [];
          var i = -1;
          while (++i < len) {
              currentQueue[i]();
          }
          len = queue.length;
      }
      draining = false;
  }
  process.nextTick = function (fun) {
      queue.push(fun);
      if (!draining) {
          setTimeout(drainQueue, 0);
      }
  };
  
  process.title = 'browser';
  process.browser = true;
  process.env = {};
  process.argv = [];
  process.version = ''; // empty string to avoid regexp issues
  process.versions = {};
  
  function noop() {}
  
  process.on = noop;
  process.addListener = noop;
  process.once = noop;
  process.off = noop;
  process.removeListener = noop;
  process.removeAllListeners = noop;
  process.emit = noop;
  
  process.binding = function (name) {
      throw new Error('process.binding is not supported');
  };
  
  // TODO(shtylman)
  process.cwd = function () { return '/' };
  process.chdir = function (dir) {
      throw new Error('process.chdir is not supported');
  };
  process.umask = function() { return 0; };
  
  },{}],5:[function(require,module,exports){
  module.exports = function isBuffer(arg) {
    return arg && typeof arg === 'object'
      && typeof arg.copy === 'function'
      && typeof arg.fill === 'function'
      && typeof arg.readUInt8 === 'function';
  }
  },{}],6:[function(require,module,exports){
  (function (process,global){
  // Copyright Joyent, Inc. and other Node contributors.
  //
  // 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.
  
  var formatRegExp = /%[sdj%]/g;
  exports.format = function(f) {
    if (!isString(f)) {
      var objects = [];
      for (var i = 0; i < arguments.length; i++) {
        objects.push(inspect(arguments[i]));
      }
      return objects.join(' ');
    }
  
    var i = 1;
    var args = arguments;
    var len = args.length;
    var str = String(f).replace(formatRegExp, function(x) {
      if (x === '%%') return '%';
      if (i >= len) return x;
      switch (x) {
        case '%s': return String(args[i++]);
        case '%d': return Number(args[i++]);
        case '%j':
          try {
            return JSON.stringify(args[i++]);
          } catch (_) {
            return '[Circular]';
          }
        default:
          return x;
      }
    });
    for (var x = args[i]; i < len; x = args[++i]) {
      if (isNull(x) || !isObject(x)) {
        str += ' ' + x;
      } else {
        str += ' ' + inspect(x);
      }
    }
    return str;
  };
  
  
  // Mark that a method should not be used.
  // Returns a modified function which warns once by default.
  // If --no-deprecation is set, then it is a no-op.
  exports.deprecate = function(fn, msg) {
    // Allow for deprecating things in the process of starting up.
    if (isUndefined(global.process)) {
      return function() {
        return exports.deprecate(fn, msg).apply(this, arguments);
      };
    }
  
    if (process.noDeprecation === true) {
      return fn;
    }
  
    var warned = false;
    function deprecated() {
      if (!warned) {
        if (process.throwDeprecation) {
          throw new Error(msg);
        } else if (process.traceDeprecation) {
          console.trace(msg);
        } else {
          console.error(msg);
        }
        warned = true;
      }
      return fn.apply(this, arguments);
    }
  
    return deprecated;
  };
  
  
  var debugs = {};
  var debugEnviron;
  exports.debuglog = function(set) {
    if (isUndefined(debugEnviron))
      debugEnviron = process.env.NODE_DEBUG || '';
    set = set.toUpperCase();
    if (!debugs[set]) {
      if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
        var pid = process.pid;
        debugs[set] = function() {
          var msg = exports.format.apply(exports, arguments);
          console.error('%s %d: %s', set, pid, msg);
        };
      } else {
        debugs[set] = function() {};
      }
    }
    return debugs[set];
  };
  
  
  /**
   * Echos the value of a value. Trys to print the value out
   * in the best way possible given the different types.
   *
   * @param {Object} obj The object to print out.
   * @param {Object} opts Optional options object that alters the output.
   */
  /* legacy: obj, showHidden, depth, colors*/
  function inspect(obj, opts) {
    // default options
    var ctx = {
      seen: [],
      stylize: stylizeNoColor
    };
    // legacy...
    if (arguments.length >= 3) ctx.depth = arguments[2];
    if (arguments.length >= 4) ctx.colors = arguments[3];
    if (isBoolean(opts)) {
      // legacy...
      ctx.showHidden = opts;
    } else if (opts) {
      // got an "options" object
      exports._extend(ctx, opts);
    }
    // set default options
    if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
    if (isUndefined(ctx.depth)) ctx.depth = 2;
    if (isUndefined(ctx.colors)) ctx.colors = false;
    if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
    if (ctx.colors) ctx.stylize = stylizeWithColor;
    return formatValue(ctx, obj, ctx.depth);
  }
  exports.inspect = inspect;
  
  
  // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
  inspect.colors = {
    'bold' : [1, 22],
    'italic' : [3, 23],
    'underline' : [4, 24],
    'inverse' : [7, 27],
    'white' : [37, 39],
    'grey' : [90, 39],
    'black' : [30, 39],
    'blue' : [34, 39],
    'cyan' : [36, 39],
    'green' : [32, 39],
    'magenta' : [35, 39],
    'red' : [31, 39],
    'yellow' : [33, 39]
  };
  
  // Don't use 'blue' not visible on cmd.exe
  inspect.styles = {
    'special': 'cyan',
    'number': 'yellow',
    'boolean': 'yellow',
    'undefined': 'grey',
    'null': 'bold',
    'string': 'green',
    'date': 'magenta',
    // "name": intentionally not styling
    'regexp': 'red'
  };
  
  
  function stylizeWithColor(str, styleType) {
    var style = inspect.styles[styleType];
  
    if (style) {
      return '\u001b[' + inspect.colors[style][0] + 'm' + str +
             '\u001b[' + inspect.colors[style][1] + 'm';
    } else {
      return str;
    }
  }
  
  
  function stylizeNoColor(str, styleType) {
    return str;
  }
  
  
  function arrayToHash(array) {
    var hash = {};
  
    array.forEach(function(val, idx) {
      hash[val] = true;
    });
  
    return hash;
  }
  
  
  function formatValue(ctx, value, recurseTimes) {
    // Provide a hook for user-specified inspect functions.
    // Check that value is an object with an inspect function on it
    if (ctx.customInspect &&
        value &&
        isFunction(value.inspect) &&
        // Filter out the util module, it's inspect function is special
        value.inspect !== exports.inspect &&
        // Also filter out any prototype objects using the circular check.
        !(value.constructor && value.constructor.prototype === value)) {
      var ret = value.inspect(recurseTimes, ctx);
      if (!isString(ret)) {
        ret = formatValue(ctx, ret, recurseTimes);
      }
      return ret;
    }
  
    // Primitive types cannot have properties
    var primitive = formatPrimitive(ctx, value);
    if (primitive) {
      return primitive;
    }
  
    // Look up the keys of the object.
    var keys = Object.keys(value);
    var visibleKeys = arrayToHash(keys);
  
    if (ctx.showHidden) {
      keys = Object.getOwnPropertyNames(value);
    }
  
    // IE doesn't make error fields non-enumerable
    // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
    if (isError(value)
        && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
      return formatError(value);
    }
  
    // Some type of object without properties can be shortcutted.
    if (keys.length === 0) {
      if (isFunction(value)) {
        var name = value.name ? ': ' + value.name : '';
        return ctx.stylize('[Function' + name + ']', 'special');
      }
      if (isRegExp(value)) {
        return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
      }
      if (isDate(value)) {
        return ctx.stylize(Date.prototype.toString.call(value), 'date');
      }
      if (isError(value)) {
        return formatError(value);
      }
    }
  
    var base = '', array = false, braces = ['{', '}'];
  
    // Make Array say that they are Array
    if (isArray(value)) {
      array = true;
      braces = ['[', ']'];
    }
  
    // Make functions say that they are functions
    if (isFunction(value)) {
      var n = value.name ? ': ' + value.name : '';
      base = ' [Function' + n + ']';
    }
  
    // Make RegExps say that they are RegExps
    if (isRegExp(value)) {
      base = ' ' + RegExp.prototype.toString.call(value);
    }
  
    // Make dates with properties first say the date
    if (isDate(value)) {
      base = ' ' + Date.prototype.toUTCString.call(value);
    }
  
    // Make error with message first say the error
    if (isError(value)) {
      base = ' ' + formatError(value);
    }
  
    if (keys.length === 0 && (!array || value.length == 0)) {
      return braces[0] + base + braces[1];
    }
  
    if (recurseTimes < 0) {
      if (isRegExp(value)) {
        return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
      } else {
        return ctx.stylize('[Object]', 'special');
      }
    }
  
    ctx.seen.push(value);
  
    var output;
    if (array) {
      output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
    } else {
      output = keys.map(function(key) {
        return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
      });
    }
  
    ctx.seen.pop();
  
    return reduceToSingleString(output, base, braces);
  }
  
  
  function formatPrimitive(ctx, value) {
    if (isUndefined(value))
      return ctx.stylize('undefined', 'undefined');
    if (isString(value)) {
      var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
                                               .replace(/'/g, "\\'")
                                               .replace(/\\"/g, '"') + '\'';
      return ctx.stylize(simple, 'string');
    }
    if (isNumber(value))
      return ctx.stylize('' + value, 'number');
    if (isBoolean(value))
      return ctx.stylize('' + value, 'boolean');
    // For some reason typeof null is "object", so special case here.
    if (isNull(value))
      return ctx.stylize('null', 'null');
  }
  
  
  function formatError(value) {
    return '[' + Error.prototype.toString.call(value) + ']';
  }
  
  
  function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
    var output = [];
    for (var i = 0, l = value.length; i < l; ++i) {
      if (hasOwnProperty(value, String(i))) {
        output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
            String(i), true));
      } else {
        output.push('');
      }
    }
    keys.forEach(function(key) {
      if (!key.match(/^\d+$/)) {
        output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
            key, true));
      }
    });
    return output;
  }
  
  
  function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
    var name, str, desc;
    desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
    if (desc.get) {
      if (desc.set) {
        str = ctx.stylize('[Getter/Setter]', 'special');
      } else {
        str = ctx.stylize('[Getter]', 'special');
      }
    } else {
      if (desc.set) {
        str = ctx.stylize('[Setter]', 'special');
      }
    }
    if (!hasOwnProperty(visibleKeys, key)) {
      name = '[' + key + ']';
    }
    if (!str) {
      if (ctx.seen.indexOf(desc.value) < 0) {
        if (isNull(recurseTimes)) {
          str = formatValue(ctx, desc.value, null);
        } else {
          str = formatValue(ctx, desc.value, recurseTimes - 1);
        }
        if (str.indexOf('\n') > -1) {
          if (array) {
            str = str.split('\n').map(function(line) {
              return '  ' + line;
            }).join('\n').substr(2);
          } else {
            str = '\n' + str.split('\n').map(function(line) {
              return '   ' + line;
            }).join('\n');
          }
        }
      } else {
        str = ctx.stylize('[Circular]', 'special');
      }
    }
    if (isUndefined(name)) {
      if (array && key.match(/^\d+$/)) {
        return str;
      }
      name = JSON.stringify('' + key);
      if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
        name = name.substr(1, name.length - 2);
        name = ctx.stylize(name, 'name');
      } else {
        name = name.replace(/'/g, "\\'")
                   .replace(/\\"/g, '"')
                   .replace(/(^"|"$)/g, "'");
        name = ctx.stylize(name, 'string');
      }
    }
  
    return name + ': ' + str;
  }
  
  
  function reduceToSingleString(output, base, braces) {
    var numLinesEst = 0;
    var length = output.reduce(function(prev, cur) {
      numLinesEst++;
      if (cur.indexOf('\n') >= 0) numLinesEst++;
      return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
    }, 0);
  
    if (length > 60) {
      return braces[0] +
             (base === '' ? '' : base + '\n ') +
             ' ' +
             output.join(',\n  ') +
             ' ' +
             braces[1];
    }
  
    return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
  }
  
  
  // NOTE: These type checking functions intentionally don't use `instanceof`
  // because it is fragile and can be easily faked with `Object.create()`.
  function isArray(ar) {
    return Array.isArray(ar);
  }
  exports.isArray = isArray;
  
  function isBoolean(arg) {
    return typeof arg === 'boolean';
  }
  exports.isBoolean = isBoolean;
  
  function isNull(arg) {
    return arg === null;
  }
  exports.isNull = isNull;
  
  function isNullOrUndefined(arg) {
    return arg == null;
  }
  exports.isNullOrUndefined = isNullOrUndefined;
  
  function isNumber(arg) {
    return typeof arg === 'number';
  }
  exports.isNumber = isNumber;
  
  function isString(arg) {
    return typeof arg === 'string';
  }
  exports.isString = isString;
  
  function isSymbol(arg) {
    return typeof arg === 'symbol';
  }
  exports.isSymbol = isSymbol;
  
  function isUndefined(arg) {
    return arg === void 0;
  }
  exports.isUndefined = isUndefined;
  
  function isRegExp(re) {
    return isObject(re) && objectToString(re) === '[object RegExp]';
  }
  exports.isRegExp = isRegExp;
  
  function isObject(arg) {
    return typeof arg === 'object' && arg !== null;
  }
  exports.isObject = isObject;
  
  function isDate(d) {
    return isObject(d) && objectToString(d) === '[object Date]';
  }
  exports.isDate = isDate;
  
  function isError(e) {
    return isObject(e) &&
        (objectToString(e) === '[object Error]' || e instanceof Error);
  }
  exports.isError = isError;
  
  function isFunction(arg) {
    return typeof arg === 'function';
  }
  exports.isFunction = isFunction;
  
  function isPrimitive(arg) {
    return arg === null ||
           typeof arg === 'boolean' ||
           typeof arg === 'number' ||
           typeof arg === 'string' ||
           typeof arg === 'symbol' ||  // ES6 symbol
           typeof arg === 'undefined';
  }
  exports.isPrimitive = isPrimitive;
  
  exports.isBuffer = require('./support/isBuffer');
  
  function objectToString(o) {
    return Object.prototype.toString.call(o);
  }
  
  
  function pad(n) {
    return n < 10 ? '0' + n.toString(10) : n.toString(10);
  }
  
  
  var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
                'Oct', 'Nov', 'Dec'];
  
  // 26 Feb 16:19:34
  function timestamp() {
    var d = new Date();
    var time = [pad(d.getHours()),
                pad(d.getMinutes()),
                pad(d.getSeconds())].join(':');
    return [d.getDate(), months[d.getMonth()], time].join(' ');
  }
  
  
  // log is just a thin wrapper to console.log that prepends a timestamp
  exports.log = function() {
    console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
  };
  
  
  /**
   * Inherit the prototype methods from one constructor into another.
   *
   * The Function.prototype.inherits from lang.js rewritten as a standalone
   * function (not on Function.prototype). NOTE: If this file is to be loaded
   * during bootstrapping this function needs to be rewritten using some native
   * functions as prototype setup using normal JavaScript does not work as
   * expected during bootstrapping (see mirror.js in r114903).
   *
   * @param {function} ctor Constructor function which needs to inherit the
   *     prototype.
   * @param {function} superCtor Constructor function to inherit prototype from.
   */
  exports.inherits = require('inherits');
  
  exports._extend = function(origin, add) {
    // Don't do anything if add isn't an object
    if (!add || !isObject(add)) return origin;
  
    var keys = Object.keys(add);
    var i = keys.length;
    while (i--) {
      origin[keys[i]] = add[keys[i]];
    }
    return origin;
  };
  
  function hasOwnProperty(obj, prop) {
    return Object.prototype.hasOwnProperty.call(obj, prop);
  }
  
  }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
  },{"./support/isBuffer":5,"_process":4,"inherits":3}],7:[function(require,module,exports){
  /**
   * Creates an array with all falsey values removed. The values `false`, `null`,
   * `0`, `""`, `undefined`, and `NaN` are falsey.
   *
   * @static
   * @memberOf _
   * @category Array
   * @param {Array} array The array to compact.
   * @returns {Array} Returns the new array of filtered values.
   * @example
   *
   * _.compact([0, 1, false, 2, '', 3]);
   * // => [1, 2, 3]
   */
  function compact(array) {
    var index = -1,
        length = array ? array.length : 0,
        resIndex = -1,
        result = [];
  
    while (++index < length) {
      var value = array[index];
      if (value) {
        result[++resIndex] = value;
      }
    }
    return result;
  }
  
  module.exports = compact;
  
  },{}],8:[function(require,module,exports){
  var baseCallback = require('../internal/baseCallback');
  
  /**
   * This method is like `_.find` except that it returns the index of the first
   * element `predicate` returns truthy for, instead of the element itself.
   *
   * If a property name is provided for `predicate` the created `_.property`
   * style callback returns the property value of the given element.
   *
   * If a value is also provided for `thisArg` the created `_.matchesProperty`
   * style callback returns `true` for elements that have a matching property
   * value, else `false`.
   *
   * If an object is provided for `predicate` the created `_.matches` style
   * callback returns `true` for elements that have the properties of the given
   * object, else `false`.
   *
   * @static
   * @memberOf _
   * @category Array
   * @param {Array} array The array to search.
   * @param {Function|Object|string} [predicate=_.identity] The function invoked
   *  per iteration.
   * @param {*} [thisArg] The `this` binding of `predicate`.
   * @returns {number} Returns the index of the found element, else `-1`.
   * @example
   *
   * var users = [
   *   { 'user': 'barney',  'active': false },
   *   { 'user': 'fred',    'active': false },
   *   { 'user': 'pebbles', 'active': true }
   * ];
   *
   * _.findIndex(users, function(chr) {
   *   return chr.user == 'barney';
   * });
   * // => 0
   *
   * // using the `_.matches` callback shorthand
   * _.findIndex(users, { 'user': 'fred', 'active': false });
   * // => 1
   *
   * // using the `_.matchesProperty` callback shorthand
   * _.findIndex(users, 'active', false);
   * // => 0
   *
   * // using the `_.property` callback shorthand
   * _.findIndex(users, 'active');
   * // => 2
   */
  function findIndex(array, predicate, thisArg) {
    var index = -1,
        length = array ? array.length : 0;
  
    predicate = baseCallback(predicate, thisArg, 3);
    while (++index < length) {
      if (predicate(array[index], index, array)) {
        return index;
      }
    }
    return -1;
  }
  
  module.exports = findIndex;
  
  },{"../internal/baseCallback":19}],9:[function(require,module,exports){
  var baseIndexOf = require('../internal/baseIndexOf'),
      cacheIndexOf = require('../internal/cacheIndexOf'),
      createCache = require('../internal/createCache'),
      isArguments = require('../lang/isArguments'),
      isArray = require('../lang/isArray');
  
  /**
   * Creates an array of unique values in all provided arrays using `SameValueZero`
   * for equality comparisons.
   *
   * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
   * e.g. `===`, except that `NaN` matches `NaN`. See the
   * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
   * for more details.
   *
   * @static
   * @memberOf _
   * @category Array
   * @param {...Array} [arrays] The arrays to inspect.
   * @returns {Array} Returns the new array of shared values.
   * @example
   * _.intersection([1, 2], [4, 2], [2, 1]);
   * // => [2]
   */
  function intersection() {
    var args = [],
        argsIndex = -1,
        argsLength = arguments.length,
        caches = [],
        indexOf = baseIndexOf,
        isCommon = true;
  
    while (++argsIndex < argsLength) {
      var value = arguments[argsIndex];
      if (isArray(value) || isArguments(value)) {
        args.push(value);
        caches.push((isCommon && value.length >= 120) ? createCache(argsIndex && value) : null);
      }
    }
    argsLength = args.length;
    var array = args[0],
        index = -1,
        length = array ? array.length : 0,
        result = [],
        seen = caches[0];
  
    outer:
    while (++index < length) {
      value = array[index];
      if ((seen ? cacheIndexOf(seen, value) : indexOf(result, value, 0)) < 0) {
        argsIndex = argsLength;
        while (--argsIndex) {
          var cache = caches[argsIndex];
          if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value, 0)) < 0) {
            continue outer;
          }
        }
        if (seen) {
          seen.push(value);
        }
        result.push(value);
      }
    }
    return result;
  }
  
  module.exports = intersection;
  
  },{"../internal/baseIndexOf":25,"../internal/cacheIndexOf":38,"../internal/createCache":43,"../lang/isArguments":65,"../lang/isArray":66}],10:[function(require,module,exports){
  var baseCallback = require('../internal/baseCallback'),
      baseEach = require('../internal/baseEach'),
      baseFind = require('../internal/baseFind'),
      findIndex = require('../array/findIndex'),
      isArray = require('../lang/isArray');
  
  /**
   * Iterates over elements of `collection`, returning the first element
   * `predicate` returns truthy for. The predicate is bound to `thisArg` and
   * invoked with three arguments; (value, index|key, collection).
   *
   * If a property name is provided for `predicate` the created `_.property`
   * style callback returns the property value of the given element.
   *
   * If a value is also provided for `thisArg` the created `_.matchesProperty`
   * style callback returns `true` for elements that have a matching property
   * value, else `false`.
   *
   * If an object is provided for `predicate` the created `_.matches` style
   * callback returns `true` for elements that have the properties of the given
   * object, else `false`.
   *
   * @static
   * @memberOf _
   * @alias detect
   * @category Collection
   * @param {Array|Object|string} collection The collection to search.
   * @param {Function|Object|string} [predicate=_.identity] The function invoked
   *  per iteration.
   * @param {*} [thisArg] The `this` binding of `predicate`.
   * @returns {*} Returns the matched element, else `undefined`.
   * @example
   *
   * var users = [
   *   { 'user': 'barney',  'age': 36, 'active': true },
   *   { 'user': 'fred',    'age': 40, 'active': false },
   *   { 'user': 'pebbles', 'age': 1,  'active': true }
   * ];
   *
   * _.result(_.find(users, function(chr) {
   *   return chr.age < 40;
   * }), 'user');
   * // => 'barney'
   *
   * // using the `_.matches` callback shorthand
   * _.result(_.find(users, { 'age': 1, 'active': true }), 'user');
   * // => 'pebbles'
   *
   * // using the `_.matchesProperty` callback shorthand
   * _.result(_.find(users, 'active', false), 'user');
   * // => 'fred'
   *
   * // using the `_.property` callback shorthand
   * _.result(_.find(users, 'active'), 'user');
   * // => 'barney'
   */
  function find(collection, predicate, thisArg) {
    if (isArray(collection)) {
      var index = findIndex(collection, predicate, thisArg);
      return index > -1 ? collection[index] : undefined;
    }
    predicate = baseCallback(predicate, thisArg, 3);
    return baseFind(collection, predicate, baseEach);
  }
  
  module.exports = find;
  
  },{"../array/findIndex":8,"../internal/baseCallback":19,"../internal/baseEach":21,"../internal/baseFind":22,"../lang/isArray":66}],11:[function(require,module,exports){
  var arrayEach = require('../internal/arrayEach'),
      baseEach = require('../internal/baseEach'),
      bindCallback = require('../internal/bindCallback'),
      isArray = require('../lang/isArray');
  
  /**
   * Iterates over elements of `collection` invoking `iteratee` for each element.
   * The `iteratee` is bound to `thisArg` and invoked with three arguments;
   * (value, index|key, collection). Iterator functions may exit iteration early
   * by explicitly returning `false`.
   *
   * **Note:** As with other "Collections" methods, objects with a `length` property
   * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
   * may be used for object iteration.
   *
   * @static
   * @memberOf _
   * @alias each
   * @category Collection
   * @param {Array|Object|string} collection The collection to iterate over.
   * @param {Function} [iteratee=_.identity] The function invoked per iteration.
   * @param {*} [thisArg] The `this` binding of `iteratee`.
   * @returns {Array|Object|string} Returns `collection`.
   * @example
   *
   * _([1, 2]).forEach(function(n) {
   *   console.log(n);
   * }).value();
   * // => logs each value from left to right and returns the array
   *
   * _.forEach({ 'a': 1, 'b': 2 }, function(n, key) {
   *   console.log(n, key);
   * });
   * // => logs each value-key pair and returns the object (iteration order is not guaranteed)
   */
  function forEach(collection, iteratee, thisArg) {
    return (typeof iteratee == 'function' && typeof thisArg == 'undefined' && isArray(collection))
      ? arrayEach(collection, iteratee)
      : baseEach(collection, bindCallback(iteratee, thisArg, 3));
  }
  
  module.exports = forEach;
  
  },{"../internal/arrayEach":17,"../internal/baseEach":21,"../internal/bindCallback":37,"../lang/isArray":66}],12:[function(require,module,exports){
  var arrayReduce = require('../internal/arrayReduce'),
      baseCallback = require('../internal/baseCallback'),
      baseEach = require('../internal/baseEach'),
      baseReduce = require('../internal/baseReduce'),
      isArray = require('../lang/isArray');
  
  /**
   * Reduces `collection` to a value which is the accumulated result of running
   * each element in `collection` through `iteratee`, where each successive
   * invocation is supplied the return value of the previous. If `accumulator`
   * is not provided the first element of `collection` is used as the initial
   * value. The `iteratee` is bound to `thisArg`and invoked with four arguments;
   * (accumulator, value, index|key, collection).
   *
   * Many lodash methods are guarded to work as interatees for methods like
   * `_.reduce`, `_.reduceRight`, and `_.transform`.
   *
   * The guarded methods are:
   * `assign`, `defaults`, `merge`, and `sortAllBy`
   *
   * @static
   * @memberOf _
   * @alias foldl, inject
   * @category Collection
   * @param {Array|Object|string} collection The collection to iterate over.
   * @param {Function} [iteratee=_.identity] The function invoked per iteration.
   * @param {*} [accumulator] The initial value.
   * @param {*} [thisArg] The `this` binding of `iteratee`.
   * @returns {*} Returns the accumulated value.
   * @example
   *
   * _.reduce([1, 2], function(sum, n) {
   *   return sum + n;
   * });
   * // => 3
   *
   * _.reduce({ 'a': 1, 'b': 2 }, function(result, n, key) {
   *   result[key] = n * 3;
   *   return result;
   * }, {});
   * // => { 'a': 3, 'b': 6 } (iteration order is not guaranteed)
   */
  function reduce(collection, iteratee, accumulator, thisArg) {
    var func = isArray(collection) ? arrayReduce : baseReduce;
    return func(collection, baseCallback(iteratee, thisArg, 4), accumulator, arguments.length < 3, baseEach);
  }
  
  module.exports = reduce;
  
  },{"../internal/arrayReduce":18,"../internal/baseCallback":19,"../internal/baseEach":21,"../internal/baseReduce":33,"../lang/isArray":66}],13:[function(require,module,exports){
  var isNative = require('../lang/isNative');
  
  /* Native method references for those with the same name as other `lodash` methods. */
  var nativeNow = isNative(nativeNow = Date.now) && nativeNow;
  
  /**
   * Gets the number of milliseconds that have elapsed since the Unix epoch
   * (1 January 1970 00:00:00 UTC).
   *
   * @static
   * @memberOf _
   * @category Date
   * @example
   *
   * _.defer(function(stamp) {
   *   console.log(_.now() - stamp);
   * }, _.now());
   * // => logs the number of milliseconds it took for the deferred function to be invoked
   */
  var now = nativeNow || function() {
    return new Date().getTime();
  };
  
  module.exports = now;
  
  },{"../lang/isNative":69}],14:[function(require,module,exports){
  var baseSlice = require('../internal/baseSlice'),
      createWrapper = require('../internal/createWrapper'),
      replaceHolders = require('../internal/replaceHolders');
  
  /** Used to compose bitmasks for wrapper metadata. */
  var BIND_FLAG = 1,
      PARTIAL_FLAG = 32;
  
  /**
   * Creates a function that invokes `func` with the `this` binding of `thisArg`
   * and prepends any additional `_.bind` arguments to those provided to the
   * bound function.
   *
   * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
   * may be used as a placeholder for partially applied arguments.
   *
   * **Note:** Unlike native `Function#bind` this method does not set the `length`
   * property of bound functions.
   *
   * @static
   * @memberOf _
   * @category Function
   * @param {Function} func The function to bind.
   * @param {*} thisArg The `this` binding of `func`.
   * @param {...*} [args] The arguments to be partially applied.
   * @returns {Function} Returns the new bound function.
   * @example
   *
   * var greet = function(greeting, punctuation) {
   *   return greeting + ' ' + this.user + punctuation;
   * };
   *
   * var object = { 'user': 'fred' };
   *
   * var bound = _.bind(greet, object, 'hi');
   * bound('!');
   * // => 'hi fred!'
   *
   * // using placeholders
   * var bound = _.bind(greet, object, _, '!');
   * bound('hi');
   * // => 'hi fred!'
   */
  function bind(func, thisArg) {
    var bitmask = BIND_FLAG;
    if (arguments.length > 2) {
      var partials = baseSlice(arguments, 2),
          holders = replaceHolders(partials, bind.placeholder);
  
      bitmask |= PARTIAL_FLAG;
    }
    return createWrapper(func, bitmask, thisArg, partials, holders);
  }
  
  // Assign default placeholders.
  bind.placeholder = {};
  
  module.exports = bind;
  
  },{"../internal/baseSlice":35,"../internal/createWrapper":47,"../internal/replaceHolders":61}],15:[function(require,module,exports){
  (function (global){
  var cachePush = require('./cachePush'),
      isNative = require('../lang/isNative');
  
  /** Native method references. */
  var Set = isNative(Set = global.Set) && Set;
  
  /* Native method references for those with the same name as other `lodash` methods. */
  var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate;
  
  /**
   *
   * Creates a cache object to store unique values.
   *
   * @private
   * @param {Array} [values] The values to cache.
   */
  function SetCache(values) {
    var length = values ? values.length : 0;
  
    this.data = { 'hash': nativeCreate(null), 'set': new Set };
    while (length--) {
      this.push(values[length]);
    }
  }
  
  // Add functions to the `Set` cache.
  SetCache.prototype.push = cachePush;
  
  module.exports = SetCache;
  
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
  },{"../lang/isNative":69,"./cachePush":39}],16:[function(require,module,exports){
  /**
   * Copies the values of `source` to `array`.
   *
   * @private
   * @param {Array} source The array to copy values from.
   * @param {Array} [array=[]] The array to copy values to.
   * @returns {Array} Returns `array`.
   */
  function arrayCopy(source, array) {
    var index = -1,
        length = source.length;
  
    array || (array = Array(length));
    while (++index < length) {
      array[index] = source[index];
    }
    return array;
  }
  
  module.exports = arrayCopy;
  
  },{}],17:[function(require,module,exports){
  /**
   * A specialized version of `_.forEach` for arrays without support for callback
   * shorthands or `this` binding.
   *
   * @private
   * @param {Array} array The array to iterate over.
   * @param {Function} iteratee The function invoked per iteration.
   * @returns {Array} Returns `array`.
   */
  function arrayEach(array, iteratee) {
    var index = -1,
        length = array.length;
  
    while (++index < length) {
      if (iteratee(array[index], index, array) === false) {
        break;
      }
    }
    return array;
  }
  
  module.exports = arrayEach;
  
  },{}],18:[function(require,module,exports){
  /**
   * A specialized version of `_.reduce` for arrays without support for callback
   * shorthands or `this` binding.
   *
   * @private
   * @param {Array} array The array to iterate over.
   * @param {Function} iteratee The function invoked per iteration.
   * @param {*} [accumulator] The initial value.
   * @param {boolean} [initFromArray] Specify using the first element of `array`
   *  as the initial value.
   * @returns {*} Returns the accumulated value.
   */
  function arrayReduce(array, iteratee, accumulator, initFromArray) {
    var index = -1,
        length = array.length;
  
    if (initFromArray && length) {
      accumulator = array[++index];
    }
    while (++index < length) {
      accumulator = iteratee(accumulator, array[index], index, array);
    }
    return accumulator;
  }
  
  module.exports = arrayReduce;
  
  },{}],19:[function(require,module,exports){
  var baseMatches = require('./baseMatches'),
      baseMatchesProperty = require('./baseMatchesProperty'),
      baseProperty = require('./baseProperty'),
      bindCallback = require('./bindCallback'),
      identity = require('../utility/identity'),
      isBindable = require('./isBindable');
  
  /**
   * The base implementation of `_.callback` which supports specifying the
   * number of arguments to provide to `func`.
   *
   * @private
   * @param {*} [func=_.identity] The value to convert to a callback.
   * @param {*} [thisArg] The `this` binding of `func`.
   * @param {number} [argCount] The number of arguments to provide to `func`.
   * @returns {Function} Returns the callback.
   */
  function baseCallback(func, thisArg, argCount) {
    var type = typeof func;
    if (type == 'function') {
      return (typeof thisArg != 'undefined' && isBindable(func))
        ? bindCallback(func, thisArg, argCount)
        : func;
    }
    if (func == null) {
      return identity;
    }
    if (type == 'object') {
      return baseMatches(func);
    }
    return typeof thisArg == 'undefined'
      ? baseProperty(func + '')
      : baseMatchesProperty(func + '', thisArg);
  }
  
  module.exports = baseCallback;
  
  },{"../utility/identity":79,"./baseMatches":30,"./baseMatchesProperty":31,"./baseProperty":32,"./bindCallback":37,"./isBindable":53}],20:[function(require,module,exports){
  (function (global){
  var isObject = require('../lang/isObject');
  
  /**
   * The base implementation of `_.create` without support for assigning
   * properties to the created object.
   *
   * @private
   * @param {Object} prototype The object to inherit from.
   * @returns {Object} Returns the new object.
   */
  var baseCreate = (function() {
    function Object() {}
    return function(prototype) {
      if (isObject(prototype)) {
        Object.prototype = prototype;
        var result = new Object;
        Object.prototype = null;
      }
      return result || global.Object();
    };
  }());
  
  module.exports = baseCreate;
  
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
  },{"../lang/isObject":70}],21:[function(require,module,exports){
  var baseForOwn = require('./baseForOwn'),
      isLength = require('./isLength'),
      toObject = require('./toObject');
  
  /**
   * The base implementation of `_.forEach` without support for callback
   * shorthands and `this` binding.
   *
   * @private
   * @param {Array|Object|string} collection The collection to iterate over.
   * @param {Function} iteratee The function invoked per iteration.
   * @returns {Array|Object|string} Returns `collection`.
   */
  function baseEach(collection, iteratee) {
    var length = collection ? collection.length : 0;
    if (!isLength(length)) {
      return baseForOwn(collection, iteratee);
    }
    var index = -1,
        iterable = toObject(collection);
  
    while (++index < length) {
      if (iteratee(iterable[index], index, iterable) === false) {
        break;
      }
    }
    return collection;
  }
  
  module.exports = baseEach;
  
  },{"./baseForOwn":24,"./isLength":55,"./toObject":64}],22:[function(require,module,exports){
  /**
   * The base implementation of `_.find`, `_.findLast`, `_.findKey`, and `_.findLastKey`,
   * without support for callback shorthands and `this` binding, which iterates
   * over `collection` using the provided `eachFunc`.
   *
   * @private
   * @param {Array|Object|string} collection The collection to search.
   * @param {Function} predicate The function invoked per iteration.
   * @param {Function} eachFunc The function to iterate over `collection`.
   * @param {boolean} [retKey] Specify returning the key of the found element
   *  instead of the element itself.
   * @returns {*} Returns the found element or its key, else `undefined`.
   */
  function baseFind(collection, predicate, eachFunc, retKey) {
    var result;
    eachFunc(collection, function(value, key, collection) {
      if (predicate(value, key, collection)) {
        result = retKey ? key : value;
        return false;
      }
    });
    return result;
  }
  
  module.exports = baseFind;
  
  },{}],23:[function(require,module,exports){
  var toObject = require('./toObject');
  
  /**
   * The base implementation of `baseForIn` and `baseForOwn` which iterates
   * over `object` properties returned by `keysFunc` invoking `iteratee` for
   * each property. Iterator functions may exit iteration early by explicitly
   * returning `false`.
   *
   * @private
   * @param {Object} object The object to iterate over.
   * @param {Function} iteratee The function invoked per iteration.
   * @param {Function} keysFunc The function to get the keys of `object`.
   * @returns {Object} Returns `object`.
   */
  function baseFor(object, iteratee, keysFunc) {
    var index = -1,
        iterable = toObject(object),
        props = keysFunc(object),
        length = props.length;
  
    while (++index < length) {
      var key = props[index];
      if (iteratee(iterable[key], key, iterable) === false) {
        break;
      }
    }
    return object;
  }
  
  module.exports = baseFor;
  
  },{"./toObject":64}],24:[function(require,module,exports){
  var baseFor = require('./baseFor'),
      keys = require('../object/keys');
  
  /**
   * The base implementation of `_.forOwn` without support for callback
   * shorthands and `this` binding.
   *
   * @private
   * @param {Object} object The object to iterate over.
   * @param {Function} iteratee The function invoked per iteration.
   * @returns {Object} Returns `object`.
   */
  function baseForOwn(object, iteratee) {
    return baseFor(object, iteratee, keys);
  }
  
  module.exports = baseForOwn;
  
  },{"../object/keys":74,"./baseFor":23}],25:[function(require,module,exports){
  var indexOfNaN = require('./indexOfNaN');
  
  /**
   * The base implementation of `_.indexOf` without support for binary searches.
   *
   * @private
   * @param {Array} array The array to search.
   * @param {*} value The value to search for.
   * @param {number} fromIndex The index to search from.
   * @returns {number} Returns the index of the matched value, else `-1`.
   */
  function baseIndexOf(array, value, fromIndex) {
    if (value !== value) {
      return indexOfNaN(array, fromIndex);
    }
    var index = fromIndex - 1,
        length = array.length;
  
    while (++index < length) {
      if (array[index] === value) {
        return index;
      }
    }
    return -1;
  }
  
  module.exports = baseIndexOf;
  
  },{"./indexOfNaN":52}],26:[function(require,module,exports){
  var baseIsEqualDeep = require('./baseIsEqualDeep');
  
  /**
   * The base implementation of `_.isEqual` without support for `this` binding
   * `customizer` functions.
   *
   * @private
   * @param {*} value The value to compare.
   * @param {*} other The other value to compare.
   * @param {Function} [customizer] The function to customize comparing values.
   * @param {boolean} [isWhere] Specify performing partial comparisons.
   * @param {Array} [stackA] Tracks traversed `value` objects.
   * @param {Array} [stackB] Tracks traversed `other` objects.
   * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
   */
  function baseIsEqual(value, other, customizer, isWhere, stackA, stackB) {
    // Exit early for identical values.
    if (value === other) {
      // Treat `+0` vs. `-0` as not equal.
      return value !== 0 || (1 / value == 1 / other);
    }
    var valType = typeof value,
        othType = typeof other;
  
    // Exit early for unlike primitive values.
    if ((valType != 'function' && valType != 'object' && othType != 'function' && othType != 'object') ||
        value == null || other == null) {
      // Return `false` unless both values are `NaN`.
      return value !== value && other !== other;
    }
    return baseIsEqualDeep(value, other, baseIsEqual, customizer, isWhere, stackA, stackB);
  }
  
  module.exports = baseIsEqual;
  
  },{"./baseIsEqualDeep":27}],27:[function(require,module,exports){
  var equalArrays = require('./equalArrays'),
      equalByTag = require('./equalByTag'),
      equalObjects = require('./equalObjects'),
      isArray = require('../lang/isArray'),
      isTypedArray = require('../lang/isTypedArray');
  
  /** `Object#toString` result references. */
  var argsTag = '[object Arguments]',
      arrayTag = '[object Array]',
      objectTag = '[object Object]';
  
  /** Used for native method references. */
  var objectProto = Object.prototype;
  
  /** Used to check objects for own properties. */
  var hasOwnProperty = objectProto.hasOwnProperty;
  
  /**
   * Used to resolve the `toStringTag` of values.
   * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring)
   * for more details.
   */
  var objToString = objectProto.toString;
  
  /**
   * A specialized version of `baseIsEqual` for arrays and objects which performs
   * deep comparisons and tracks traversed objects enabling objects with circular
   * references to be compared.
   *
   * @private
   * @param {Object} object The object to compare.
   * @param {Object} other The other object to compare.
   * @param {Function} equalFunc The function to determine equivalents of values.
   * @param {Function} [customizer] The function to customize comparing objects.
   * @param {boolean} [isWhere] Specify performing partial comparisons.
   * @param {Array} [stackA=[]] Tracks traversed `value` objects.
   * @param {Array} [stackB=[]] Tracks traversed `other` objects.
   * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
   */
  function baseIsEqualDeep(object, other, equalFunc, customizer, isWhere, stackA, stackB) {
    var objIsArr = isArray(object),
        othIsArr = isArray(other),
        objTag = arrayTag,
        othTag = arrayTag;
  
    if (!objIsArr) {
      objTag = objToString.call(object);
      if (objTag == argsTag) {
        objTag = objectTag;
      } else if (objTag != objectTag) {
        objIsArr = isTypedArray(object);
      }
    }
    if (!othIsArr) {
      othTag = objToString.call(other);
      if (othTag == argsTag) {
        othTag = objectTag;
      } else if (othTag != objectTag) {
        othIsArr = isTypedArray(other);
      }
    }
    var objIsObj = objTag == objectTag,
        othIsObj = othTag == objectTag,
        isSameTag = objTag == othTag;
  
    if (isSameTag && !(objIsArr || objIsObj)) {
      return equalByTag(object, other, objTag);
    }
    var valWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
        othWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
  
    if (valWrapped || othWrapped) {
      return equalFunc(valWrapped ? object.value() : object, othWrapped ? other.value() : other, customizer, isWhere, stackA, stackB);
    }
    if (!isSameTag) {
      return false;
    }
    // Assume cyclic values are equal.
    // For more information on detecting circular references see https://es5.github.io/#JO.
    stackA || (stackA = []);
    stackB || (stackB = []);
  
    var length = stackA.length;
    while (length--) {
      if (stackA[length] == object) {
        return stackB[length] == other;
      }
    }
    // Add `object` and `other` to the stack of traversed objects.
    stackA.push(object);
    stackB.push(other);
  
    var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isWhere, stackA, stackB);
  
    stackA.pop();
    stackB.pop();
  
    return result;
  }
  
  module.exports = baseIsEqualDeep;
  
  },{"../lang/isArray":66,"../lang/isTypedArray":72,"./equalArrays":48,"./equalByTag":49,"./equalObjects":50}],28:[function(require,module,exports){
  /**
   * The base implementation of `_.isFunction` without support for environments
   * with incorrect `typeof` results.
   *
   * @private
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
   */
  function baseIsFunction(value) {
    // Avoid a Chakra JIT bug in compatibility modes of IE 11.
    // See https://github.com/jashkenas/underscore/issues/1621 for more details.
    return typeof value == 'function' || false;
  }
  
  module.exports = baseIsFunction;
  
  },{}],29:[function(require,module,exports){
  var baseIsEqual = require('./baseIsEqual');
  
  /** Used for native method references. */
  var objectProto = Object.prototype;
  
  /** Used to check objects for own properties. */
  var hasOwnProperty = objectProto.hasOwnProperty;
  
  /**
   * The base implementation of `_.isMatch` without support for callback
   * shorthands or `this` binding.
   *
   * @private
   * @param {Object} object The object to inspect.
   * @param {Array} props The source property names to match.
   * @param {Array} values The source values to match.
   * @param {Array} strictCompareFlags Strict comparison flags for source values.
   * @param {Function} [customizer] The function to customize comparing objects.
   * @returns {boolean} Returns `true` if `object` is a match, else `false`.
   */
  function baseIsMatch(object, props, values, strictCompareFlags, customizer) {
    var length = props.length;
    if (object == null) {
      return !length;
    }
    var index = -1,
        noCustomizer = !customizer;
  
    while (++index < length) {
      if ((noCustomizer && strictCompareFlags[index])
            ? values[index] !== object[props[index]]
            : !hasOwnProperty.call(object, props[index])
          ) {
        return false;
      }
    }
    index = -1;
    while (++index < length) {
      var key = props[index];
      if (noCustomizer && strictCompareFlags[index]) {
        var result = hasOwnProperty.call(object, key);
      } else {
        var objValue = object[key],
            srcValue = values[index];
  
        result = customizer ? customizer(objValue, srcValue, key) : undefined;
        if (typeof result == 'undefined') {
          result = baseIsEqual(srcValue, objValue, customizer, true);
        }
      }
      if (!result) {
        return false;
      }
    }
    return true;
  }
  
  module.exports = baseIsMatch;
  
  },{"./baseIsEqual":26}],30:[function(require,module,exports){
  var baseIsMatch = require('./baseIsMatch'),
      isStrictComparable = require('./isStrictComparable'),
      keys = require('../object/keys');
  
  /** Used for native method references. */
  var objectProto = Object.prototype;
  
  /** Used to check objects for own properties. */
  var hasOwnProperty = objectProto.hasOwnProperty;
  
  /**
   * The base implementation of `_.matches` which does not clone `source`.
   *
   * @private
   * @param {Object} source The object of property values to match.
   * @returns {Function} Returns the new function.
   */
  function baseMatches(source) {
    var props = keys(source),
        length = props.length;
  
    if (length == 1) {
      var key = props[0],
          value = source[key];
  
      if (isStrictComparable(value)) {
        return function(object) {
          return object != null && object[key] === value && hasOwnProperty.call(object, key);
        };
      }
    }
    var values = Array(length),
        strictCompareFlags = Array(length);
  
    while (length--) {
      value = source[props[length]];
      values[length] = value;
      strictCompareFlags[length] = isStrictComparable(value);
    }
    return function(object) {
      return baseIsMatch(object, props, values, strictCompareFlags);
    };
  }
  
  module.exports = baseMatches;
  
  },{"../object/keys":74,"./baseIsMatch":29,"./isStrictComparable":57}],31:[function(require,module,exports){
  var baseIsEqual = require('./baseIsEqual'),
      isStrictComparable = require('./isStrictComparable');
  
  /**
   * The base implementation of `_.matchesProperty` which does not coerce `key`
   * to a string.
   *
   * @private
   * @param {string} key The key of the property to get.
   * @param {*} value The value to compare.
   * @returns {Function} Returns the new function.
   */
  function baseMatchesProperty(key, value) {
    if (isStrictComparable(value)) {
      return function(object) {
        return object != null && object[key] === value;
      };
    }
    return function(object) {
      return object != null && baseIsEqual(value, object[key], null, true);
    };
  }
  
  module.exports = baseMatchesProperty;
  
  },{"./baseIsEqual":26,"./isStrictComparable":57}],32:[function(require,module,exports){
  /**
   * The base implementation of `_.property` which does not coerce `key` to a string.
   *
   * @private
   * @param {string} key The key of the property to get.
   * @returns {Function} Returns the new function.
   */
  function baseProperty(key) {
    return function(object) {
      return object == null ? undefined : object[key];
    };
  }
  
  module.exports = baseProperty;
  
  },{}],33:[function(require,module,exports){
  /**
   * The base implementation of `_.reduce` and `_.reduceRight` without support
   * for callback shorthands or `this` binding, which iterates over `collection`
   * using the provided `eachFunc`.
   *
   * @private
   * @param {Array|Object|string} collection The collection to iterate over.
   * @param {Function} iteratee The function invoked per iteration.
   * @param {*} accumulator The initial value.
   * @param {boolean} initFromCollection Specify using the first or last element
   *  of `collection` as the initial value.
   * @param {Function} eachFunc The function to iterate over `collection`.
   * @returns {*} Returns the accumulated value.
   */
  function baseReduce(collection, iteratee, accumulator, initFromCollection, eachFunc) {
    eachFunc(collection, function(value, index, collection) {
      accumulator = initFromCollection
        ? (initFromCollection = false, value)
        : iteratee(accumulator, value, index, collection);
    });
    return accumulator;
  }
  
  module.exports = baseReduce;
  
  },{}],34:[function(require,module,exports){
  var identity = require('../utility/identity'),
      metaMap = require('./metaMap');
  
  /**
   * The base implementation of `setData` without support for hot loop detection.
   *
   * @private
   * @param {Function} func The function to associate metadata with.
   * @param {*} data The metadata.
   * @returns {Function} Returns `func`.
   */
  var baseSetData = !metaMap ? identity : function(func, data) {
    metaMap.set(func, data);
    return func;
  };
  
  module.exports = baseSetData;
  
  },{"../utility/identity":79,"./metaMap":59}],35:[function(require,module,exports){
  /**
   * The base implementation of `_.slice` without an iteratee call guard.
   *
   * @private
   * @param {Array} array The array to slice.
   * @param {number} [start=0] The start position.
   * @param {number} [end=array.length] The end position.
   * @returns {Array} Returns the slice of `array`.
   */
  function baseSlice(array, start, end) {
    var index = -1,
        length = array.length;
  
    start = start == null ? 0 : (+start || 0);
    if (start < 0) {
      start = -start > length ? 0 : (length + start);
    }
    end = (typeof end == 'undefined' || end > length) ? length : (+end || 0);
    if (end < 0) {
      end += length;
    }
    length = start > end ? 0 : ((end - start) >>> 0);
    start >>>= 0;
  
    var result = Array(length);
    while (++index < length) {
      result[index] = array[index + start];
    }
    return result;
  }
  
  module.exports = baseSlice;
  
  },{}],36:[function(require,module,exports){
  /**
   * Converts `value` to a string if it is not one. An empty string is returned
   * for `null` or `undefined` values.
   *
   * @private
   * @param {*} value The value to process.
   * @returns {string} Returns the string.
   */
  function baseToString(value) {
    if (typeof value == 'string') {
      return value;
    }
    return value == null ? '' : (value + '');
  }
  
  module.exports = baseToString;
  
  },{}],37:[function(require,module,exports){
  var identity = require('../utility/identity');
  
  /**
   * A specialized version of `baseCallback` which only supports `this` binding
   * and specifying the number of arguments to provide to `func`.
   *
   * @private
   * @param {Function} func The function to bind.
   * @param {*} thisArg The `this` binding of `func`.
   * @param {number} [argCount] The number of arguments to provide to `func`.
   * @returns {Function} Returns the callback.
   */
  function bindCallback(func, thisArg, argCount) {
    if (typeof func != 'function') {
      return identity;
    }
    if (typeof thisArg == 'undefined') {
      return func;
    }
    switch (argCount) {
      case 1: return function(value) {
        return func.call(thisArg, value);
      };
      case 3: return function(value, index, collection) {
        return func.call(thisArg, value, index, collection);
      };
      case 4: return function(accumulator, value, index, collection) {
        return func.call(thisArg, accumulator, value, index, collection);
      };
      case 5: return function(value, other, key, object, source) {
        return func.call(thisArg, value, other, key, object, source);
      };
    }
    return function() {
      return func.apply(thisArg, arguments);
    };
  }
  
  module.exports = bindCallback;
  
  },{"../utility/identity":79}],38:[function(require,module,exports){
  var isObject = require('../lang/isObject');
  
  /**
   * Checks if `value` is in `cache` mimicking the return signature of
   * `_.indexOf` by returning `0` if the value is found, else `-1`.
   *
   * @private
   * @param {Object} cache The cache to search.
   * @param {*} value The value to search for.
   * @returns {number} Returns `0` if `value` is found, else `-1`.
   */
  function cacheIndexOf(cache, value) {
    var data = cache.data,
        result = (typeof value == 'string' || isObject(value)) ? data.set.has(value) : data.hash[value];
  
    return result ? 0 : -1;
  }
  
  module.exports = cacheIndexOf;
  
  },{"../lang/isObject":70}],39:[function(require,module,exports){
  var isObject = require('../lang/isObject');
  
  /**
   * Adds `value` to the cache.
   *
   * @private
   * @name push
   * @memberOf SetCache
   * @param {*} value The value to cache.
   */
  function cachePush(value) {
    var data = this.data;
    if (typeof value == 'string' || isObject(value)) {
      data.set.add(value);
    } else {
      data.hash[value] = true;
    }
  }
  
  module.exports = cachePush;
  
  },{"../lang/isObject":70}],40:[function(require,module,exports){
  /* Native method references for those with the same name as other `lodash` methods. */
  var nativeMax = Math.max;
  
  /**
   * Creates an array that is the composition of partially applied arguments,
   * placeholders, and provided arguments into a single array of arguments.
   *
   * @private
   * @param {Array|Object} args The provided arguments.
   * @param {Array} partials The arguments to prepend to those provided.
   * @param {Array} holders The `partials` placeholder indexes.
   * @returns {Array} Returns the new array of composed arguments.
   */
  function composeArgs(args, partials, holders) {
    var holdersLength = holders.length,
        argsIndex = -1,
        argsLength = nativeMax(args.length - holdersLength, 0),
        leftIndex = -1,
        leftLength = partials.length,
        result = Array(argsLength + leftLength);
  
    while (++leftIndex < leftLength) {
      result[leftIndex] = partials[leftIndex];
    }
    while (++argsIndex < holdersLength) {
      result[holders[argsIndex]] = args[argsIndex];
    }
    while (argsLength--) {
      result[leftIndex++] = args[argsIndex++];
    }
    return result;
  }
  
  module.exports = composeArgs;
  
  },{}],41:[function(require,module,exports){
  /* Native method references for those with the same name as other `lodash` methods. */
  var nativeMax = Math.max;
  
  /**
   * This function is like `composeArgs` except that the arguments composition
   * is tailored for `_.partialRight`.
   *
   * @private
   * @param {Array|Object} args The provided arguments.
   * @param {Array} partials The arguments to append to those provided.
   * @param {Array} holders The `partials` placeholder indexes.
   * @returns {Array} Returns the new array of composed arguments.
   */
  function composeArgsRight(args, partials, holders) {
    var holdersIndex = -1,
        holdersLength = holders.length,
        argsIndex = -1,
        argsLength = nativeMax(args.length - holdersLength, 0),
        rightIndex = -1,
        rightLength = partials.length,
        result = Array(argsLength + rightLength);
  
    while (++argsIndex < argsLength) {
      result[argsIndex] = args[argsIndex];
    }
    var pad = argsIndex;
    while (++rightIndex < rightLength) {
      result[pad + rightIndex] = partials[rightIndex];
    }
    while (++holdersIndex < holdersLength) {
      result[pad + holders[holdersIndex]] = args[argsIndex++];
    }
    return result;
  }
  
  module.exports = composeArgsRight;
  
  },{}],42:[function(require,module,exports){
  (function (global){
  var createCtorWrapper = require('./createCtorWrapper');
  
  /**
   * Creates a function that wraps `func` and invokes it with the `this`
   * binding of `thisArg`.
   *
   * @private
   * @param {Function} func The function to bind.
   * @param {*} [thisArg] The `this` binding of `func`.
   * @returns {Function} Returns the new bound function.
   */
  function createBindWrapper(func, thisArg) {
    var Ctor = createCtorWrapper(func);
  
    function wrapper() {
      var fn = (this && this !== global && this instanceof wrapper) ? Ctor : func;
      return fn.apply(thisArg, arguments);
    }
    return wrapper;
  }
  
  module.exports = createBindWrapper;
  
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
  },{"./createCtorWrapper":44}],43:[function(require,module,exports){
  (function (global){
  var SetCache = require('./SetCache'),
      constant = require('../utility/constant'),
      isNative = require('../lang/isNative');
  
  /** Native method references. */
  var Set = isNative(Set = global.Set) && Set;
  
  /* Native method references for those with the same name as other `lodash` methods. */
  var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate;
  
  /**
   * Creates a `Set` cache object to optimize linear searches of large arrays.
   *
   * @private
   * @param {Array} [values] The values to cache.
   * @returns {null|Object} Returns the new cache object if `Set` is supported, else `null`.
   */
  var createCache = !(nativeCreate && Set) ? constant(null) : function(values) {
    return new SetCache(values);
  };
  
  module.exports = createCache;
  
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
  },{"../lang/isNative":69,"../utility/constant":78,"./SetCache":15}],44:[function(require,module,exports){
  var baseCreate = require('./baseCreate'),
      isObject = require('../lang/isObject');
  
  /**
   * Creates a function that produces an instance of `Ctor` regardless of
   * whether it was invoked as part of a `new` expression or by `call` or `apply`.
   *
   * @private
   * @param {Function} Ctor The constructor to wrap.
   * @returns {Function} Returns the new wrapped function.
   */
  function createCtorWrapper(Ctor) {
    return function() {
      var thisBinding = baseCreate(Ctor.prototype),
          result = Ctor.apply(thisBinding, arguments);
  
      // Mimic the constructor's `return` behavior.
      // See https://es5.github.io/#x13.2.2 for more details.
      return isObject(result) ? result : thisBinding;
    };
  }
  
  module.exports = createCtorWrapper;
  
  },{"../lang/isObject":70,"./baseCreate":20}],45:[function(require,module,exports){
  (function (global){
  var arrayCopy = require('./arrayCopy'),
      composeArgs = require('./composeArgs'),
      composeArgsRight = require('./composeArgsRight'),
      createCtorWrapper = require('./createCtorWrapper'),
      reorder = require('./reorder'),
      replaceHolders = require('./replaceHolders');
  
  /** Used to compose bitmasks for wrapper metadata. */
  var BIND_FLAG = 1,
      BIND_KEY_FLAG = 2,
      CURRY_BOUND_FLAG = 4,
      CURRY_FLAG = 8,
      CURRY_RIGHT_FLAG = 16,
      PARTIAL_FLAG = 32,
      PARTIAL_RIGHT_FLAG = 64,
      ARY_FLAG = 256;
  
  /* Native method references for those with the same name as other `lodash` methods. */
  var nativeMax = Math.max;
  
  /**
   * Creates a function that wraps `func` and invokes it with optional `this`
   * binding of, partial application, and currying.
   *
   * @private
   * @param {Function|string} func The function or method name to reference.
   * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
   * @param {*} [thisArg] The `this` binding of `func`.
   * @param {Array} [partials] The arguments to prepend to those provided to the new function.
   * @param {Array} [holders] The `partials` placeholder indexes.
   * @param {Array} [partialsRight] The arguments to append to those provided to the new function.
   * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
   * @param {Array} [argPos] The argument positions of the new function.
   * @param {number} [ary] The arity cap of `func`.
   * @param {number} [arity] The arity of `func`.
   * @returns {Function} Returns the new wrapped function.
   */
  function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
    var isAry = bitmask & ARY_FLAG,
        isBind = bitmask & BIND_FLAG,
        isBindKey = bitmask & BIND_KEY_FLAG,
        isCurry = bitmask & CURRY_FLAG,
        isCurryBound = bitmask & CURRY_BOUND_FLAG,
        isCurryRight = bitmask & CURRY_RIGHT_FLAG;
  
    var Ctor = !isBindKey && createCtorWrapper(func),
        key = func;
  
    function wrapper() {
      // Avoid `arguments` object use disqualifying optimizations by
      // converting it to an array before providing it to other functions.
      var length = arguments.length,
          index = length,
          args = Array(length);
  
      while (index--) {
        args[index] = arguments[index];
      }
      if (partials) {
        args = composeArgs(args, partials, holders);
      }
      if (partialsRight) {
        args = composeArgsRight(args, partialsRight, holdersRight);
      }
      if (isCurry || isCurryRight) {
        var placeholder = wrapper.placeholder,
            argsHolders = replaceHolders(args, placeholder);
  
        length -= argsHolders.length;
        if (length < arity) {
          var newArgPos = argPos ? arrayCopy(argPos) : null,
              newArity = nativeMax(arity - length, 0),
              newsHolders = isCurry ? argsHolders : null,
              newHoldersRight = isCurry ? null : argsHolders,
              newPartials = isCurry ? args : null,
              newPartialsRight = isCurry ? null : args;
  
          bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG);
          bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG);
  
          if (!isCurryBound) {
            bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG);
          }
          var result = createHybridWrapper(func, bitmask, thisArg, newPartials, newsHolders, newPartialsRight, newHoldersRight, newArgPos, ary, newArity);
          result.placeholder = placeholder;
          return result;
        }
      }
      var thisBinding = isBind ? thisArg : this;
      if (isBindKey) {
        func = thisBinding[key];
      }
      if (argPos) {
        args = reorder(args, argPos);
      }
      if (isAry && ary < args.length) {
        args.length = ary;
      }
      var fn = (this && this !== global && this instanceof wrapper) ? (Ctor || createCtorWrapper(func)) : func;
      return fn.apply(thisBinding, args);
    }
    return wrapper;
  }
  
  module.exports = createHybridWrapper;
  
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
  },{"./arrayCopy":16,"./composeArgs":40,"./composeArgsRight":41,"./createCtorWrapper":44,"./reorder":60,"./replaceHolders":61}],46:[function(require,module,exports){
  (function (global){
  var createCtorWrapper = require('./createCtorWrapper');
  
  /** Used to compose bitmasks for wrapper metadata. */
  var BIND_FLAG = 1;
  
  /**
   * Creates a function that wraps `func` and invokes it with the optional `this`
   * binding of `thisArg` and the `partials` prepended to those provided to
   * the wrapper.
   *
   * @private
   * @param {Function} func The function to partially apply arguments to.
   * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
   * @param {*} thisArg The `this` binding of `func`.
   * @param {Array} partials The arguments to prepend to those provided to the new function.
   * @returns {Function} Returns the new bound function.
   */
  function createPartialWrapper(func, bitmask, thisArg, partials) {
    var isBind = bitmask & BIND_FLAG,
        Ctor = createCtorWrapper(func);
  
    function wrapper() {
      // Avoid `arguments` object use disqualifying optimizations by
      // converting it to an array before providing it `func`.
      var argsIndex = -1,
          argsLength = arguments.length,
          leftIndex = -1,
          leftLength = partials.length,
          args = Array(argsLength + leftLength);
  
      while (++leftIndex < leftLength) {
        args[leftIndex] = partials[leftIndex];
      }
      while (argsLength--) {
        args[leftIndex++] = arguments[++argsIndex];
      }
      var fn = (this && this !== global && this instanceof wrapper) ? Ctor : func;
      return fn.apply(isBind ? thisArg : this, args);
    }
    return wrapper;
  }
  
  module.exports = createPartialWrapper;
  
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
  },{"./createCtorWrapper":44}],47:[function(require,module,exports){
  var baseSetData = require('./baseSetData'),
      createBindWrapper = require('./createBindWrapper'),
      createHybridWrapper = require('./createHybridWrapper'),
      createPartialWrapper = require('./createPartialWrapper'),
      getData = require('./getData'),
      mergeData = require('./mergeData'),
      setData = require('./setData');
  
  /** Used to compose bitmasks for wrapper metadata. */
  var BIND_FLAG = 1,
      BIND_KEY_FLAG = 2,
      PARTIAL_FLAG = 32,
      PARTIAL_RIGHT_FLAG = 64;
  
  /** Used as the `TypeError` message for "Functions" methods. */
  var FUNC_ERROR_TEXT = 'Expected a function';
  
  /* Native method references for those with the same name as other `lodash` methods. */
  var nativeMax = Math.max;
  
  /**
   * Creates a function that either curries or invokes `func` with optional
   * `this` binding and partially applied arguments.
   *
   * @private
   * @param {Function|string} func The function or method name to reference.
   * @param {number} bitmask The bitmask of flags.
   *  The bitmask may be composed of the following flags:
   *     1 - `_.bind`
   *     2 - `_.bindKey`
   *     4 - `_.curry` or `_.curryRight` of a bound function
   *     8 - `_.curry`
   *    16 - `_.curryRight`
   *    32 - `_.partial`
   *    64 - `_.partialRight`
   *   128 - `_.rearg`
   *   256 - `_.ary`
   * @param {*} [thisArg] The `this` binding of `func`.
   * @param {Array} [partials] The arguments to be partially applied.
   * @param {Array} [holders] The `partials` placeholder indexes.
   * @param {Array} [argPos] The argument positions of the new function.
   * @param {number} [ary] The arity cap of `func`.
   * @param {number} [arity] The arity of `func`.
   * @returns {Function} Returns the new wrapped function.
   */
  function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
    var isBindKey = bitmask & BIND_KEY_FLAG;
    if (!isBindKey && typeof func != 'function') {
      throw new TypeError(FUNC_ERROR_TEXT);
    }
    var length = partials ? partials.length : 0;
    if (!length) {
      bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG);
      partials = holders = null;
    }
    length -= (holders ? holders.length : 0);
    if (bitmask & PARTIAL_RIGHT_FLAG) {
      var partialsRight = partials,
          holdersRight = holders;
  
      partials = holders = null;
    }
    var data = !isBindKey && getData(func),
        newData = [func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity];
  
    if (data && data !== true) {
      mergeData(newData, data);
      bitmask = newData[1];
      arity = newData[9];
    }
    newData[9] = arity == null
      ? (isBindKey ? 0 : func.length)
      : (nativeMax(arity - length, 0) || 0);
  
    if (bitmask == BIND_FLAG) {
      var result = createBindWrapper(newData[0], newData[2]);
    } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) {
      result = createPartialWrapper.apply(undefined, newData);
    } else {
      result = createHybridWrapper.apply(undefined, newData);
    }
    var setter = data ? baseSetData : setData;
    return setter(result, newData);
  }
  
  module.exports = createWrapper;
  
  },{"./baseSetData":34,"./createBindWrapper":42,"./createHybridWrapper":45,"./createPartialWrapper":46,"./getData":51,"./mergeData":58,"./setData":62}],48:[function(require,module,exports){
  /**
   * A specialized version of `baseIsEqualDeep` for arrays with support for
   * partial deep comparisons.
   *
   * @private
   * @param {Array} array The array to compare.
   * @param {Array} other The other array to compare.
   * @param {Function} equalFunc The function to determine equivalents of values.
   * @param {Function} [customizer] The function to customize comparing arrays.
   * @param {boolean} [isWhere] Specify performing partial comparisons.
   * @param {Array} [stackA] Tracks traversed `value` objects.
   * @param {Array} [stackB] Tracks traversed `other` objects.
   * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
   */
  function equalArrays(array, other, equalFunc, customizer, isWhere, stackA, stackB) {
    var index = -1,
        arrLength = array.length,
        othLength = other.length,
        result = true;
  
    if (arrLength != othLength && !(isWhere && othLength > arrLength)) {
      return false;
    }
    // Deep compare the contents, ignoring non-numeric properties.
    while (result && ++index < arrLength) {
      var arrValue = array[index],
          othValue = other[index];
  
      result = undefined;
      if (customizer) {
        result = isWhere
          ? customizer(othValue, arrValue, index)
          : customizer(arrValue, othValue, index);
      }
      if (typeof result == 'undefined') {
        // Recursively compare arrays (susceptible to call stack limits).
        if (isWhere) {
          var othIndex = othLength;
          while (othIndex--) {
            othValue = other[othIndex];
            result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isWhere, stackA, stackB);
            if (result) {
              break;
            }
          }
        } else {
          result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isWhere, stackA, stackB);
        }
      }
    }
    return !!result;
  }
  
  module.exports = equalArrays;
  
  },{}],49:[function(require,module,exports){
  /** `Object#toString` result references. */
  var boolTag = '[object Boolean]',
      dateTag = '[object Date]',
      errorTag = '[object Error]',
      numberTag = '[object Number]',
      regexpTag = '[object RegExp]',
      stringTag = '[object String]';
  
  /**
   * A specialized version of `baseIsEqualDeep` for comparing objects of
   * the same `toStringTag`.
   *
   * **Note:** This function only supports comparing values with tags of
   * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
   *
   * @private
   * @param {Object} value The object to compare.
   * @param {Object} other The other object to compare.
   * @param {string} tag The `toStringTag` of the objects to compare.
   * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
   */
  function equalByTag(object, other, tag) {
    switch (tag) {
      case boolTag:
      case dateTag:
        // Coerce dates and booleans to numbers, dates to milliseconds and booleans
        // to `1` or `0` treating invalid dates coerced to `NaN` as not equal.
        return +object == +other;
  
      case errorTag:
        return object.name == other.name && object.message == other.message;
  
      case numberTag:
        // Treat `NaN` vs. `NaN` as equal.
        return (object != +object)
          ? other != +other
          // But, treat `-0` vs. `+0` as not equal.
          : (object == 0 ? ((1 / object) == (1 / other)) : object == +other);
  
      case regexpTag:
      case stringTag:
        // Coerce regexes to strings and treat strings primitives and string
        // objects as equal. See https://es5.github.io/#x15.10.6.4 for more details.
        return object == (other + '');
    }
    return false;
  }
  
  module.exports = equalByTag;
  
  },{}],50:[function(require,module,exports){
  var keys = require('../object/keys');
  
  /** Used for native method references. */
  var objectProto = Object.prototype;
  
  /** Used to check objects for own properties. */
  var hasOwnProperty = objectProto.hasOwnProperty;
  
  /**
   * A specialized version of `baseIsEqualDeep` for objects with support for
   * partial deep comparisons.
   *
   * @private
   * @param {Object} object The object to compare.
   * @param {Object} other The other object to compare.
   * @param {Function} equalFunc The function to determine equivalents of values.
   * @param {Function} [customizer] The function to customize comparing values.
   * @param {boolean} [isWhere] Specify performing partial comparisons.
   * @param {Array} [stackA] Tracks traversed `value` objects.
   * @param {Array} [stackB] Tracks traversed `other` objects.
   * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
   */
  function equalObjects(object, other, equalFunc, customizer, isWhere, stackA, stackB) {
    var objProps = keys(object),
        objLength = objProps.length,
        othProps = keys(other),
        othLength = othProps.length;
  
    if (objLength != othLength && !isWhere) {
      return false;
    }
    var hasCtor,
        index = -1;
  
    while (++index < objLength) {
      var key = objProps[index],
          result = hasOwnProperty.call(other, key);
  
      if (result) {
        var objValue = object[key],
            othValue = other[key];
  
        result = undefined;
        if (customizer) {
          result = isWhere
            ? customizer(othValue, objValue, key)
            : customizer(objValue, othValue, key);
        }
        if (typeof result == 'undefined') {
          // Recursively compare objects (susceptible to call stack limits).
          result = (objValue && objValue === othValue) || equalFunc(objValue, othValue, customizer, isWhere, stackA, stackB);
        }
      }
      if (!result) {
        return false;
      }
      hasCtor || (hasCtor = key == 'constructor');
    }
    if (!hasCtor) {
      var objCtor = object.constructor,
          othCtor = other.constructor;
  
      // Non `Object` object instances with different constructors are not equal.
      if (objCtor != othCtor &&
          ('constructor' in object && 'constructor' in other) &&
          !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
            typeof othCtor == 'function' && othCtor instanceof othCtor)) {
        return false;
      }
    }
    return true;
  }
  
  module.exports = equalObjects;
  
  },{"../object/keys":74}],51:[function(require,module,exports){
  var metaMap = require('./metaMap'),
      noop = require('../utility/noop');
  
  /**
   * Gets metadata for `func`.
   *
   * @private
   * @param {Function} func The function to query.
   * @returns {*} Returns the metadata for `func`.
   */
  var getData = !metaMap ? noop : function(func) {
    return metaMap.get(func);
  };
  
  module.exports = getData;
  
  },{"../utility/noop":80,"./metaMap":59}],52:[function(require,module,exports){
  /**
   * Gets the index at which the first occurrence of `NaN` is found in `array`.
   * If `fromRight` is provided elements of `array` are iterated from right to left.
   *
   * @private
   * @param {Array} array The array to search.
   * @param {number} fromIndex The index to search from.
   * @param {boolean} [fromRight] Specify iterating from right to left.
   * @returns {number} Returns the index of the matched `NaN`, else `-1`.
   */
  function indexOfNaN(array, fromIndex, fromRight) {
    var length = array.length,
        index = fromIndex + (fromRight ? 0 : -1);
  
    while ((fromRight ? index-- : ++index < length)) {
      var other = array[index];
      if (other !== other) {
        return index;
      }
    }
    return -1;
  }
  
  module.exports = indexOfNaN;
  
  },{}],53:[function(require,module,exports){
  var baseSetData = require('./baseSetData'),
      isNative = require('../lang/isNative'),
      support = require('../support');
  
  /** Used to detect named functions. */
  var reFuncName = /^\s*function[ \n\r\t]+\w/;
  
  /** Used to detect functions containing a `this` reference. */
  var reThis = /\bthis\b/;
  
  /** Used to resolve the decompiled source of functions. */
  var fnToString = Function.prototype.toString;
  
  /**
   * Checks if `func` is eligible for `this` binding.
   *
   * @private
   * @param {Function} func The function to check.
   * @returns {boolean} Returns `true` if `func` is eligible, else `false`.
   */
  function isBindable(func) {
    var result = !(support.funcNames ? func.name : support.funcDecomp);
  
    if (!result) {
      var source = fnToString.call(func);
      if (!support.funcNames) {
        result = !reFuncName.test(source);
      }
      if (!result) {
        // Check if `func` references the `this` keyword and store the result.
        result = reThis.test(source) || isNative(func);
        baseSetData(func, result);
      }
    }
    return result;
  }
  
  module.exports = isBindable;
  
  },{"../lang/isNative":69,"../support":77,"./baseSetData":34}],54:[function(require,module,exports){
  /**
   * Used as the maximum length of an array-like value.
   * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer)
   * for more details.
   */
  var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1;
  
  /**
   * Checks if `value` is a valid array-like index.
   *
   * @private
   * @param {*} value The value to check.
   * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
   * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
   */
  function isIndex(value, length) {
    value = +value;
    length = length == null ? MAX_SAFE_INTEGER : length;
    return value > -1 && value % 1 == 0 && value < length;
  }
  
  module.exports = isIndex;
  
  },{}],55:[function(require,module,exports){
  /**
   * Used as the maximum length of an array-like value.
   * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer)
   * for more details.
   */
  var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1;
  
  /**
   * Checks if `value` is a valid array-like length.
   *
   * **Note:** This function is based on ES `ToLength`. See the
   * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength)
   * for more details.
   *
   * @private
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
   */
  function isLength(value) {
    return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
  }
  
  module.exports = isLength;
  
  },{}],56:[function(require,module,exports){
  /**
   * Checks if `value` is object-like.
   *
   * @private
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
   */
  function isObjectLike(value) {
    return (value && typeof value == 'object') || false;
  }
  
  module.exports = isObjectLike;
  
  },{}],57:[function(require,module,exports){
  var isObject = require('../lang/isObject');
  
  /**
   * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
   *
   * @private
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` if suitable for strict
   *  equality comparisons, else `false`.
   */
  function isStrictComparable(value) {
    return value === value && (value === 0 ? ((1 / value) > 0) : !isObject(value));
  }
  
  module.exports = isStrictComparable;
  
  },{"../lang/isObject":70}],58:[function(require,module,exports){
  var arrayCopy = require('./arrayCopy'),
      composeArgs = require('./composeArgs'),
      composeArgsRight = require('./composeArgsRight'),
      replaceHolders = require('./replaceHolders');
  
  /** Used to compose bitmasks for wrapper metadata. */
  var BIND_FLAG = 1,
      BIND_KEY_FLAG = 2,
      CURRY_BOUND_FLAG = 4,
      CURRY_RIGHT_FLAG = 16,
      REARG_FLAG = 128,
      ARY_FLAG = 256;
  
  /** Used as the internal argument placeholder. */
  var PLACEHOLDER = '__lodash_placeholder__';
  
  /* Native method references for those with the same name as other `lodash` methods. */
  var nativeMin = Math.min;
  
  /**
   * Merges the function metadata of `source` into `data`.
   *
   * Merging metadata reduces the number of wrappers required to invoke a function.
   * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
   * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg`
   * augment function arguments, making the order in which they are executed important,
   * preventing the merging of metadata. However, we make an exception for a safe
   * common case where curried functions have `_.ary` and or `_.rearg` applied.
   *
   * @private
   * @param {Array} data The destination metadata.
   * @param {Array} source The source metadata.
   * @returns {Array} Returns `data`.
   */
  function mergeData(data, source) {
    var bitmask = data[1],
        srcBitmask = source[1],
        newBitmask = bitmask | srcBitmask;
  
    var arityFlags = ARY_FLAG | REARG_FLAG,
        bindFlags = BIND_FLAG | BIND_KEY_FLAG,
        comboFlags = arityFlags | bindFlags | CURRY_BOUND_FLAG | CURRY_RIGHT_FLAG;
  
    var isAry = bitmask & ARY_FLAG && !(srcBitmask & ARY_FLAG),
        isRearg = bitmask & REARG_FLAG && !(srcBitmask & REARG_FLAG),
        argPos = (isRearg ? data : source)[7],
        ary = (isAry ? data : source)[8];
  
    var isCommon = !(bitmask >= REARG_FLAG && srcBitmask > bindFlags) &&
      !(bitmask > bindFlags && srcBitmask >= REARG_FLAG);
  
    var isCombo = (newBitmask >= arityFlags && newBitmask <= comboFlags) &&
      (bitmask < REARG_FLAG || ((isRearg || isAry) && argPos.length <= ary));
  
    // Exit early if metadata can't be merged.
    if (!(isCommon || isCombo)) {
      return data;
    }
    // Use source `thisArg` if available.
    if (srcBitmask & BIND_FLAG) {
      data[2] = source[2];
      // Set when currying a bound function.
      newBitmask |= (bitmask & BIND_FLAG) ? 0 : CURRY_BOUND_FLAG;
    }
    // Compose partial arguments.
    var value = source[3];
    if (value) {
      var partials = data[3];
      data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value);
      data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]);
    }
    // Compose partial right arguments.
    value = source[5];
    if (value) {
      partials = data[5];
      data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value);
      data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]);
    }
    // Use source `argPos` if available.
    value = source[7];
    if (value) {
      data[7] = arrayCopy(value);
    }
    // Use source `ary` if it's smaller.
    if (srcBitmask & ARY_FLAG) {
      data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
    }
    // Use source `arity` if one is not provided.
    if (data[9] == null) {
      data[9] = source[9];
    }
    // Use source `func` and merge bitmasks.
    data[0] = source[0];
    data[1] = newBitmask;
  
    return data;
  }
  
  module.exports = mergeData;
  
  },{"./arrayCopy":16,"./composeArgs":40,"./composeArgsRight":41,"./replaceHolders":61}],59:[function(require,module,exports){
  (function (global){
  var isNative = require('../lang/isNative');
  
  /** Native method references. */
  var WeakMap = isNative(WeakMap = global.WeakMap) && WeakMap;
  
  /** Used to store function metadata. */
  var metaMap = WeakMap && new WeakMap;
  
  module.exports = metaMap;
  
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
  },{"../lang/isNative":69}],60:[function(require,module,exports){
  var arrayCopy = require('./arrayCopy'),
      isIndex = require('./isIndex');
  
  /* Native method references for those with the same name as other `lodash` methods. */
  var nativeMin = Math.min;
  
  /**
   * Reorder `array` according to the specified indexes where the element at
   * the first index is assigned as the first element, the element at
   * the second index is assigned as the second element, and so on.
   *
   * @private
   * @param {Array} array The array to reorder.
   * @param {Array} indexes The arranged array indexes.
   * @returns {Array} Returns `array`.
   */
  function reorder(array, indexes) {
    var arrLength = array.length,
        length = nativeMin(indexes.length, arrLength),
        oldArray = arrayCopy(array);
  
    while (length--) {
      var index = indexes[length];
      array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
    }
    return array;
  }
  
  module.exports = reorder;
  
  },{"./arrayCopy":16,"./isIndex":54}],61:[function(require,module,exports){
  /** Used as the internal argument placeholder. */
  var PLACEHOLDER = '__lodash_placeholder__';
  
  /**
   * Replaces all `placeholder` elements in `array` with an internal placeholder
   * and returns an array of their indexes.
   *
   * @private
   * @param {Array} array The array to modify.
   * @param {*} placeholder The placeholder to replace.
   * @returns {Array} Returns the new array of placeholder indexes.
   */
  function replaceHolders(array, placeholder) {
    var index = -1,
        length = array.length,
        resIndex = -1,
        result = [];
  
    while (++index < length) {
      if (array[index] === placeholder) {
        array[index] = PLACEHOLDER;
        result[++resIndex] = index;
      }
    }
    return result;
  }
  
  module.exports = replaceHolders;
  
  },{}],62:[function(require,module,exports){
  var baseSetData = require('./baseSetData'),
      now = require('../date/now');
  
  /** Used to detect when a function becomes hot. */
  var HOT_COUNT = 150,
      HOT_SPAN = 16;
  
  /**
   * Sets metadata for `func`.
   *
   * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
   * period of time, it will trip its breaker and transition to an identity function
   * to avoid garbage collection pauses in V8. See [V8 issue 2070](https://code.google.com/p/v8/issues/detail?id=2070)
   * for more details.
   *
   * @private
   * @param {Function} func The function to associate metadata with.
   * @param {*} data The metadata.
   * @returns {Function} Returns `func`.
   */
  var setData = (function() {
    var count = 0,
        lastCalled = 0;
  
    return function(key, value) {
      var stamp = now(),
          remaining = HOT_SPAN - (stamp - lastCalled);
  
      lastCalled = stamp;
      if (remaining > 0) {
        if (++count >= HOT_COUNT) {
          return key;
        }
      } else {
        count = 0;
      }
      return baseSetData(key, value);
    };
  }());
  
  module.exports = setData;
  
  },{"../date/now":13,"./baseSetData":34}],63:[function(require,module,exports){
  var isArguments = require('../lang/isArguments'),
      isArray = require('../lang/isArray'),
      isIndex = require('./isIndex'),
      isLength = require('./isLength'),
      keysIn = require('../object/keysIn'),
      support = require('../support');
  
  /** Used for native method references. */
  var objectProto = Object.prototype;
  
  /** Used to check objects for own properties. */
  var hasOwnProperty = objectProto.hasOwnProperty;
  
  /**
   * A fallback implementation of `Object.keys` which creates an array of the
   * own enumerable property names of `object`.
   *
   * @private
   * @param {Object} object The object to inspect.
   * @returns {Array} Returns the array of property names.
   */
  function shimKeys(object) {
    var props = keysIn(object),
        propsLength = props.length,
        length = propsLength && object.length;
  
    var allowIndexes = length && isLength(length) &&
      (isArray(object) || (support.nonEnumArgs && isArguments(object)));
  
    var index = -1,
        result = [];
  
    while (++index < propsLength) {
      var key = props[index];
      if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
        result.push(key);
      }
    }
    return result;
  }
  
  module.exports = shimKeys;
  
  },{"../lang/isArguments":65,"../lang/isArray":66,"../object/keysIn":75,"../support":77,"./isIndex":54,"./isLength":55}],64:[function(require,module,exports){
  var isObject = require('../lang/isObject');
  
  /**
   * Converts `value` to an object if it is not one.
   *
   * @private
   * @param {*} value The value to process.
   * @returns {Object} Returns the object.
   */
  function toObject(value) {
    return isObject(value) ? value : Object(value);
  }
  
  module.exports = toObject;
  
  },{"../lang/isObject":70}],65:[function(require,module,exports){
  var isLength = require('../internal/isLength'),
      isObjectLike = require('../internal/isObjectLike');
  
  /** `Object#toString` result references. */
  var argsTag = '[object Arguments]';
  
  /** Used for native method references. */
  var objectProto = Object.prototype;
  
  /**
   * Used to resolve the `toStringTag` of values.
   * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring)
   * for more details.
   */
  var objToString = objectProto.toString;
  
  /**
   * Checks if `value` is classified as an `arguments` object.
   *
   * @static
   * @memberOf _
   * @category Lang
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
   * @example
   *
   * _.isArguments(function() { return arguments; }());
   * // => true
   *
   * _.isArguments([1, 2, 3]);
   * // => false
   */
  function isArguments(value) {
    var length = isObjectLike(value) ? value.length : undefined;
    return (isLength(length) && objToString.call(value) == argsTag) || false;
  }
  
  module.exports = isArguments;
  
  },{"../internal/isLength":55,"../internal/isObjectLike":56}],66:[function(require,module,exports){
  var isLength = require('../internal/isLength'),
      isNative = require('./isNative'),
      isObjectLike = require('../internal/isObjectLike');
  
  /** `Object#toString` result references. */
  var arrayTag = '[object Array]';
  
  /** Used for native method references. */
  var objectProto = Object.prototype;
  
  /**
   * Used to resolve the `toStringTag` of values.
   * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring)
   * for more details.
   */
  var objToString = objectProto.toString;
  
  /* Native method references for those with the same name as other `lodash` methods. */
  var nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray;
  
  /**
   * Checks if `value` is classified as an `Array` object.
   *
   * @static
   * @memberOf _
   * @category Lang
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
   * @example
   *
   * _.isArray([1, 2, 3]);
   * // => true
   *
   * _.isArray(function() { return arguments; }());
   * // => false
   */
  var isArray = nativeIsArray || function(value) {
    return (isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag) || false;
  };
  
  module.exports = isArray;
  
  },{"../internal/isLength":55,"../internal/isObjectLike":56,"./isNative":69}],67:[function(require,module,exports){
  var isArguments = require('./isArguments'),
      isArray = require('./isArray'),
      isFunction = require('./isFunction'),
      isLength = require('../internal/isLength'),
      isObjectLike = require('../internal/isObjectLike'),
      isString = require('./isString'),
      keys = require('../object/keys');
  
  /**
   * Checks if `value` is empty. A value is considered empty unless it is an
   * `arguments` object, array, string, or jQuery-like collection with a length
   * greater than `0` or an object with own enumerable properties.
   *
   * @static
   * @memberOf _
   * @category Lang
   * @param {Array|Object|string} value The value to inspect.
   * @returns {boolean} Returns `true` if `value` is empty, else `false`.
   * @example
   *
   * _.isEmpty(null);
   * // => true
   *
   * _.isEmpty(true);
   * // => true
   *
   * _.isEmpty(1);
   * // => true
   *
   * _.isEmpty([1, 2, 3]);
   * // => false
   *
   * _.isEmpty({ 'a': 1 });
   * // => false
   */
  function isEmpty(value) {
    if (value == null) {
      return true;
    }
    var length = value.length;
    if (isLength(length) && (isArray(value) || isString(value) || isArguments(value) ||
        (isObjectLike(value) && isFunction(value.splice)))) {
      return !length;
    }
    return !keys(value).length;
  }
  
  module.exports = isEmpty;
  
  },{"../internal/isLength":55,"../internal/isObjectLike":56,"../object/keys":74,"./isArguments":65,"./isArray":66,"./isFunction":68,"./isString":71}],68:[function(require,module,exports){
  (function (global){
  var baseIsFunction = require('../internal/baseIsFunction'),
      isNative = require('./isNative');
  
  /** `Object#toString` result references. */
  var funcTag = '[object Function]';
  
  /** Used for native method references. */
  var objectProto = Object.prototype;
  
  /**
   * Used to resolve the `toStringTag` of values.
   * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring)
   * for more details.
   */
  var objToString = objectProto.toString;
  
  /** Native method references. */
  var Uint8Array = isNative(Uint8Array = global.Uint8Array) && Uint8Array;
  
  /**
   * Checks if `value` is classified as a `Function` object.
   *
   * @static
   * @memberOf _
   * @category Lang
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
   * @example
   *
   * _.isFunction(_);
   * // => true
   *
   * _.isFunction(/abc/);
   * // => false
   */
  var isFunction = !(baseIsFunction(/x/) || (Uint8Array && !baseIsFunction(Uint8Array))) ? baseIsFunction : function(value) {
    // The use of `Object#toString` avoids issues with the `typeof` operator
    // in older versions of Chrome and Safari which return 'function' for regexes
    // and Safari 8 equivalents which return 'object' for typed array constructors.
    return objToString.call(value) == funcTag;
  };
  
  module.exports = isFunction;
  
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
  },{"../internal/baseIsFunction":28,"./isNative":69}],69:[function(require,module,exports){
  var escapeRegExp = require('../string/escapeRegExp'),
      isObjectLike = require('../internal/isObjectLike');
  
  /** `Object#toString` result references. */
  var funcTag = '[object Function]';
  
  /** Used to detect host constructors (Safari > 5). */
  var reHostCtor = /^\[object .+?Constructor\]$/;
  
  /** Used for native method references. */
  var objectProto = Object.prototype;
  
  /** Used to resolve the decompiled source of functions. */
  var fnToString = Function.prototype.toString;
  
  /**
   * Used to resolve the `toStringTag` of values.
   * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring)
   * for more details.
   */
  var objToString = objectProto.toString;
  
  /** Used to detect if a method is native. */
  var reNative = RegExp('^' +
    escapeRegExp(objToString)
    .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
  );
  
  /**
   * Checks if `value` is a native function.
   *
   * @static
   * @memberOf _
   * @category Lang
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is a native function, else `false`.
   * @example
   *
   * _.isNative(Array.prototype.push);
   * // => true
   *
   * _.isNative(_);
   * // => false
   */
  function isNative(value) {
    if (value == null) {
      return false;
    }
    if (objToString.call(value) == funcTag) {
      return reNative.test(fnToString.call(value));
    }
    return (isObjectLike(value) && reHostCtor.test(value)) || false;
  }
  
  module.exports = isNative;
  
  },{"../internal/isObjectLike":56,"../string/escapeRegExp":76}],70:[function(require,module,exports){
  /**
   * Checks if `value` is the language type of `Object`.
   * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
   *
   * **Note:** See the [ES5 spec](https://es5.github.io/#x8) for more details.
   *
   * @static
   * @memberOf _
   * @category Lang
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is an object, else `false`.
   * @example
   *
   * _.isObject({});
   * // => true
   *
   * _.isObject([1, 2, 3]);
   * // => true
   *
   * _.isObject(1);
   * // => false
   */
  function isObject(value) {
    // Avoid a V8 JIT bug in Chrome 19-20.
    // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
    var type = typeof value;
    return type == 'function' || (value && type == 'object') || false;
  }
  
  module.exports = isObject;
  
  },{}],71:[function(require,module,exports){
  var isObjectLike = require('../internal/isObjectLike');
  
  /** `Object#toString` result references. */
  var stringTag = '[object String]';
  
  /** Used for native method references. */
  var objectProto = Object.prototype;
  
  /**
   * Used to resolve the `toStringTag` of values.
   * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring)
   * for more details.
   */
  var objToString = objectProto.toString;
  
  /**
   * Checks if `value` is classified as a `String` primitive or object.
   *
   * @static
   * @memberOf _
   * @category Lang
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
   * @example
   *
   * _.isString('abc');
   * // => true
   *
   * _.isString(1);
   * // => false
   */
  function isString(value) {
    return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag) || false;
  }
  
  module.exports = isString;
  
  },{"../internal/isObjectLike":56}],72:[function(require,module,exports){
  var isLength = require('../internal/isLength'),
      isObjectLike = require('../internal/isObjectLike');
  
  /** `Object#toString` result references. */
  var argsTag = '[object Arguments]',
      arrayTag = '[object Array]',
      boolTag = '[object Boolean]',
      dateTag = '[object Date]',
      errorTag = '[object Error]',
      funcTag = '[object Function]',
      mapTag = '[object Map]',
      numberTag = '[object Number]',
      objectTag = '[object Object]',
      regexpTag = '[object RegExp]',
      setTag = '[object Set]',
      stringTag = '[object String]',
      weakMapTag = '[object WeakMap]';
  
  var arrayBufferTag = '[object ArrayBuffer]',
      float32Tag = '[object Float32Array]',
      float64Tag = '[object Float64Array]',
      int8Tag = '[object Int8Array]',
      int16Tag = '[object Int16Array]',
      int32Tag = '[object Int32Array]',
      uint8Tag = '[object Uint8Array]',
      uint8ClampedTag = '[object Uint8ClampedArray]',
      uint16Tag = '[object Uint16Array]',
      uint32Tag = '[object Uint32Array]';
  
  /** Used to identify `toStringTag` values of typed arrays. */
  var typedArrayTags = {};
  typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
  typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
  typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
  typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
  typedArrayTags[uint32Tag] = true;
  typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
  typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
  typedArrayTags[dateTag] = typedArrayTags[errorTag] =
  typedArrayTags[funcTag] = typedArrayTags[mapTag] =
  typedArrayTags[numberTag] = typedArrayTags[objectTag] =
  typedArrayTags[regexpTag] = typedArrayTags[setTag] =
  typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;
  
  /** Used for native method references. */
  var objectProto = Object.prototype;
  
  /**
   * Used to resolve the `toStringTag` of values.
   * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring)
   * for more details.
   */
  var objToString = objectProto.toString;
  
  /**
   * Checks if `value` is classified as a typed array.
   *
   * @static
   * @memberOf _
   * @category Lang
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
   * @example
   *
   * _.isTypedArray(new Uint8Array);
   * // => true
   *
   * _.isTypedArray([]);
   * // => false
   */
  function isTypedArray(value) {
    return (isObjectLike(value) && isLength(value.length) && typedArrayTags[objToString.call(value)]) || false;
  }
  
  module.exports = isTypedArray;
  
  },{"../internal/isLength":55,"../internal/isObjectLike":56}],73:[function(require,module,exports){
  /**
   * Checks if `value` is `undefined`.
   *
   * @static
   * @memberOf _
   * @category Lang
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
   * @example
   *
   * _.isUndefined(void 0);
   * // => true
   *
   * _.isUndefined(null);
   * // => false
   */
  function isUndefined(value) {
    return typeof value == 'undefined';
  }
  
  module.exports = isUndefined;
  
  },{}],74:[function(require,module,exports){
  var isLength = require('../internal/isLength'),
      isNative = require('../lang/isNative'),
      isObject = require('../lang/isObject'),
      shimKeys = require('../internal/shimKeys');
  
  /* Native method references for those with the same name as other `lodash` methods. */
  var nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys;
  
  /**
   * Creates an array of the own enumerable property names of `object`.
   *
   * **Note:** Non-object values are coerced to objects. See the
   * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.keys)
   * for more details.
   *
   * @static
   * @memberOf _
   * @category Object
   * @param {Object} object The object to inspect.
   * @returns {Array} Returns the array of property names.
   * @example
   *
   * function Foo() {
   *   this.a = 1;
   *   this.b = 2;
   * }
   *
   * Foo.prototype.c = 3;
   *
   * _.keys(new Foo);
   * // => ['a', 'b'] (iteration order is not guaranteed)
   *
   * _.keys('hi');
   * // => ['0', '1']
   */
  var keys = !nativeKeys ? shimKeys : function(object) {
    if (object) {
      var Ctor = object.constructor,
          length = object.length;
    }
    if ((typeof Ctor == 'function' && Ctor.prototype === object) ||
        (typeof object != 'function' && (length && isLength(length)))) {
      return shimKeys(object);
    }
    return isObject(object) ? nativeKeys(object) : [];
  };
  
  module.exports = keys;
  
  },{"../internal/isLength":55,"../internal/shimKeys":63,"../lang/isNative":69,"../lang/isObject":70}],75:[function(require,module,exports){
  var isArguments = require('../lang/isArguments'),
      isArray = require('../lang/isArray'),
      isIndex = require('../internal/isIndex'),
      isLength = require('../internal/isLength'),
      isObject = require('../lang/isObject'),
      support = require('../support');
  
  /** Used for native method references. */
  var objectProto = Object.prototype;
  
  /** Used to check objects for own properties. */
  var hasOwnProperty = objectProto.hasOwnProperty;
  
  /**
   * Creates an array of the own and inherited enumerable property names of `object`.
   *
   * **Note:** Non-object values are coerced to objects.
   *
   * @static
   * @memberOf _
   * @category Object
   * @param {Object} object The object to inspect.
   * @returns {Array} Returns the array of property names.
   * @example
   *
   * function Foo() {
   *   this.a = 1;
   *   this.b = 2;
   * }
   *
   * Foo.prototype.c = 3;
   *
   * _.keysIn(new Foo);
   * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
   */
  function keysIn(object) {
    if (object == null) {
      return [];
    }
    if (!isObject(object)) {
      object = Object(object);
    }
    var length = object.length;
    length = (length && isLength(length) &&
      (isArray(object) || (support.nonEnumArgs && isArguments(object))) && length) || 0;
  
    var Ctor = object.constructor,
        index = -1,
        isProto = typeof Ctor == 'function' && Ctor.prototype === object,
        result = Array(length),
        skipIndexes = length > 0;
  
    while (++index < length) {
      result[index] = (index + '');
    }
    for (var key in object) {
      if (!(skipIndexes && isIndex(key, length)) &&
          !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
        result.push(key);
      }
    }
    return result;
  }
  
  module.exports = keysIn;
  
  },{"../internal/isIndex":54,"../internal/isLength":55,"../lang/isArguments":65,"../lang/isArray":66,"../lang/isObject":70,"../support":77}],76:[function(require,module,exports){
  var baseToString = require('../internal/baseToString');
  
  /**
   * Used to match `RegExp` special characters.
   * See this [article on `RegExp` characters](http://www.regular-expressions.info/characters.html#special)
   * for more details.
   */
  var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g,
      reHasRegExpChars = RegExp(reRegExpChars.source);
  
  /**
   * Escapes the `RegExp` special characters "\", "^", "$", ".", "|", "?", "*",
   * "+", "(", ")", "[", "]", "{" and "}" in `string`.
   *
   * @static
   * @memberOf _
   * @category String
   * @param {string} [string=''] The string to escape.
   * @returns {string} Returns the escaped string.
   * @example
   *
   * _.escapeRegExp('[lodash](https://lodash.com/)');
   * // => '\[lodash\]\(https://lodash\.com/\)'
   */
  function escapeRegExp(string) {
    string = baseToString(string);
    return (string && reHasRegExpChars.test(string))
      ? string.replace(reRegExpChars, '\\$&')
      : string;
  }
  
  module.exports = escapeRegExp;
  
  },{"../internal/baseToString":36}],77:[function(require,module,exports){
  (function (global){
  var isNative = require('./lang/isNative');
  
  /** Used to detect functions containing a `this` reference. */
  var reThis = /\bthis\b/;
  
  /** Used for native method references. */
  var objectProto = Object.prototype;
  
  /** Used to detect DOM support. */
  var document = (document = global.window) && document.document;
  
  /** Native method references. */
  var propertyIsEnumerable = objectProto.propertyIsEnumerable;
  
  /**
   * An object environment feature flags.
   *
   * @static
   * @memberOf _
   * @type Object
   */
  var support = {};
  
  (function(x) {
  
    /**
     * Detect if functions can be decompiled by `Function#toString`
     * (all but Firefox OS certified apps, older Opera mobile browsers, and
     * the PlayStation 3; forced `false` for Windows 8 apps).
     *
     * @memberOf _.support
     * @type boolean
     */
    support.funcDecomp = !isNative(global.WinRTError) && reThis.test(function() { return this; });
  
    /**
     * Detect if `Function#name` is supported (all but IE).
     *
     * @memberOf _.support
     * @type boolean
     */
    support.funcNames = typeof Function.name == 'string';
  
    /**
     * Detect if the DOM is supported.
     *
     * @memberOf _.support
     * @type boolean
     */
    try {
      support.dom = document.createDocumentFragment().nodeType === 11;
    } catch(e) {
      support.dom = false;
    }
  
    /**
     * Detect if `arguments` object indexes are non-enumerable.
     *
     * In Firefox < 4, IE < 9, PhantomJS, and Safari < 5.1 `arguments` object
     * indexes are non-enumerable. Chrome < 25 and Node.js < 0.11.0 treat
     * `arguments` object indexes as non-enumerable and fail `hasOwnProperty`
     * checks for indexes that exceed their function's formal parameters with
     * associated values of `0`.
     *
     * @memberOf _.support
     * @type boolean
     */
    try {
      support.nonEnumArgs = !propertyIsEnumerable.call(arguments, 1);
    } catch(e) {
      support.nonEnumArgs = true;
    }
  }(0, 0));
  
  module.exports = support;
  
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
  },{"./lang/isNative":69}],78:[function(require,module,exports){
  /**
   * Creates a function that returns `value`.
   *
   * @static
   * @memberOf _
   * @category Utility
   * @param {*} value The value to return from the new function.
   * @returns {Function} Returns the new function.
   * @example
   *
   * var object = { 'user': 'fred' };
   * var getter = _.constant(object);
   *
   * getter() === object;
   * // => true
   */
  function constant(value) {
    return function() {
      return value;
    };
  }
  
  module.exports = constant;
  
  },{}],79:[function(require,module,exports){
  /**
   * This method returns the first argument provided to it.
   *
   * @static
   * @memberOf _
   * @category Utility
   * @param {*} value Any value.
   * @returns {*} Returns `value`.
   * @example
   *
   * var object = { 'user': 'fred' };
   *
   * _.identity(object) === object;
   * // => true
   */
  function identity(value) {
    return value;
  }
  
  module.exports = identity;
  
  },{}],80:[function(require,module,exports){
  /**
   * A no-operation function which returns `undefined` regardless of the
   * arguments it receives.
   *
   * @static
   * @memberOf _
   * @category Utility
   * @example
   *
   * var object = { 'user': 'fred' };
   *
   * _.noop(object) === undefined;
   * // => true
   */
  function noop() {
    // No operation performed.
  }
  
  module.exports = noop;
  
  },{}],81:[function(require,module,exports){
  "use strict";
  var keys = require( "lodash/object/keys" );
  var intersection = require( "lodash/array/intersection" );
  var forEach = require( "lodash/collection/forEach" );
  var reduce = require( "lodash/collection/reduce" );
  var isEmpty = require( "lodash/lang/isEmpty" );
  var isUndefined = require( "lodash/lang/isUndefined" );
  var isString = require( "lodash/lang/isString" );
  
  /**
   * @typedef FacetList
   * @type {Array.<string>}
   *
   * @typedef OperatorList
   * @type {Object.<string, number>}
   */
  
  /**
   * SearchParameters is the data structure that contains all the informations
   * usable for making a search to Algolia API. It doesn't do the search itself,
   * nor does it contains logic about the parameters.
   * It is an immutable object, therefore it has been created in a way that each
   * "mutation" does not mutate the object itself but returns a copy with the
   * modification.
   * This object should probably not be instantiated outside of the helper. It will
   * be provided when needed. This object is documented for reference as you'll
   * get it from events generated by the {Helper}.
   * @constructor
   * @classdesc contains all the parameters of a search
   */
  var SearchParameters = function( newParameters ) {
    var params = newParameters || {};
    //Query
    /**
     * Query used for the search.
     * @member {string}
     */
    this.query = params.query || "";
    //Facets
    /**
     * All the facets that will be requested to the server
     * @member {Object.<string, string>}
     */
    this.facets = params.facets || [];
    /**
     * All the declared disjunctive facets
     * @member {Object.<string, string>}
     */
    this.disjunctiveFacets = params.disjunctiveFacets || [];
    //Refinements
    /** @member {Object.<string, FacetList>}*/
    this.facetsRefinements = params.facetsRefinements || {};
    /** @member {Object.<string, FacetList>}*/
    this.facetsExcludes = params.facetsExcludes || {};
    /** @member {Object.<string, FacetList>}*/
    this.disjunctiveFacetsRefinements = params.disjunctiveFacetsRefinements || {};
    /**
     * @member {Object.<string, OperatorList>}
     */
    this.numericRefinements = params.numericRefinements || {};
    //Misc. parameters
    /** @member {number} */
    this.hitsPerPage = params.hitsPerPage || 20;
    /**
     * @member {number}
     **/
    this.maxValuesPerFacet = params.maxValuesPerFacet || 10;
    /** @member {number} */
    this.page = params.page || 0;
  
    /**
     * Possible values : prefixAll, prefixLast, prefixNone
     * @member {string}
     */
    this.queryType = params.queryType;
    /**
     * Possible values : true, false, min, strict
     * @member {string}
     */
    this.typoTolerance = params.typoTolerance;
  
    this.minWordSizefor1Typo = params.minWordSizefor1Typo;
    this.minWordSizefor2Typos = params.minWordSizefor2Typos;
    this.allowTyposOnNumericTokens = params.allowTyposOnNumericTokens;
    this.ignorePlurals = params.ignorePlurals;
    this.restrictSearchableAttributes = params.restrictSearchableAttributes;
    this.advancedSyntax = params.advancedSyntax;
    this.analytics = params.analytics;
    this.analyticsTags = params.analyticsTags;
    this.synonyms = params.synonyms;
    this.replaceSynonymsInHighlight = params.replaceSynonymsInHighlight;
    this.optionalWords = params.optionalWords;
    this.removeWordsIfNoResults = params.removeWordsIfNoResults;
    this.attributesToRetrieve = params.attributesToRetrieve;
    this.attributesToHighlight = params.attributesToHighlight;
    this.attributesToSnippet = params.attributesToSnippet;
    this.getRankingInfo = params.getRankingInfo;
    this.tagFilters = params.tagFilters;
    this.distinct = params.distinct;
    this.aroundLatLng = params.aroundLatLng;
    this.aroundLatLngViaIP = params.aroundLatLngViaIP;
    this.aroundRadius = params.aroundRadius;
    this.aroundPrecision = params.aroundPrecision;
    this.insideBoundingBox = params.insideBoundingBox;
  };
  
  SearchParameters.prototype = {
    constructor : SearchParameters,
  
    /**
     * Remove all refinements (disjunctive + conjunctive + excludes + numeric filters)
     * @method
     * @param {string} [name] - If given, name of the facet / attribute on which  we want to remove all refinements
     * @return {AlgoliaSearchHelper}
     */
    clearRefinements : function clearRefinements( name ) {
      return this.mutateMe( function( m ) {
        m.page = 0;
        m._clearNumericRefinements( name );
        m._clearFacetRefinements( name );
        m._clearExcludeRefinements( name );
        m._clearDisjunctiveFacetRefinements( name );
      } );
    },
    /**
     * Query setter
     * @method
     * @param {string} newQuery value for the new query
     * @return {SearchParameters}
     */
    setQuery : function setQuery( newQuery ) {
      return this.mutateMe( function( m ) {
        m.query = newQuery;
        m.page = 0;
      } );
    },
    /**
     * Page setter
     * @method
     * @param {number} newPage new page number
     * @return {SearchParameters}
     */
    setPage : function setPage( newPage ) {
      return this.mutateMe( function( mutable ) {
        mutable.page = newPage;
      } );
    },
    /**
     * Facets setter
     * The facets are the simple facets, used for conjunctive (and) facetting.
     * @method
     * @param {string[]} facets all the attributes of the algolia records used for conjunctive facetting
     * @return {SearchParameters}
     */
    setFacets : function setFacets( facets ) {
      return this.mutateMe( function( m ) {
        m.facets = facets;
      } );
    },
    /**
     * Disjunctive facets setter
     * Change the list of disjunctive (or) facets the helper chan handle.
     * @method
     * @param {string[]} facets all the attributes of the algolia records used for disjunctive facetting
     * @return {SearchParameters}
     */
    setDisjunctiveFacets : function setDisjunctiveFacets( facets ) {
      return this.mutateMe( function( m ) {
        m.disjunctiveFacets = facets;
      } );
    },
    /**
     * HitsPerPage setter
     * Hits per page represents the number of hits retrieved for this query
     * @method
     * @param {number} n number of hits retrieved per page of results
     * @return {SearchParameters}
     */
    setHitsPerPage : function setHitsPerPage( n ) {
      return this.mutateMe( function( m ) {
        m.HitsPerPage = n;
        m.page = 0;
      } );
    },
    /**
     * Add or update a numeric filter for a given attribute
     * Current limitation of the numeric filters : you can't have more than one value
     * filtered for each (attribute, oprator). It means that you can't have a filter
     * for ( "attribute", "=", 3 ) and ( "attribute", "=", 8 )
     * @method
     * @param {string} attribute attribute to set the filter on
     * @param {string} operator operator of the filter ( possible values : =, >, >=, <, <=, != )
     * @param {number} value value of the filter
     */
    addNumericRefinement : function( attribute, operator, value ) {
      return this.mutateMe( function( m ) {
        m.page = 0;
        if( !m.numericRefinements[ attribute ] ) {
          m.numericRefinements[ attribute ] = {};
        }
        m.numericRefinements[ attribute ][ operator ] = value;
      } );
    },
    /**
     * Remove a numeric filter
     * @method
     * @param {string} attribute attribute to set the filter on
     * @param {string} operator operator of the filter ( possible values : =, >, >=, <, <=, != )
     */
    removeNumericRefinement : function( attribute, operator ) {
      return this.mutateMe( function( m ) {
        if( m.numericRefinements[ attribute ] ) {
          m.page = 0;
          var value = m.numericRefinements[ attribute ][ operator ];
          if( !isUndefined( value ) ) {
            delete m.numericRefinements[ attribute ][ operator ];
            if( isEmpty( m.numericRefinements[ attribute ] ) ) {
              delete m.numericRefinements[ attribute ];
            }
          }
        }
      } );
    },
    /**
     * Return the current refinement for the ( attribute, operator )
     * @param {string} attribute of the record
     * @param {string} operator applied
     * @return {number} value of the refinement
     */
    getNumericRefinement : function( attribute, operator ){
      return this.numericRefinements[ attribute ] && this.numericRefinements[ attribute ][ operator ];
    },
    /**
     * Clear numeric filters.
     * @method
     * @private
     * @param {string} [attribute] -
     * - If not given, means to clear all the filters.
     * - If `string`, means to clear all refinements for the `attribute` named filter.
     */
    _clearNumericRefinements : function _clearNumericRefinements( attribute ) {
      if ( isUndefined( attribute ) ) {
        this.numericRefinements = {};
      }
      else if ( isString( attribute ) ) {
        if ( !isUndefined( this.numericRefinements[ attribute ] ) ) {
          delete this.numericRefinements[ attribute ];
        }
      }
    },
    /**
     * Add a refinement on a "normal" facet
     * @method
     * @param {string} facet attribute to apply the facetting on
     * @param {string} value value of the attribute
     * @return {SearchParameters}
     */
    addFacetRefinement : function addFacetRefinement( facet, value ) {
      return this.mutateMe( function( m ) {
        m.page = 0;
        m.facetsRefinements[ facet ] = value;
      } );
    },
    /**
     * Exclude a value from a "normal" facet
     * @method
     * @param {string} facet attribute to apply the exclusion on
     * @param {string} value value of the attribute
     * @return {SearchParameters}
     */
    addExcludeRefinement : function addExcludeRefinement( facet, value ) {
      return this.mutateMe( function( m ) {
        m.page = 0;
        if( !m.facetsExcludes[ facet ] ) {
          m.facetsExcludes[ facet ] = [];
        }
        m.facetsExcludes[ facet ].push( value );
      } );
    },
    /**
     * Adds a refinement on a disjunctive facet.
     * @method
     * @param {string} facet attribute to apply the facetting on
     * @param {string} value value of the attribute
     * @return {SearchParameters}
     */
    addDisjunctiveFacetRefinement : function addDisjunctiveFacetRefinement( facet, value ) {
      return this.mutateMe( function( m ) {
        m.page = 0;
        if( !m.disjunctiveFacetsRefinements[ facet ] ) {
          m.disjunctiveFacetsRefinements[ facet ] = [];
        }
        m.disjunctiveFacetsRefinements[ facet ].push( value );
      } );
    },
    /**
     * Remove a refinement set on facet.
     * @method
     * @param {string} facet
     * @return {SearchParameters}
     */
    removeFacetRefinement : function removeFacetRefinement( facet ) {
      return this.mutateMe( function( m ) {
        m.page = 0;
        m._clearFacetRefinements( facet );
      } );
    },
    /**
     * Remove a negative refinement on a facet
     * @method
     * @param {string} facet
     * @param {string} value
     * @return {SearchParameters}
     */
    removeExcludeRefinement : function removeExcludeRefinement( facet, value ) {
      return this.mutateMe( function( m ) {
        if( m.facetsExcludes[ facet ] ) {
          m.page = 0;
          var idx = m.facetsExcludes[ facet ].indexOf( value );
          if( idx > -1 ) {
            m.facetsExcludes[ facet ].splice( idx, 1 );
            if( m.facetsExcludes[ facet ].length === 0 ) {
              delete m.facetsExcludes[ facet ];
            }
          }
        }
      } );
    },
    /**
     * Remove a refinement on a disjunctive facet
     * @method
     * @param {string} facet
     * @param {string} value
     * @return {SearchParameters}
     */
    removeDisjunctiveFacetRefinement : function removeDisjunctiveFacetRefinement( facet, value ) {
      return this.mutateMe( function( m ) {
        if( m.disjunctiveFacetsRefinements[ facet ] ) {
          m.page = 0;
          var idx = m.disjunctiveFacetsRefinements[ facet ].indexOf( value );
          if( idx > -1 ) {
            m.disjunctiveFacetsRefinements[ facet ].splice( idx, 1 );
            if( m.disjunctiveFacetsRefinements[facet].length === 0 ) {
              delete m.disjunctiveFacetsRefinements[ facet ];
            }
          }
        }
      } );
    },
    /**
     * Clear the facet refinements
     * @method
     * @private
     * @param {string} [facet] -
     * - If not given, means to clear the refinement of all facets.
     * - If `string`, means to clear the refinement for the `facet` named facet.
     */
    _clearFacetRefinements : function _clearFacetRefinements( facet ) {
      if ( isUndefined( facet ) ) {
        this.facetsRefinements = {};
      }
      else if ( isString( facet ) ) {
        if ( !isUndefined( this.facetsRefinements[ facet ] ) ) {
          delete this.facetsRefinements[ facet ];
        }
      }
    },
    /**
     * Clear the exclude refinements
     * @method
     * @private
     * @param {string} [facet] -
     * - If not given, means to clear all the excludes of all facets.
     * - If `string`, means to clear all the excludes for the `facet` named facet.
     */
    _clearExcludeRefinements : function _clearExcludeRefinements( facet ) {
      if ( isUndefined( facet ) ) {
        this.facetsExcludes = {};
      }
      else if ( isString( facet ) ) {
        if ( !isUndefined( this.facetsExcludes[ facet ] ) ) {
          delete this.facetsExcludes[ facet ];
        }
      }
    },
    /**
     * Clear the disjunctive refinements
     * @method
     * @private
     * @param {string} [facet] -
     * - If not given, means to clear all the refinements of all disjunctive facets.
     * - If `string`, means to clear all the refinements for the `facet` named facet.
     */
    _clearDisjunctiveFacetRefinements : function _clearDisjunctiveFacetRefinements( facet ) {
      if ( isUndefined( facet ) ) {
        this.disjunctiveFacetsRefinements = {};
      }
      else if ( isString( facet ) ) {
        if ( !isUndefined( this.disjunctiveFacetsRefinements[ facet ] ) ) {
          delete this.disjunctiveFacetsRefinements[ facet ];
        }
      }
    },
    /**
     * Switch the refinement applied over a facet/value
     * @method
     * @param {string} facet
     * @param {value} value
     * @return {SearchParameters}
     */
    toggleFacetRefinement : function toggleFacetRefinement( facet, value ) {
      if( this.isFacetRefined( facet, value ) ) {
        return this.removeFacetRefinement( facet );
      }
      else {
        return this.addFacetRefinement( facet, value );
      }
    },
    /**
     * Switch the refinement applied over a facet/value
     * @method
     * @param {string} facet
     * @param {value} value
     * @return {SearchParameters}
     */
    toggleExcludeFacetRefinement : function toggleExcludeFacetRefinement( facet, value ) {
      if( this.isExcludeRefined( facet, value ) ) {
        return this.removeExcludeRefinement( facet, value );
      }
      else {
        return this.addExcludeRefinement( facet, value );
      }
    },
    /**
     * Switch the refinement applied over a facet/value
     * @method
     * @param {string} facet
     * @param {value} value
     * @return {SearchParameters}
     */
    toggleDisjunctiveFacetRefinement : function toggleDisjunctiveFacetRefinement( facet, value ) {
      if( this.isDisjunctiveFacetRefined( facet, value ) ) {
        return this.removeDisjunctiveFacetRefinement( facet, value );
      }
      else {
        return this.addDisjunctiveFacetRefinement( facet, value );
      }
    },
    /**
     * Returns true if the couple (facet, value) is refined
     * @method
     * @param {string} facet
     * @param {string} value
     * @return {boolean}
     */
    isFacetRefined : function isFacetRefined( facet, value ) {
      return this.facetsRefinements[ facet ] === value;
    },
    /**
     * Returns true if the couple (facet, value) is excluded
     * @method
     * @param {string} facet
     * @param {string} value
     * @return {boolean}
     */
    isExcludeRefined : function isExcludeRefined( facet, value ) {
      return this.facetsExcludes[ facet ] &&
             this.facetsExcludes[ facet ].indexOf( value ) !== -1;
    },
    /**
     * Returns true if the couple (facet, value) is refined
     * @method
     * @param {string} facet
     * @param {string} value
     * @return {boolean}
     */
    isDisjunctiveFacetRefined : function isDisjunctiveFacetRefined( facet, value ) {
      return this.disjunctiveFacetsRefinements[ facet ] &&
             this.disjunctiveFacetsRefinements[ facet ].indexOf( value ) !== -1;
    },
    /**
     * Returns the list of all disjunctive facets refined
     * @method
     * @param {string} facet
     * @param {value} value
     * @return {string[]}
     */
    getRefinedDisjunctiveFacets : function getRefinedDisjunctiveFacets() {
      var disjunctiveNumericRefinedFacets = intersection(
        keys( this.numericRefinements ),
        this.disjunctiveFacets
      );
      return keys( this.disjunctiveFacetsRefinements ).concat( disjunctiveNumericRefinedFacets );
    },
    /**
     * Returned the list of all disjunctive facets not refined
     * @method
     * @return {string[]}
     */
    getUnrefinedDisjunctiveFacets : function() {
      var unrefinedFacets = [];
      var refinedFacets = this.getRefinedDisjunctiveFacets();
      forEach( this.disjunctiveFacets, function( f ) {
        if( refinedFacets.indexOf( f ) === -1 ) {
          unrefinedFacets.push( f );
        }
      } );
      return unrefinedFacets;
    },
    managedParameters : [
      "facets", "disjunctiveFacets", "facetsRefinements",
      "facetsExcludes", "disjunctiveFacetsRefinements",
      "numericRefinements"
    ],
    getQueryParams : function getQueryParams() {
      var managedParameters = this.managedParameters;
      return reduce( this, function( memo, value, parameter, parameters ) {
        if( managedParameters.indexOf( parameter ) === -1 &&
            parameters[ parameter ] !== undefined ) {
          memo[ parameter ] = value;
        }
        return memo;
      }, {} );
    },
    /**
     * Helper function to make it easier to build new instances from a mutating
     * function
     * @private
     */
    mutateMe : function mutateMe( fn ) {
      var newState = new ( this.constructor )( this );
      fn( newState );
      return Object.freeze( newState );
    }
  };
  
  module.exports = SearchParameters;
  
  },{"lodash/array/intersection":9,"lodash/collection/forEach":11,"lodash/collection/reduce":12,"lodash/lang/isEmpty":67,"lodash/lang/isString":71,"lodash/lang/isUndefined":73,"lodash/object/keys":74}],82:[function(require,module,exports){
  "use strict";
  var forEach = require( "lodash/collection/forEach" );
  var compact = require( "lodash/array/compact" );
  var find = require( "lodash/collection/find" );
  
  /**
   * @typedef Facet
   * @type {object}
   * @property {string} name name of the attribute in the record
   * @property {object.<string, number>} data the facetting data : value, number of entries
   * @property {object} stats undefined unless facet_stats is retrieved from algolia
   */
  
  function getIndices( obj ) {
    var indices = {};
    forEach( obj, function( val, idx ) { indices[ val ] = idx; } );
    return indices;
  }
  
  function assignFacetStats( dest, facetStats, key ) {
    if ( facetStats && facetStats[key] ) {
      dest.stats = facetStats[key];
    }
  }
  
  function assignFacetTimeout( dest, timeoutCounts, getRankingInfo ) {
    if ( getRankingInfo ) {
      dest.timeout = !!( timeoutCounts );
    }
  }
  
  /**
   * Constructor for SearchResults
   * @class
   * @classdesc SearchResults is an object that contains all the data from a
   * helper query.
   * @param {SearchParameters} state state that led to the response
   * @param {object} algoliaResponse the response from algolia client
   **/
  var SearchResults = function( state, algoliaResponse ) {
    var mainSubResponse = algoliaResponse.results[ 0 ];
  
    /**
     * query used to generate the results
     * @member {string}
     */
    this.query = mainSubResponse.query;
    /**
     * all the hits generated for the query
     * @member {array}
     */
    this.hits = mainSubResponse.hits;
    /**
     * index where the results come from
     * @member {string}
     */
    this.index = mainSubResponse.index;
    /**
     * number of hits per page requested
     * @member {number}
     */
    this.hitsPerPage = mainSubResponse.hitsPerPage;
    /**
     * total number of hits of this query on the index
     * @member {number}
     */
    this.nbHits = mainSubResponse.nbHits;
    /**
     * total number of pages with respect to the number of hits per page and the total number of hits
     * @member {number}
     */
    this.nbPages = mainSubResponse.nbPages;
    /**
     * current page
     * @member {number}
     */
    this.page = mainSubResponse.page;
    /**
     * processing time of the main query
     * @member {number}
     */
    this.processingTimeMS = mainSubResponse.processingTimeMS;
    /**
     * disjunctive facets results
     * @member {array}
     */
    this.disjunctiveFacets = [];
    /**
     * other facets results
     * @member {array}
     */
    this.facets = [];
  
    var disjunctiveFacets = state.getRefinedDisjunctiveFacets();
  
    var facetsIndices = getIndices( state.facets );
    var disjunctiveFacetsIndices = getIndices( state.disjunctiveFacets );
  
    //Since we send request only for disjunctive facets that have been refined,
    //we get the facets informations from the first, general, response.
    forEach( mainSubResponse.facets, function( facetValueObject, facetKey ) {
      var isFacetDisjunctive = state.disjunctiveFacets.indexOf( facetKey ) !== -1;
      var position = isFacetDisjunctive ? disjunctiveFacetsIndices[ facetKey ] :
                                          facetsIndices[ facetKey ];
      if( isFacetDisjunctive ) {
        this.disjunctiveFacets[ position ] = {
          name : facetKey,
          data : facetValueObject
        };
        assignFacetStats( this.disjunctiveFacets[ position ], mainSubResponse.facets_stats, facetKey );
        assignFacetTimeout( this.disjunctiveFacets[ position ],
                            state.getRankingInfo,
                            mainSubResponse.timeoutCounts,
                            facetKey );
      }
      else {
        this.facets[ position ] = {
          name : facetKey,
          data : facetValueObject
        };
        assignFacetStats( this.facets[ position ], mainSubResponse.facets_stats, facetKey );
        assignFacetTimeout( this.facets[ position ], state.getRankingInfo, mainSubResponse.timeoutCounts, facetKey );
      }
    }, this );
  
    // aggregate the refined disjunctive facets
    forEach( disjunctiveFacets, function( disjunctiveFacet, idx ) {
      var result = algoliaResponse.results[ idx + 1 ];
  
      // There should be only item in facets.
      forEach( result.facets, function( facetResults, dfacet ) {
        var position = disjunctiveFacetsIndices[ dfacet ];
  
        this.disjunctiveFacets[ position ] = {
          name : dfacet,
          data : facetResults
        };
        assignFacetStats( this.disjunctiveFacets[ position ], result.facets_stats, dfacet );
        assignFacetTimeout( this.disjunctiveFacets[ position ], state.getRankingInfo, result.timeoutCounts, dfacet );
  
        if ( state.disjunctiveFacetsRefinements[dfacet] ) {
          forEach( state.disjunctiveFacetsRefinements[ dfacet ], function( refinementValue ) {
            // add the disjunctive refinements if it is no more retrieved
            if ( !this.disjunctiveFacets[position].data[refinementValue] &&
                 state.disjunctiveFacetsRefinements[dfacet].indexOf( refinementValue ) > -1 ) {
              this.disjunctiveFacets[position].data[refinementValue] = 0;
            }
          }, this );
        }
      }, this );
    }, this );
  
    // add the excludes
    forEach( state.facetsExcludes, function( excludes, facetName ) {
      var position = facetsIndices[ facetName ];
      this.facets[ position ] = {
        name : facetName,
        data : mainSubResponse.facets[ facetName ]
      };
      forEach( excludes, function( facetValue ) {
        this.facets[ position ] = this.facets[ position ] || { name : facetName };
        this.facets[ position ].data = this.facets[ position ].data || {};
        this.facets[ position ].data[ facetValue ] = 0;
      }, this );
    }, this );
  
    this.facets = compact( this.facets );
    this.disjunctiveFacets = compact( this.disjunctiveFacets );
  
    this._state = state;
  };
  
  /**
   * Get a facet object with its name
   * @param {string} name name of the attribute facetted
   * @return {Facet} the facet object
   */
  SearchResults.prototype.getFacetByName = function( name ) {
    var isName = function( facet ) { return facet.name === name; };
    var indexInFacets = find( this.facets, isName );
    return indexInFacets || find( this.disjunctiveFacets, isName );
  };
  
  module.exports = SearchResults;
  
  },{"lodash/array/compact":7,"lodash/collection/find":10,"lodash/collection/forEach":11}],83:[function(require,module,exports){
  "use strict";
  var SearchParameters = require( "./SearchParameters" );
  var SearchResults = require( "./SearchResults" );
  var extend = require( "./functions/extend" );
  var util = require( "util" );
  var events = require( "events" );
  var forEach = require( "lodash/collection/forEach" );
  var bind = require( "lodash/function/bind" );
  
  /**
   * Initialize a new AlgoliaSearchHelper
   * @class
   * @classdesc The AlgoliaSearchHelper is a class that ease the management of the
   * search. It provides an event based interface for search callbacks :
   *  - change : when the internal search state is changed. This event contains a {SearchParameters} object
   *  - result : when the response is retrieved from Algolia and is processed. This event contains a {SearchResults} object
   *  - error  : when the response is an error. This event contains the error returned by the server.
   * @param  {AlgoliaSearch} client an AlgoliaSearch client
   * @param  {string} index the index name to query
   * @param  {SearchParameters | object} options an object defining the initial config of the search. It doesn't have to be a {SearchParamaters}, just an object containing the properties you need from it.
   */
  function AlgoliaSearchHelper( client, index, options ) {
    this.client = client;
    this.index = index;
    this.state = new SearchParameters( options );
  }
  
  util.inherits( AlgoliaSearchHelper, events.EventEmitter );
  
  /**
   * Start the search with the parameters set in the state.
   * @return {AlgoliaSearchHelper}
   */
  AlgoliaSearchHelper.prototype.search = function() {
    this._search();
    return this;
  };
  
  /**
   * Sets the query. Also sets the current page to 0.
   * @param  {string} q the user query
   * @return {AlgoliaSearchHelper}
   */
  AlgoliaSearchHelper.prototype.setQuery = function( q ) {
    this.state = this.state.setQuery( q );
  
    this.emit( "change", this.state );
    return this;
  };
  
  /**
   * Remove all refinements (disjunctive + conjunctive + excludes + numeric filters)
   * @param {string} [name] - If given, name of the facet / attribute on which  we want to remove all refinements
   * @return {AlgoliaSearchHelper}
   */
  AlgoliaSearchHelper.prototype.clearRefinements = function( name ) {
    this.state = this.state.clearRefinements( name );
    this.emit( "change", this.state );
    return this;
  };
  
  /**
   * Ensure a facet refinement exists
   * @param  {string} facet the facet to refine
   * @param  {string} value the associated value
   * @return {AlgoliaSearchHelper}
   */
  AlgoliaSearchHelper.prototype.addDisjunctiveRefine = function( facet, value ) {
    this.state = this.state.addDisjunctiveFacetRefinement( facet, value );
    this.emit( "change", this.state );
    return this;
  };
  
  /**
   * Ensure a facet refinement does not exist
   * @param  {string} facet the facet to refine
   * @param  {string} value the associated value
   * @return {AlgoliaSearchHelper}
   */
  AlgoliaSearchHelper.prototype.removeDisjunctiveRefine = function( facet, value ) {
    this.state = this.state.removeDisjunctiveFacetRefinement( facet, value );
    this.emit( "change", this.state );
    return this;
  };
  
  /**
   * Add a numeric refinement on the given attribute
   * @param  {string} attribute
   * @param  {string} operator
   * @param  {number} value
   * @return {AlgoliaSearchHelper}
   */
  AlgoliaSearchHelper.prototype.addNumericRefinement = function( attribute, operator, value ) {
    this.state = this.state.addNumericRefinement( attribute, operator, value );
    this.emit( "change", this.state );
    return this;
  };
  
  /**
   * Remove a numeric filter.
   * @param  {string} attribute
   * @param  {string} operator
   * @param  {number} value
   * @return {AlgoliaSearchHelper}
   */
  AlgoliaSearchHelper.prototype.removeNumericRefinement = function( attribute, operator, value ) {
    this.state = this.state.removeNumericRefinement( attribute, operator, value );
    this.emit( "change", this.state );
    return this;
  };
  
  /**
   * Ensure a facet refinement exists
   * @param  {string} facet the facet to refine
   * @param  {string} value the associated value
   * @return {AlgoliaSearchHelper}
   */
  AlgoliaSearchHelper.prototype.addRefine = function( facet, value ) {
    this.state = this.state.addFacetRefinement( facet, value );
    this.emit( "change", this.state );
    return this;
  };
  
  /**
   * Ensure a facet refinement does not exist
   * @param  {string} facet the facet to refine
   * @param  {string} value the associated value
   * @return {AlgoliaSearchHelper}
   */
  AlgoliaSearchHelper.prototype.removeRefine = function( facet, value ) {
    this.state = this.state.removeFacetRefinement( facet, value );
    this.emit( "change", this.state );
    return this;
  };
  
  /**
   * Ensure a facet exclude exists
   * @param  {string} facet the facet to refine
   * @param  {string} value the associated value
   * @return {AlgoliaSearchHelper}
   */
  AlgoliaSearchHelper.prototype.addExclude = function( facet, value ) {
    this.state = this.state.addExcludeRefinement( facet, value );
    this.emit( "change", this.state );
    return this;
  };
  
  /**
   * Ensure a facet exclude does not exist
   * @param  {string} facet the facet to refine
   * @param  {string} value the associated value
   * @return {AlgoliaSearchHelper}
   */
  AlgoliaSearchHelper.prototype.removeExclude = function( facet, value ) {
    this.state = this.state.removeExcludeRefinement( facet, value );
    this.emit( "change", this.state );
    return this;
  };
  
  /**
   * Toggle refinement state of an exclude
   * @param  {string} facet the facet to refine
   * @param  {string} value the associated value
   * @return {AlgoliaSearchHelper}
   */
  AlgoliaSearchHelper.prototype.toggleExclude = function( facet, value ) {
    this.state = this.state.toggleExcludeFacetRefinement( facet, value );
    this.emit( "change", this.state );
    return this;
  };
  
  /**
   * Toggle refinement state of a facet
   * @param  {string} facet the facet to refine
   * @param  {string} value the associated value
   * @return {AlgoliaSearchHelper}
   */
  AlgoliaSearchHelper.prototype.toggleRefine = function( facet, value ) {
    if( this.state.facets.indexOf( facet ) > -1 ) {
      this.state = this.state.toggleFacetRefinement( facet, value );
    }
    else if( this.state.disjunctiveFacets.indexOf( facet ) > -1 ) {
      this.state = this.state.toggleDisjunctiveFacetRefinement( facet, value );
    }
    else {
      /* eslint-disable */
      console.log( "warning : you're trying to refine the undeclared facet '" + facet +
                  "'; add it to the helper options 'facets' or 'disjunctiveFacets'" );
      /* eslint-enable */
      return this;
    }
    this.emit( "change", this.state );
    return this;
  };
  
  /**
   * Go to next page
   * @return {AlgoliaSearchHelper}
   */
  AlgoliaSearchHelper.prototype.nextPage = function() {
    return this.setCurrentPage( this.state.page + 1 );
  };
  
  /**
   * Go to previous page
   * @return {AlgoliaSearchHelper}
   */
  AlgoliaSearchHelper.prototype.previousPage = function() {
    return this.setCurrentPage( this.state.page - 1 );
  };
  
  /**
   * Change the current page
   * @param  {integer} page The page number
   * @return {AlgoliaSearchHelper}
   */
  AlgoliaSearchHelper.prototype.setCurrentPage = function( page ) {
    if( page < 0 ) throw new Error( "Page requested below 0." );
  
    this.state = this.state.setPage( page );
    this.emit( "change", this.state );
    return this;
  };
  
  /**
   * Configure the underlying index name
   * @param {string} name the index name
   * @return {AlgoliaSearchHelper}
   */
  AlgoliaSearchHelper.prototype.setIndex = function( name ) {
    this.index = name;
    this.setCurrentPage( 0 );
    return this;
  };
  
  /**
   * Set the whole state ( warning : will erase previous state )
   * @param {SearchParameters} newState the whole new state
   * @return {AlgoliaSearchHelper}
   */
  AlgoliaSearchHelper.prototype.setState = function( newState ) {
    this.state = new SearchParameters( newState );
    this.emit( "change", this.state );
    return this;
  };
  
  /**
   * Check the refinement state of a facet
   * @param  {string}  facet the facet
   * @param  {string}  value the associated value
   * @return {boolean} true if refined
   */
  AlgoliaSearchHelper.prototype.isRefined = function( facet, value ) {
    if( this.state.facets.indexOf( facet ) > -1 ) {
      return this.state.isFacetRefined( facet, value );
    }
    else if( this.state.disjunctiveFacets.indexOf( facet ) > -1 ) {
      return this.state.isDisjunctiveFacetRefined( facet, value );
    }
    return false;
  };
  
  /**
   * Check the exclude state of a facet
   * @param  {string}  facet the facet
   * @param  {string}  value the associated value
   * @return {boolean} true if refined
   */
  AlgoliaSearchHelper.prototype.isExcluded = function( facet, value ) {
    return this.state.isExcludeRefined( facet, value );
  };
  
  /**
   * Check the refinement state of the disjunctive facet
   * @param  {string}  facet the facet
   * @param  {string}  value the associated value
   * @return {boolean} true if refined
   */
  AlgoliaSearchHelper.prototype.isDisjunctiveRefined = function( facet, value ) {
    return this.state.isDisjunctiveFacetRefined( facet, value );
  };
  
  /**
   * Get the underlying configured index name
   */
  AlgoliaSearchHelper.prototype.getIndex = function() {
    return this.index;
  };
  
  /**
   * Get the currently selected page
   * @return Number the current page
   */
  AlgoliaSearchHelper.prototype.getCurrentPage = function() {
    return this.state.page;
  };
  
  ///////////// PRIVATE
  
  /**
   * Perform the underlying queries
   * @private
   */
  AlgoliaSearchHelper.prototype._search = function() {
    var state = this.state;
    var queries = [];
  
    //One query for the hits
    queries.push( {
      indexName : this.index,
      query : state.query,
      params : this._getHitsSearchParams()
    } );
  
    //One for each disjunctive facets
    forEach( state.getRefinedDisjunctiveFacets(), function( refinedFacet ) {
      queries.push( {
        indexName : this.index,
        query : state.query,
        params : this._getDisjunctiveFacetSearchParams( refinedFacet )
      } );
    }, this );
  
    this.client.search( queries, bind( this._handleResponse, this, state ) );
  };
  
  /**
   * Transform the response as sent by the server and transform it into a user
   * usable objet that merge the results of all the batch requests.
   * @private
   * @param {SearchParameters} state state used for to generate the request
   * @param {Error} err error if any, null otherwise
   * @param {object} content content of the response
   */
  AlgoliaSearchHelper.prototype._handleResponse = function( state, err, content ) {
    if ( err ) {
      this.emit( "error", err );
      return;
    }
  
    var formattedResponse = new SearchResults( state, content );
  
    this.emit( "result", formattedResponse );
  };
  
  /**
   * Build search parameters used to fetch hits
   * @private
   * @return {object.<string, any>}
   */
  AlgoliaSearchHelper.prototype._getHitsSearchParams = function() {
    var facets = this.state.facets.concat( this.state.getUnrefinedDisjunctiveFacets() );
    var facetFilters = this._getFacetFilters();
    var numericFilters = this._getNumericFilters();
    var additionalParams = {
      facets : facets,
      distinct : false
    };
  
    if( facetFilters.length > 0 ) {
      additionalParams.facetFilters = facetFilters;
      additionalParams.distinct = this.state.distinct || false;
    }
  
    if( numericFilters.length > 0 ) {
      additionalParams.numericFilters = numericFilters;
    }
  
    return extend( this.state.getQueryParams(), additionalParams );
  };
  
  /**
   * Build search parameters used to fetch a disjunctive facet
   * @private
   * @param  {string} facet the associated facet name
   * @return {object}
   */
  AlgoliaSearchHelper.prototype._getDisjunctiveFacetSearchParams = function( facet ) {
    var facetFilters = this._getFacetFilters( facet );
    var numericFilters = this._getNumericFilters( facet );
    var additionalParams = {
      hitsPerPage : 1,
      page : 0,
      attributesToRetrieve : [],
      attributesToHighlight : [],
      attributesToSnippet : [],
      facets : facet,
      distinct : false
    };
  
    if( numericFilters.length > 0 ) {
      additionalParams.numericFilters = numericFilters;
    }
  
    if( facetFilters.length > 0 ) {
      additionalParams.facetFilters = facetFilters;
      additionalParams.distinct = this.state.distinct || false;
    }
  
    return extend( this.state.getQueryParams(), additionalParams );
  };
  
  /**
   * Return the numeric filters in an algolia request fashion
   * @private
   * @return {array.<string>} the numeric filters in the algolia format
   */
  AlgoliaSearchHelper.prototype._getNumericFilters = function( facetName ) {
    var numericFilters = [];
    forEach( this.state.numericRefinements, function( operators, attribute ) {
      forEach( operators, function( value, operator ) {
        if( facetName !== attribute ) {
          numericFilters.push( attribute + operator + value );
        }
      } );
    } );
    return numericFilters;
  };
  
  /**
   * Test if there are some disjunctive refinements on the facet
   * @private
   */
  AlgoliaSearchHelper.prototype._hasDisjunctiveRefinements = function( facet ) {
    return this.state.disjunctiveRefinements[ facet ] &&
           this.state.disjunctiveRefinements[ facet ].length > 0;
  };
  
  /**
   * Build facetFilters parameter based on current refinements. The array returned
   * contains strings representing the facet filters in the algolia format.
   * @private
   * @param  {string} facet if set, the current disjunctive facet
   * @return {array.<string>}
   */
  AlgoliaSearchHelper.prototype._getFacetFilters = function( facet ) {
    var facetFilters = [];
  
    forEach( this.state.facetsRefinements, function( facetValue, facetName ) {
      facetFilters.push( facetName + ":" + facetValue );
    } );
  
    forEach( this.state.facetsExcludes, function( facetValues, facetName ) {
      forEach( facetValues, function( facetValue ) {
        facetFilters.push( facetName + ":-" + facetValue );
      } );
    } );
  
    forEach( this.state.disjunctiveFacetsRefinements, function( facetValues, facetName ) {
      if( facetName === facet || !facetValues || facetValues.length === 0 ) return;
      var orFilters = [];
      forEach( facetValues, function( facetValue ) {
        orFilters.push( facetName + ":" + facetValue );
      } );
      facetFilters.push( orFilters );
    } );
  
    return facetFilters;
  };
  
  module.exports = AlgoliaSearchHelper;
  
  },{"./SearchParameters":81,"./SearchResults":82,"./functions/extend":84,"events":2,"lodash/collection/forEach":11,"lodash/function/bind":14,"util":6}],84:[function(require,module,exports){
  "use strict";
  module.exports = function extend( out ) {
    out = out || {};
    for ( var i = 1; i < arguments.length; i++ ) {
      if ( !arguments[i] ) {
        continue;
      }
      for ( var key in arguments[i] ) {
        if ( arguments[i].hasOwnProperty( key ) ) {
          out[key] = arguments[i][key];
        }
      }
    }
    return out;
  };
  
  },{}]},{},[1])(1)
  });