diff options
Diffstat (limited to 'module/web')
| -rw-r--r-- | module/web/static/css/default/dashboard.less | 26 | ||||
| -rw-r--r-- | module/web/static/js/config.js | 2 | ||||
| -rw-r--r-- | module/web/static/js/libs/lodash-1.0.1.js | 5049 | ||||
| -rw-r--r-- | module/web/static/js/libs/lodash-1.0.rc3.js | 4454 | ||||
| -rw-r--r-- | module/web/static/js/utils/apitypes.js | 14 | ||||
| -rw-r--r-- | module/web/static/js/views/actionbarView.js | 28 | ||||
| -rw-r--r-- | module/web/static/js/views/dashboardView.js | 6 | ||||
| -rw-r--r-- | module/web/static/js/views/fileView.js | 10 | ||||
| -rw-r--r-- | module/web/static/js/views/filterView.js | 93 | ||||
| -rw-r--r-- | module/web/static/js/views/packageView.js | 5 | ||||
| -rw-r--r-- | module/web/static/js/views/selectionView.js | 24 | ||||
| -rw-r--r-- | module/web/templates/default/dashboard.html | 48 | 
12 files changed, 5234 insertions, 4525 deletions
diff --git a/module/web/static/css/default/dashboard.less b/module/web/static/css/default/dashboard.less index e9d313d32..31c648453 100644 --- a/module/web/static/css/default/dashboard.less +++ b/module/web/static/css/default/dashboard.less @@ -245,7 +245,7 @@ FANCY CHECKBOXES    display: inline;
    width: 20px;
    height: 21px;
 -  margin: -1px 4px 0 0;
 +  margin-top: -1px;
    vertical-align: middle;
    background: url(../../img/default/checks_sheet.png) left top no-repeat;
    cursor: pointer;
 @@ -253,4 +253,28 @@ FANCY CHECKBOXES  .file-view.ui-selected .checkbox {
    background: url(../../img/default/checks_sheet.png) -21px top no-repeat;
 +}
 +
 +/*
 +  Actionbar
 +*/
 +
 +li.finished > a, li.finished:hover > a {
 +  background-color: @green;
 +  color: @light;
 +
 +  .caret, .caret:hover {
 +    border-bottom-color: @light !important;
 +    border-top-color: @light !important;
 +  }
 +}
 +
 +li.failed > a, li.failed:hover > a {
 +  background-color: @red;
 +  color: @light;
 +
 +  .caret, .caret:hover {
 +    border-bottom-color: @light !important;
 +    border-top-color: @light !important;
 +  }
  }
\ No newline at end of file diff --git a/module/web/static/js/config.js b/module/web/static/js/config.js index 20ad894de..86704740c 100644 --- a/module/web/static/js/config.js +++ b/module/web/static/js/config.js @@ -13,7 +13,7 @@ require.config({          select2: "libs/select2-3.2",          bootstrap: "libs/bootstrap-2.3", -        underscore: "libs/lodash-1.0.rc3", +        underscore: "libs/lodash-1.0.1",          backbone: "libs/backbone-0.9.10",          wreqr: "libs/backbone.wreqr-0.1.0",          handlebars: "libs/Handlebars-1.0rc1", diff --git a/module/web/static/js/libs/lodash-1.0.1.js b/module/web/static/js/libs/lodash-1.0.1.js new file mode 100644 index 000000000..9a78cd589 --- /dev/null +++ b/module/web/static/js/libs/lodash-1.0.1.js @@ -0,0 +1,5049 @@ +/** + * @license + * Lo-Dash 1.0.1 (Custom Build) <http://lodash.com/> + * Build: `lodash modern -o ./dist/lodash.js` + * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/> + * Based on Underscore.js 1.4.4 <http://underscorejs.org/> + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud Inc. + * Available under MIT license <http://lodash.com/license> + */ +;(function(window) { + +  /** Used as a safe reference for `undefined` in pre ES5 environments */ +  var undefined; + +  /** Detect free variable `exports` */ +  var freeExports = typeof exports == 'object' && exports; + +  /** Detect free variable `module` */ +  var freeModule = typeof module == 'object' && module && module.exports == freeExports && module; + +  /** Detect free variable `global` and use it as `window` */ +  var freeGlobal = typeof global == 'object' && global; +  if (freeGlobal.global === freeGlobal) { +    window = freeGlobal; +  } + +  /** Used to generate unique IDs */ +  var idCounter = 0; + +  /** Used internally to indicate various things */ +  var indicatorObject = {}; + +  /** Used by `cachedContains` as the default size when optimizations are enabled for large arrays */ +  var largeArraySize = 30; + +  /** Used to match HTML entities */ +  var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g; + +  /** Used to match empty string literals in compiled template source */ +  var reEmptyStringLeading = /\b__p \+= '';/g, +      reEmptyStringMiddle = /\b(__p \+=) '' \+/g, +      reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; + +  /** Used to match regexp flags from their coerced string values */ +  var reFlags = /\w*$/; + +  /** +   * Used to match ES6 template delimiters +   * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-7.8.6 +   */ +  var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; + +  /** Used to match "interpolate" template delimiters */ +  var reInterpolate = /<%=([\s\S]+?)%>/g; + +  /** Used to ensure capturing order of template delimiters */ +  var reNoMatch = /($^)/; + +  /** Used to match HTML characters */ +  var reUnescapedHtml = /[&<>"']/g; + +  /** Used to match unescaped characters in compiled string literals */ +  var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g; + +  /** Used to assign default `context` object properties */ +  var contextProps = [ +    'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object', 'RegExp', +    'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN', 'parseInt', +    'setImmediate', 'setTimeout' +  ]; + +  /** Used to make template sourceURLs easier to identify */ +  var templateCounter = 0; + +  /** `Object#toString` result shortcuts */ +  var argsClass = '[object Arguments]', +      arrayClass = '[object Array]', +      boolClass = '[object Boolean]', +      dateClass = '[object Date]', +      funcClass = '[object Function]', +      numberClass = '[object Number]', +      objectClass = '[object Object]', +      regexpClass = '[object RegExp]', +      stringClass = '[object String]'; + +  /** Used to identify object classifications that `_.clone` supports */ +  var cloneableClasses = {}; +  cloneableClasses[funcClass] = false; +  cloneableClasses[argsClass] = cloneableClasses[arrayClass] = +  cloneableClasses[boolClass] = cloneableClasses[dateClass] = +  cloneableClasses[numberClass] = cloneableClasses[objectClass] = +  cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true; + +  /** Used to determine if values are of the language type Object */ +  var objectTypes = { +    'boolean': false, +    'function': true, +    'object': true, +    'number': false, +    'string': false, +    'undefined': false +  }; + +  /** Used to escape characters for inclusion in compiled string literals */ +  var stringEscapes = { +    '\\': '\\', +    "'": "'", +    '\n': 'n', +    '\r': 'r', +    '\t': 't', +    '\u2028': 'u2028', +    '\u2029': 'u2029' +  }; + +  /*--------------------------------------------------------------------------*/ + +  /** +   * Create a new `lodash` function using the given `context` object. +   * +   * @static +   * @memberOf _ +   * @category Utilities +   * @param {Object} [context=window] The context object. +   * @returns {Function} Returns the `lodash` function. +   */ +  function runInContext(context) { +    context = context ? _.defaults({}, context, _.pick(window, contextProps)) : window; + +    /** Native constructor references */ +    var Array = context.Array, +        Boolean = context.Boolean, +        Date = context.Date, +        Function = context.Function, +        Math = context.Math, +        Number = context.Number, +        Object = context.Object, +        RegExp = context.RegExp, +        String = context.String; + +    /** Used for `Array` and `Object` method references */ +    var arrayRef = Array(), +        objectRef = Object(); + +    /** Used to restore the original `_` reference in `noConflict` */ +    var oldDash = context._; + +    /** Used to detect if a method is native */ +    var reNative = RegExp('^' + +      (objectRef.valueOf + '') +        .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') +        .replace(/valueOf|for [^\]]+/g, '.+?') + '$' +    ); + +    /** Native method shortcuts */ +    var ceil = Math.ceil, +        clearTimeout = context.clearTimeout, +        concat = arrayRef.concat, +        floor = Math.floor, +        getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf, +        hasOwnProperty = objectRef.hasOwnProperty, +        push = arrayRef.push, +        setImmediate = context.setImmediate, +        setTimeout = context.setTimeout, +        toString = objectRef.toString; + +    /* Native method shortcuts for methods with the same name as other `lodash` methods */ +    var nativeBind = reNative.test(nativeBind = slice.bind) && nativeBind, +        nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray, +        nativeIsFinite = context.isFinite, +        nativeIsNaN = context.isNaN, +        nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys, +        nativeMax = Math.max, +        nativeMin = Math.min, +        nativeParseInt = context.parseInt, +        nativeRandom = Math.random; + +    /** Detect various environments */ +    var isIeOpera = reNative.test(context.attachEvent), +        isJSC = !/\n{2,}/.test(Function()), +        isV8 = nativeBind && !/\n|true/.test(nativeBind + isIeOpera); + +    /* Detect if `Function#bind` exists and is inferred to be fast (all but V8) */ +    var isBindFast = nativeBind && !isV8; + +    /* Detect if `Object.keys` exists and is inferred to be fast (Firefox, IE, Opera, V8) */ +    var isKeysFast = nativeKeys && (isIeOpera || isV8 || !isJSC); + +    /** Used to lookup a built-in constructor by [[Class]] */ +    var ctorByClass = {}; +    ctorByClass[arrayClass] = Array; +    ctorByClass[boolClass] = Boolean; +    ctorByClass[dateClass] = Date; +    ctorByClass[objectClass] = Object; +    ctorByClass[numberClass] = Number; +    ctorByClass[regexpClass] = RegExp; +    ctorByClass[stringClass] = String; + +    /*--------------------------------------------------------------------------*/ + +    /** +     * Creates a `lodash` object, that wraps the given `value`, to enable method +     * chaining. +     * +     * In addition to Lo-Dash methods, wrappers also have the following `Array` methods: +     * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`, +     * and `unshift` +     * +     * Chaining is supported in custom builds as long as the `value` method is +     * implicitly or explicitly included in the build. +     * +     * The chainable wrapper functions are: +     * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`, `compose`, +     * `concat`, `countBy`, `debounce`, `defaults`, `defer`, `delay`, `difference`, +     * `filter`, `flatten`, `forEach`, `forIn`, `forOwn`, `functions`, `groupBy`, +     * `initial`, `intersection`, `invert`, `invoke`, `keys`, `map`, `max`, `memoize`, +     * `merge`, `min`, `object`, `omit`, `once`, `pairs`, `partial`, `partialRight`, +     * `pick`, `pluck`, `push`, `range`, `reject`, `rest`, `reverse`, `shuffle`, +     * `slice`, `sort`, `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, +     * `union`, `uniq`, `unshift`, `values`, `where`, `without`, `wrap`, and `zip` +     * +     * The non-chainable wrapper functions are: +     * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `has`, +     * `identity`, `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, +     * `isElement`, `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, +     * `isNull`, `isNumber`, `isObject`, `isPlainObject`, `isRegExp`, `isString`, +     * `isUndefined`, `join`, `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, +     * `pop`, `random`, `reduce`, `reduceRight`, `result`, `shift`, `size`, `some`, +     * `sortedIndex`, `runInContext`, `template`, `unescape`, `uniqueId`, and `value` +     * +     * The wrapper functions `first` and `last` return wrapped values when `n` is +     * passed, otherwise they return unwrapped values. +     * +     * @name _ +     * @constructor +     * @category Chaining +     * @param {Mixed} value The value to wrap in a `lodash` instance. +     * @returns {Object} Returns a `lodash` instance. +     */ +    function lodash(value) { +      // exit early if already wrapped, even if wrapped by a different `lodash` constructor +      if (value && typeof value == 'object' && value.__wrapped__) { +        return value; +      } +      // allow invoking `lodash` without the `new` operator +      if (!(this instanceof lodash)) { +        return new lodash(value); +      } +      this.__wrapped__ = value; +    } + +    /** +     * By default, the template delimiters used by Lo-Dash are similar to those in +     * embedded Ruby (ERB). Change the following template settings to use alternative +     * delimiters. +     * +     * @static +     * @memberOf _ +     * @type Object +     */ +    lodash.templateSettings = { + +      /** +       * Used to detect `data` property values to be HTML-escaped. +       * +       * @memberOf _.templateSettings +       * @type RegExp +       */ +      'escape': /<%-([\s\S]+?)%>/g, + +      /** +       * Used to detect code to be evaluated. +       * +       * @memberOf _.templateSettings +       * @type RegExp +       */ +      'evaluate': /<%([\s\S]+?)%>/g, + +      /** +       * Used to detect `data` property values to inject. +       * +       * @memberOf _.templateSettings +       * @type RegExp +       */ +      'interpolate': reInterpolate, + +      /** +       * Used to reference the data object in the template text. +       * +       * @memberOf _.templateSettings +       * @type String +       */ +      'variable': '', + +      /** +       * Used to import variables into the compiled template. +       * +       * @memberOf _.templateSettings +       * @type Object +       */ +      'imports': { + +        /** +         * A reference to the `lodash` function. +         * +         * @memberOf _.templateSettings.imports +         * @type Function +         */ +        '_': lodash +      } +    }; + +    /*--------------------------------------------------------------------------*/ + +    /** +     * The template used to create iterator functions. +     * +     * @private +     * @param {Obect} data The data object used to populate the text. +     * @returns {String} Returns the interpolated text. +     */ +    var iteratorTemplate = function(obj) { +       +      var __p = 'var index, iterable = ' + +      (obj.firstArg ) + +      ', result = iterable;\nif (!iterable) return result;\n' + +      (obj.top ) + +      ';\n'; +       if (obj.arrays) { +      __p += 'var length = iterable.length; index = -1;\nif (' + +      (obj.arrays ) + +      ') {\n  while (++index < length) {\n    ' + +      (obj.loop ) + +      '\n  }\n}\nelse {  '; +       } ; +       +       if (obj.isKeysFast && obj.useHas) { +      __p += '\n  var ownIndex = -1,\n      ownProps = objectTypes[typeof iterable] ? nativeKeys(iterable) : [],\n      length = ownProps.length;\n\n  while (++ownIndex < length) {\n    index = ownProps[ownIndex];\n    ' + +      (obj.loop ) + +      '\n  }  '; +       } else { +      __p += '\n  for (index in iterable) {'; +          if (obj.useHas) { +      __p += '\n    if ('; +            if (obj.useHas) { +      __p += 'hasOwnProperty.call(iterable, index)'; +       }    ; +      __p += ') {    '; +       } ; +      __p +=  +      (obj.loop ) + +      ';    '; +       if (obj.useHas) { +      __p += '\n    }'; +       } ; +      __p += '\n  }  '; +       } ; +       +       if (obj.arrays) { +      __p += '\n}'; +       } ; +      __p +=  +      (obj.bottom ) + +      ';\nreturn result'; +       +       +      return __p +    }; + +    /** Reusable iterator options for `assign` and `defaults` */ +    var defaultsIteratorOptions = { +      'args': 'object, source, guard', +      'top': +        'var args = arguments,\n' + +        '    argsIndex = 0,\n' + +        "    argsLength = typeof guard == 'number' ? 2 : args.length;\n" + +        'while (++argsIndex < argsLength) {\n' + +        '  iterable = args[argsIndex];\n' + +        '  if (iterable && objectTypes[typeof iterable]) {', +      'loop': "if (typeof result[index] == 'undefined') result[index] = iterable[index]", +      'bottom': '  }\n}' +    }; + +    /** Reusable iterator options shared by `each`, `forIn`, and `forOwn` */ +    var eachIteratorOptions = { +      'args': 'collection, callback, thisArg', +      'top': "callback = callback && typeof thisArg == 'undefined' ? callback : createCallback(callback, thisArg)", +      'arrays': "typeof length == 'number'", +      'loop': 'if (callback(iterable[index], index, collection) === false) return result' +    }; + +    /** Reusable iterator options for `forIn` and `forOwn` */ +    var forOwnIteratorOptions = { +      'top': 'if (!objectTypes[typeof iterable]) return result;\n' + eachIteratorOptions.top, +      'arrays': false +    }; + +    /*--------------------------------------------------------------------------*/ + +    /** +     * Creates a function optimized to search large arrays for a given `value`, +     * starting at `fromIndex`, using strict equality for comparisons, i.e. `===`. +     * +     * @private +     * @param {Array} array The array to search. +     * @param {Mixed} value The value to search for. +     * @param {Number} [fromIndex=0] The index to search from. +     * @param {Number} [largeSize=30] The length at which an array is considered large. +     * @returns {Boolean} Returns `true`, if `value` is found, else `false`. +     */ +    function cachedContains(array, fromIndex, largeSize) { +      fromIndex || (fromIndex = 0); + +      var length = array.length, +          isLarge = (length - fromIndex) >= (largeSize || largeArraySize); + +      if (isLarge) { +        var cache = {}, +            index = fromIndex - 1; + +        while (++index < length) { +          // manually coerce `value` to a string because `hasOwnProperty`, in some +          // older versions of Firefox, coerces objects incorrectly +          var key = array[index] + ''; +          (hasOwnProperty.call(cache, key) ? cache[key] : (cache[key] = [])).push(array[index]); +        } +      } +      return function(value) { +        if (isLarge) { +          var key = value + ''; +          return hasOwnProperty.call(cache, key) && indexOf(cache[key], value) > -1; +        } +        return indexOf(array, value, fromIndex) > -1; +      } +    } + +    /** +     * Used by `_.max` and `_.min` as the default `callback` when a given +     * `collection` is a string value. +     * +     * @private +     * @param {String} value The character to inspect. +     * @returns {Number} Returns the code unit of given character. +     */ +    function charAtCallback(value) { +      return value.charCodeAt(0); +    } + +    /** +     * Used by `sortBy` to compare transformed `collection` values, stable sorting +     * them in ascending order. +     * +     * @private +     * @param {Object} a The object to compare to `b`. +     * @param {Object} b The object to compare to `a`. +     * @returns {Number} Returns the sort order indicator of `1` or `-1`. +     */ +    function compareAscending(a, b) { +      var ai = a.index, +          bi = b.index; + +      a = a.criteria; +      b = b.criteria; + +      // ensure a stable sort in V8 and other engines +      // http://code.google.com/p/v8/issues/detail?id=90 +      if (a !== b) { +        if (a > b || typeof a == 'undefined') { +          return 1; +        } +        if (a < b || typeof b == 'undefined') { +          return -1; +        } +      } +      return ai < bi ? -1 : 1; +    } + +    /** +     * Creates a function that, when called, invokes `func` with the `this` binding +     * of `thisArg` and prepends any `partialArgs` to the arguments passed to the +     * bound function. +     * +     * @private +     * @param {Function|String} func The function to bind or the method name. +     * @param {Mixed} [thisArg] The `this` binding of `func`. +     * @param {Array} partialArgs An array of arguments to be partially applied. +     * @param {Object} [rightIndicator] Used to indicate partially applying arguments from the right. +     * @returns {Function} Returns the new bound function. +     */ +    function createBound(func, thisArg, partialArgs, rightIndicator) { +      var isFunc = isFunction(func), +          isPartial = !partialArgs, +          key = thisArg; + +      // juggle arguments +      if (isPartial) { +        partialArgs = thisArg; +      } +      if (!isFunc) { +        thisArg = func; +      } + +      function bound() { +        // `Function#bind` spec +        // http://es5.github.com/#x15.3.4.5 +        var args = arguments, +            thisBinding = isPartial ? this : thisArg; + +        if (!isFunc) { +          func = thisArg[key]; +        } +        if (partialArgs.length) { +          args = args.length +            ? (args = slice(args), rightIndicator ? args.concat(partialArgs) : partialArgs.concat(args)) +            : partialArgs; +        } +        if (this instanceof bound) { +          // ensure `new bound` is an instance of `func` +          noop.prototype = func.prototype; +          thisBinding = new noop; +          noop.prototype = null; + +          // mimic the constructor's `return` behavior +          // http://es5.github.com/#x13.2.2 +          var result = func.apply(thisBinding, args); +          return isObject(result) ? result : thisBinding; +        } +        return func.apply(thisBinding, args); +      } +      return bound; +    } + +    /** +     * Produces a callback bound to an optional `thisArg`. If `func` is a property +     * name, the created callback will return the property value for a given element. +     * If `func` is an object, the created callback will return `true` for elements +     * that contain the equivalent object properties, otherwise it will return `false`. +     * +     * @private +     * @param {Mixed} [func=identity] The value to convert to a callback. +     * @param {Mixed} [thisArg] The `this` binding of the created callback. +     * @param {Number} [argCount=3] The number of arguments the callback accepts. +     * @returns {Function} Returns a callback function. +     */ +    function createCallback(func, thisArg, argCount) { +      if (func == null) { +        return identity; +      } +      var type = typeof func; +      if (type != 'function') { +        if (type != 'object') { +          return function(object) { +            return object[func]; +          }; +        } +        var props = keys(func); +        return function(object) { +          var length = props.length, +              result = false; +          while (length--) { +            if (!(result = isEqual(object[props[length]], func[props[length]], indicatorObject))) { +              break; +            } +          } +          return result; +        }; +      } +      if (typeof thisArg != 'undefined') { +        if (argCount === 1) { +          return function(value) { +            return func.call(thisArg, value); +          }; +        } +        if (argCount === 2) { +          return function(a, b) { +            return func.call(thisArg, a, b); +          }; +        } +        if (argCount === 4) { +          return function(accumulator, value, index, object) { +            return func.call(thisArg, accumulator, value, index, object); +          }; +        } +        return function(value, index, object) { +          return func.call(thisArg, value, index, object); +        }; +      } +      return func; +    } + +    /** +     * Creates compiled iteration functions. +     * +     * @private +     * @param {Object} [options1, options2, ...] The compile options object(s). +     *  arrays - A string of code to determine if the iterable is an array or array-like. +     *  useHas - A boolean to specify using `hasOwnProperty` checks in the object loop. +     *  args - A string of comma separated arguments the iteration function will accept. +     *  top - A string of code to execute before the iteration branches. +     *  loop - A string of code to execute in the object loop. +     *  bottom - A string of code to execute after the iteration branches. +     * @returns {Function} Returns the compiled function. +     */ +    function createIterator() { +      var data = { +        // support properties +        'isKeysFast': isKeysFast, + +        // iterator options +        'arrays': 'isArray(iterable)', +        'bottom': '', +        'loop': '', +        'top': '', +        'useHas': true +      }; + +      // merge options into a template data object +      for (var object, index = 0; object = arguments[index]; index++) { +        for (var key in object) { +          data[key] = object[key]; +        } +      } +      var args = data.args; +      data.firstArg = /^[^,]+/.exec(args)[0]; + +      // create the function factory +      var factory = Function( +          'createCallback, hasOwnProperty, isArguments, isArray, isString, ' + +          'objectTypes, nativeKeys', +        'return function(' + args + ') {\n' + iteratorTemplate(data) + '\n}' +      ); +      // return the compiled function +      return factory( +        createCallback, hasOwnProperty, isArguments, isArray, isString, +        objectTypes, nativeKeys +      ); +    } + +    /** +     * A function compiled to iterate `arguments` objects, arrays, objects, and +     * strings consistenly across environments, executing the `callback` for each +     * element in the `collection`. The `callback` is bound to `thisArg` and invoked +     * with three arguments; (value, index|key, collection). Callbacks may exit +     * iteration early by explicitly returning `false`. +     * +     * @private +     * @type Function +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {Function} [callback=identity] The function called per iteration. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Array|Object|String} Returns `collection`. +     */ +    var each = createIterator(eachIteratorOptions); + +    /** +     * Used by `template` to escape characters for inclusion in compiled +     * string literals. +     * +     * @private +     * @param {String} match The matched character to escape. +     * @returns {String} Returns the escaped character. +     */ +    function escapeStringChar(match) { +      return '\\' + stringEscapes[match]; +    } + +    /** +     * Used by `escape` to convert characters to HTML entities. +     * +     * @private +     * @param {String} match The matched character to escape. +     * @returns {String} Returns the escaped character. +     */ +    function escapeHtmlChar(match) { +      return htmlEscapes[match]; +    } + +    /** +     * Checks if `value` is a DOM node in IE < 9. +     * +     * @private +     * @param {Mixed} value The value to check. +     * @returns {Boolean} Returns `true` if the `value` is a DOM node, else `false`. +     */ +    function isNode(value) { +      // IE < 9 presents DOM nodes as `Object` objects except they have `toString` +      // methods that are `typeof` "string" and still can coerce nodes to strings +      return typeof value.toString != 'function' && typeof (value + '') == 'string'; +    } + +    /** +     * A no-operation function. +     * +     * @private +     */ +    function noop() { +      // no operation performed +    } + +    /** +     * Slices the `collection` from the `start` index up to, but not including, +     * the `end` index. +     * +     * Note: This function is used, instead of `Array#slice`, to support node lists +     * in IE < 9 and to ensure dense arrays are returned. +     * +     * @private +     * @param {Array|Object|String} collection The collection to slice. +     * @param {Number} start The start index. +     * @param {Number} end The end index. +     * @returns {Array} Returns the new array. +     */ +    function slice(array, start, end) { +      start || (start = 0); +      if (typeof end == 'undefined') { +        end = array ? array.length : 0; +      } +      var index = -1, +          length = end - start || 0, +          result = Array(length < 0 ? 0 : length); + +      while (++index < length) { +        result[index] = array[start + index]; +      } +      return result; +    } + +    /** +     * Used by `unescape` to convert HTML entities to characters. +     * +     * @private +     * @param {String} match The matched character to unescape. +     * @returns {String} Returns the unescaped character. +     */ +    function unescapeHtmlChar(match) { +      return htmlUnescapes[match]; +    } + +    /*--------------------------------------------------------------------------*/ + +    /** +     * Checks if `value` is an `arguments` object. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Mixed} value The value to check. +     * @returns {Boolean} Returns `true`, if the `value` is an `arguments` object, else `false`. +     * @example +     * +     * (function() { return _.isArguments(arguments); })(1, 2, 3); +     * // => true +     * +     * _.isArguments([1, 2, 3]); +     * // => false +     */ +    function isArguments(value) { +      return toString.call(value) == argsClass; +    } + +    /** +     * Iterates over `object`'s own and inherited enumerable properties, executing +     * the `callback` for each property. The `callback` is bound to `thisArg` and +     * invoked with three arguments; (value, key, object). Callbacks may exit iteration +     * early by explicitly returning `false`. +     * +     * @static +     * @memberOf _ +     * @type Function +     * @category Objects +     * @param {Object} object The object to iterate over. +     * @param {Function} [callback=identity] The function called per iteration. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Object} Returns `object`. +     * @example +     * +     * function Dog(name) { +     *   this.name = name; +     * } +     * +     * Dog.prototype.bark = function() { +     *   alert('Woof, woof!'); +     * }; +     * +     * _.forIn(new Dog('Dagny'), function(value, key) { +     *   alert(key); +     * }); +     * // => alerts 'name' and 'bark' (order is not guaranteed) +     */ +    var forIn = createIterator(eachIteratorOptions, forOwnIteratorOptions, { +      'useHas': false +    }); + +    /** +     * Iterates over an object's own enumerable properties, executing the `callback` +     * for each property. The `callback` is bound to `thisArg` and invoked with three +     * arguments; (value, key, object). Callbacks may exit iteration early by explicitly +     * returning `false`. +     * +     * @static +     * @memberOf _ +     * @type Function +     * @category Objects +     * @param {Object} object The object to iterate over. +     * @param {Function} [callback=identity] The function called per iteration. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Object} Returns `object`. +     * @example +     * +     * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) { +     *   alert(key); +     * }); +     * // => alerts '0', '1', and 'length' (order is not guaranteed) +     */ +    var forOwn = createIterator(eachIteratorOptions, forOwnIteratorOptions); + +    /** +     * Checks if `value` is an array. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Mixed} value The value to check. +     * @returns {Boolean} Returns `true`, if the `value` is an array, else `false`. +     * @example +     * +     * (function() { return _.isArray(arguments); })(); +     * // => false +     * +     * _.isArray([1, 2, 3]); +     * // => true +     */ +    var isArray = nativeIsArray || function(value) { +      // `instanceof` may cause a memory leak in IE 7 if `value` is a host object +      // http://ajaxian.com/archives/working-aroung-the-instanceof-memory-leak +      return value instanceof Array || toString.call(value) == arrayClass; +    }; + +    /** +     * Creates an array composed of the own enumerable property names of `object`. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Object} object The object to inspect. +     * @returns {Array} Returns a new array of property names. +     * @example +     * +     * _.keys({ 'one': 1, 'two': 2, 'three': 3 }); +     * // => ['one', 'two', 'three'] (order is not guaranteed) +     */ +    var keys = !nativeKeys ? shimKeys : function(object) { +      if (!isObject(object)) { +        return []; +      } +      return nativeKeys(object); +    }; + +    /** +     * A fallback implementation of `isPlainObject` that checks if a given `value` +     * is an object created by the `Object` constructor, assuming objects created +     * by the `Object` constructor have no inherited enumerable properties and that +     * there are no `Object.prototype` extensions. +     * +     * @private +     * @param {Mixed} value The value to check. +     * @returns {Boolean} Returns `true`, if `value` is a plain object, else `false`. +     */ +    function shimIsPlainObject(value) { +      // avoid non-objects and false positives for `arguments` objects +      var result = false; +      if (!(value && typeof value == 'object') || isArguments(value)) { +        return result; +      } +      // check that the constructor is `Object` (i.e. `Object instanceof Object`) +      var ctor = value.constructor; +      if ((!isFunction(ctor)) || ctor instanceof ctor) { +        // In most environments an object's own properties are iterated before +        // its inherited properties. If the last iterated property is an object's +        // own property then there are no inherited enumerable properties. +        forIn(value, function(value, key) { +          result = key; +        }); +        return result === false || hasOwnProperty.call(value, result); +      } +      return result; +    } + +    /** +     * A fallback implementation of `Object.keys` that produces an array of the +     * given object's own enumerable property names. +     * +     * @private +     * @param {Object} object The object to inspect. +     * @returns {Array} Returns a new array of property names. +     */ +    function shimKeys(object) { +      var result = []; +      forOwn(object, function(value, key) { +        result.push(key); +      }); +      return result; +    } + +    /** +     * Used to convert characters to HTML entities: +     * +     * Though the `>` character is escaped for symmetry, characters like `>` and `/` +     * don't require escaping in HTML and have no special meaning unless they're part +     * of a tag or an unquoted attribute value. +     * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact") +     */ +    var htmlEscapes = { +      '&': '&', +      '<': '<', +      '>': '>', +      '"': '"', +      "'": ''' +    }; + +    /** Used to convert HTML entities to characters */ +    var htmlUnescapes = invert(htmlEscapes); + +    /*--------------------------------------------------------------------------*/ + +    /** +     * Assigns own enumerable properties of source object(s) to the destination +     * object. Subsequent sources will overwrite propery assignments of previous +     * sources. If a `callback` function is passed, it will be executed to produce +     * the assigned values. The `callback` is bound to `thisArg` and invoked with +     * two arguments; (objectValue, sourceValue). +     * +     * @static +     * @memberOf _ +     * @type Function +     * @alias extend +     * @category Objects +     * @param {Object} object The destination object. +     * @param {Object} [source1, source2, ...] The source objects. +     * @param {Function} [callback] The function to customize assigning values. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Object} Returns the destination object. +     * @example +     * +     * _.assign({ 'name': 'moe' }, { 'age': 40 }); +     * // => { 'name': 'moe', 'age': 40 } +     * +     * var defaults = _.partialRight(_.assign, function(a, b) { +     *   return typeof a == 'undefined' ? b : a; +     * }); +     * +     * var food = { 'name': 'apple' }; +     * defaults(food, { 'name': 'banana', 'type': 'fruit' }); +     * // => { 'name': 'apple', 'type': 'fruit' } +     */ +    var assign = createIterator(defaultsIteratorOptions, { +      'top': +        defaultsIteratorOptions.top.replace(';', +          ';\n' + +          "if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {\n" + +          '  var callback = createCallback(args[--argsLength - 1], args[argsLength--], 2);\n' + +          "} else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {\n" + +          '  callback = args[--argsLength];\n' + +          '}' +        ), +      'loop': 'result[index] = callback ? callback(result[index], iterable[index]) : iterable[index]' +    }); + +    /** +     * Creates a clone of `value`. If `deep` is `true`, nested objects will also +     * be cloned, otherwise they will be assigned by reference. If a `callback` +     * function is passed, it will be executed to produce the cloned values. If +     * `callback` returns `undefined`, cloning will be handled by the method instead. +     * The `callback` is bound to `thisArg` and invoked with one argument; (value). +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Mixed} value The value to clone. +     * @param {Boolean} [deep=false] A flag to indicate a deep clone. +     * @param {Function} [callback] The function to customize cloning values. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @param- {Array} [stackA=[]] Internally used to track traversed source objects. +     * @param- {Array} [stackB=[]] Internally used to associate clones with source counterparts. +     * @returns {Mixed} Returns the cloned `value`. +     * @example +     * +     * var stooges = [ +     *   { 'name': 'moe', 'age': 40 }, +     *   { 'name': 'larry', 'age': 50 } +     * ]; +     * +     * var shallow = _.clone(stooges); +     * shallow[0] === stooges[0]; +     * // => true +     * +     * var deep = _.clone(stooges, true); +     * deep[0] === stooges[0]; +     * // => false +     * +     * _.mixin({ +     *   'clone': _.partialRight(_.clone, function(value) { +     *     return _.isElement(value) ? value.cloneNode(false) : undefined; +     *   }) +     * }); +     * +     * var clone = _.clone(document.body); +     * clone.childNodes.length; +     * // => 0 +     */ +    function clone(value, deep, callback, thisArg, stackA, stackB) { +      var result = value; + +      // allows working with "Collections" methods without using their `callback` +      // argument, `index|key`, for this method's `callback` +      if (typeof deep == 'function') { +        thisArg = callback; +        callback = deep; +        deep = false; +      } +      if (typeof callback == 'function') { +        callback = typeof thisArg == 'undefined' ? callback : createCallback(callback, thisArg, 1); +        result = callback(result); + +        var done = typeof result != 'undefined'; +        if (!done) { +          result = value; +        } +      } +      // inspect [[Class]] +      var isObj = isObject(result); +      if (isObj) { +        var className = toString.call(result); +        if (!cloneableClasses[className]) { +          return result; +        } +        var isArr = isArray(result); +      } +      // shallow clone +      if (!isObj || !deep) { +        return isObj && !done +          ? (isArr ? slice(result) : assign({}, result)) +          : result; +      } +      var ctor = ctorByClass[className]; +      switch (className) { +        case boolClass: +        case dateClass: +          return done ? result : new ctor(+result); + +        case numberClass: +        case stringClass: +          return done ? result : new ctor(result); + +        case regexpClass: +          return done ? result : ctor(result.source, reFlags.exec(result)); +      } +      // check for circular references and return corresponding clone +      stackA || (stackA = []); +      stackB || (stackB = []); + +      var length = stackA.length; +      while (length--) { +        if (stackA[length] == value) { +          return stackB[length]; +        } +      } +      // init cloned object +      if (!done) { +        result = isArr ? ctor(result.length) : {}; + +        // add array properties assigned by `RegExp#exec` +        if (isArr) { +          if (hasOwnProperty.call(value, 'index')) { +            result.index = value.index; +          } +          if (hasOwnProperty.call(value, 'input')) { +            result.input = value.input; +          } +        } +      } +      // add the source value to the stack of traversed objects +      // and associate it with its clone +      stackA.push(value); +      stackB.push(result); + +      // recursively populate clone (susceptible to call stack limits) +      (isArr ? forEach : forOwn)(done ? result : value, function(objValue, key) { +        result[key] = clone(objValue, deep, callback, undefined, stackA, stackB); +      }); + +      return result; +    } + +    /** +     * Creates a deep clone of `value`. If a `callback` function is passed, it will +     * be executed to produce the cloned values. If `callback` returns the value it +     * was passed, cloning will be handled by the method instead. The `callback` is +     * bound to `thisArg` and invoked with one argument; (value). +     * +     * Note: This function is loosely based on the structured clone algorithm. Functions +     * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and +     * objects created by constructors other than `Object` are cloned to plain `Object` objects. +     * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Mixed} value The value to deep clone. +     * @param {Function} [callback] The function to customize cloning values. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Mixed} Returns the deep cloned `value`. +     * @example +     * +     * var stooges = [ +     *   { 'name': 'moe', 'age': 40 }, +     *   { 'name': 'larry', 'age': 50 } +     * ]; +     * +     * var deep = _.cloneDeep(stooges); +     * deep[0] === stooges[0]; +     * // => false +     * +     * var view = { +     *   'label': 'docs', +     *   'node': element +     * }; +     * +     * var clone = _.cloneDeep(view, function(value) { +     *   return _.isElement(value) ? value.cloneNode(true) : value; +     * }); +     * +     * clone.node == view.node; +     * // => false +     */ +    function cloneDeep(value, callback, thisArg) { +      return clone(value, true, callback, thisArg); +    } + +    /** +     * Assigns own enumerable properties of source object(s) to the destination +     * object for all destination properties that resolve to `undefined`. Once a +     * property is set, additional defaults of the same property will be ignored. +     * +     * @static +     * @memberOf _ +     * @type Function +     * @category Objects +     * @param {Object} object The destination object. +     * @param {Object} [source1, source2, ...] The source objects. +     * @param- {Object} [guard] Internally used to allow working with `_.reduce` +     *  without using its callback's `key` and `object` arguments as sources. +     * @returns {Object} Returns the destination object. +     * @example +     * +     * var food = { 'name': 'apple' }; +     * _.defaults(food, { 'name': 'banana', 'type': 'fruit' }); +     * // => { 'name': 'apple', 'type': 'fruit' } +     */ +    var defaults = createIterator(defaultsIteratorOptions); + +    /** +     * Creates a sorted array of all enumerable properties, own and inherited, +     * of `object` that have function values. +     * +     * @static +     * @memberOf _ +     * @alias methods +     * @category Objects +     * @param {Object} object The object to inspect. +     * @returns {Array} Returns a new array of property names that have function values. +     * @example +     * +     * _.functions(_); +     * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...] +     */ +    function functions(object) { +      var result = []; +      forIn(object, function(value, key) { +        if (isFunction(value)) { +          result.push(key); +        } +      }); +      return result.sort(); +    } + +    /** +     * Checks if the specified object `property` exists and is a direct property, +     * instead of an inherited property. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Object} object The object to check. +     * @param {String} property The property to check for. +     * @returns {Boolean} Returns `true` if key is a direct property, else `false`. +     * @example +     * +     * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b'); +     * // => true +     */ +    function has(object, property) { +      return object ? hasOwnProperty.call(object, property) : false; +    } + +    /** +     * Creates an object composed of the inverted keys and values of the given `object`. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Object} object The object to invert. +     * @returns {Object} Returns the created inverted object. +     * @example +     * +     *  _.invert({ 'first': 'moe', 'second': 'larry' }); +     * // => { 'moe': 'first', 'larry': 'second' } (order is not guaranteed) +     */ +    function invert(object) { +      var index = -1, +          props = keys(object), +          length = props.length, +          result = {}; + +      while (++index < length) { +        var key = props[index]; +        result[object[key]] = key; +      } +      return result; +    } + +    /** +     * Checks if `value` is a boolean value. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Mixed} value The value to check. +     * @returns {Boolean} Returns `true`, if the `value` is a boolean value, else `false`. +     * @example +     * +     * _.isBoolean(null); +     * // => false +     */ +    function isBoolean(value) { +      return value === true || value === false || toString.call(value) == boolClass; +    } + +    /** +     * Checks if `value` is a date. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Mixed} value The value to check. +     * @returns {Boolean} Returns `true`, if the `value` is a date, else `false`. +     * @example +     * +     * _.isDate(new Date); +     * // => true +     */ +    function isDate(value) { +      return value instanceof Date || toString.call(value) == dateClass; +    } + +    /** +     * Checks if `value` is a DOM element. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Mixed} value The value to check. +     * @returns {Boolean} Returns `true`, if the `value` is a DOM element, else `false`. +     * @example +     * +     * _.isElement(document.body); +     * // => true +     */ +    function isElement(value) { +      return value ? value.nodeType === 1 : false; +    } + +    /** +     * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a +     * length of `0` and objects with no own enumerable properties are considered +     * "empty". +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Array|Object|String} value The value to inspect. +     * @returns {Boolean} Returns `true`, if the `value` is empty, else `false`. +     * @example +     * +     * _.isEmpty([1, 2, 3]); +     * // => false +     * +     * _.isEmpty({}); +     * // => true +     * +     * _.isEmpty(''); +     * // => true +     */ +    function isEmpty(value) { +      var result = true; +      if (!value) { +        return result; +      } +      var className = toString.call(value), +          length = value.length; + +      if ((className == arrayClass || className == stringClass || +          className == argsClass) || +          (className == objectClass && typeof length == 'number' && isFunction(value.splice))) { +        return !length; +      } +      forOwn(value, function() { +        return (result = false); +      }); +      return result; +    } + +    /** +     * Performs a deep comparison between two values to determine if they are +     * equivalent to each other. If `callback` is passed, it will be executed to +     * compare values. If `callback` returns `undefined`, comparisons will be handled +     * by the method instead. The `callback` is bound to `thisArg` and invoked with +     * two arguments; (a, b). +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Mixed} a The value to compare. +     * @param {Mixed} b The other value to compare. +     * @param {Function} [callback] The function to customize comparing values. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @param- {Object} [stackA=[]] Internally used track traversed `a` objects. +     * @param- {Object} [stackB=[]] Internally used track traversed `b` objects. +     * @returns {Boolean} Returns `true`, if the values are equvalent, else `false`. +     * @example +     * +     * var moe = { 'name': 'moe', 'age': 40 }; +     * var copy = { 'name': 'moe', 'age': 40 }; +     * +     * moe == copy; +     * // => false +     * +     * _.isEqual(moe, copy); +     * // => true +     * +     * var words = ['hello', 'goodbye']; +     * var otherWords = ['hi', 'goodbye']; +     * +     * _.isEqual(words, otherWords, function(a, b) { +     *   var reGreet = /^(?:hello|hi)$/i, +     *       aGreet = _.isString(a) && reGreet.test(a), +     *       bGreet = _.isString(b) && reGreet.test(b); +     * +     *   return (aGreet || bGreet) ? (aGreet == bGreet) : undefined; +     * }); +     * // => true +     */ +    function isEqual(a, b, callback, thisArg, stackA, stackB) { +      // used to indicate that when comparing objects, `a` has at least the properties of `b` +      var whereIndicator = callback === indicatorObject; +      if (callback && !whereIndicator) { +        callback = typeof thisArg == 'undefined' ? callback : createCallback(callback, thisArg, 2); +        var result = callback(a, b); +        if (typeof result != 'undefined') { +          return !!result; +        } +      } +      // exit early for identical values +      if (a === b) { +        // treat `+0` vs. `-0` as not equal +        return a !== 0 || (1 / a == 1 / b); +      } +      var type = typeof a, +          otherType = typeof b; + +      // exit early for unlike primitive values +      if (a === a && +          (!a || (type != 'function' && type != 'object')) && +          (!b || (otherType != 'function' && otherType != 'object'))) { +        return false; +      } +      // exit early for `null` and `undefined`, avoiding ES3's Function#call behavior +      // http://es5.github.com/#x15.3.4.4 +      if (a == null || b == null) { +        return a === b; +      } +      // compare [[Class]] names +      var className = toString.call(a), +          otherClass = toString.call(b); + +      if (className == argsClass) { +        className = objectClass; +      } +      if (otherClass == argsClass) { +        otherClass = objectClass; +      } +      if (className != otherClass) { +        return false; +      } +      switch (className) { +        case boolClass: +        case dateClass: +          // 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 +a == +b; + +        case numberClass: +          // treat `NaN` vs. `NaN` as equal +          return a != +a +            ? b != +b +            // but treat `+0` vs. `-0` as not equal +            : (a == 0 ? (1 / a == 1 / b) : a == +b); + +        case regexpClass: +        case stringClass: +          // coerce regexes to strings (http://es5.github.com/#x15.10.6.4) +          // treat string primitives and their corresponding object instances as equal +          return a == b + ''; +      } +      var isArr = className == arrayClass; +      if (!isArr) { +        // unwrap any `lodash` wrapped values +        if (a.__wrapped__ || b.__wrapped__) { +          return isEqual(a.__wrapped__ || a, b.__wrapped__ || b, callback, thisArg, stackA, stackB); +        } +        // exit for functions and DOM nodes +        if (className != objectClass) { +          return false; +        } +        // in older versions of Opera, `arguments` objects have `Array` constructors +        var ctorA = a.constructor, +            ctorB = b.constructor; + +        // non `Object` object instances with different constructors are not equal +        if (ctorA != ctorB && !( +              isFunction(ctorA) && ctorA instanceof ctorA && +              isFunction(ctorB) && ctorB instanceof ctorB +            )) { +          return false; +        } +      } +      // assume cyclic structures are equal +      // the algorithm for detecting cyclic structures is adapted from ES 5.1 +      // section 15.12.3, abstract operation `JO` (http://es5.github.com/#x15.12.3) +      stackA || (stackA = []); +      stackB || (stackB = []); + +      var length = stackA.length; +      while (length--) { +        if (stackA[length] == a) { +          return stackB[length] == b; +        } +      } +      var size = 0; +      result = true; + +      // add `a` and `b` to the stack of traversed objects +      stackA.push(a); +      stackB.push(b); + +      // recursively compare objects and arrays (susceptible to call stack limits) +      if (isArr) { +        length = a.length; +        size = b.length; + +        // compare lengths to determine if a deep comparison is necessary +        result = size == a.length; +        if (!result && !whereIndicator) { +          return result; +        } +        // deep compare the contents, ignoring non-numeric properties +        while (size--) { +          var index = length, +              value = b[size]; + +          if (whereIndicator) { +            while (index--) { +              if ((result = isEqual(a[index], value, callback, thisArg, stackA, stackB))) { +                break; +              } +            } +          } else if (!(result = isEqual(a[size], value, callback, thisArg, stackA, stackB))) { +            break; +          } +        } +        return result; +      } +      // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys` +      // which, in this case, is more costly +      forIn(b, function(value, key, b) { +        if (hasOwnProperty.call(b, key)) { +          // count the number of properties. +          size++; +          // deep compare each property value. +          return (result = hasOwnProperty.call(a, key) && isEqual(a[key], value, callback, thisArg, stackA, stackB)); +        } +      }); + +      if (result && !whereIndicator) { +        // ensure both objects have the same number of properties +        forIn(a, function(value, key, a) { +          if (hasOwnProperty.call(a, key)) { +            // `size` will be `-1` if `a` has more properties than `b` +            return (result = --size > -1); +          } +        }); +      } +      return result; +    } + +    /** +     * Checks if `value` is, or can be coerced to, a finite number. +     * +     * Note: This is not the same as native `isFinite`, which will return true for +     * booleans and empty strings. See http://es5.github.com/#x15.1.2.5. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Mixed} value The value to check. +     * @returns {Boolean} Returns `true`, if the `value` is finite, else `false`. +     * @example +     * +     * _.isFinite(-101); +     * // => true +     * +     * _.isFinite('10'); +     * // => true +     * +     * _.isFinite(true); +     * // => false +     * +     * _.isFinite(''); +     * // => false +     * +     * _.isFinite(Infinity); +     * // => false +     */ +    function isFinite(value) { +      return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value)); +    } + +    /** +     * Checks if `value` is a function. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Mixed} value The value to check. +     * @returns {Boolean} Returns `true`, if the `value` is a function, else `false`. +     * @example +     * +     * _.isFunction(_); +     * // => true +     */ +    function isFunction(value) { +      return typeof value == 'function'; +    } + +    /** +     * Checks if `value` is the language type of Object. +     * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Mixed} value The value to check. +     * @returns {Boolean} Returns `true`, if the `value` is an object, else `false`. +     * @example +     * +     * _.isObject({}); +     * // => true +     * +     * _.isObject([1, 2, 3]); +     * // => true +     * +     * _.isObject(1); +     * // => false +     */ +    function isObject(value) { +      // check if the value is the ECMAScript language type of Object +      // http://es5.github.com/#x8 +      // and avoid a V8 bug +      // http://code.google.com/p/v8/issues/detail?id=2291 +      return value ? objectTypes[typeof value] : false; +    } + +    /** +     * Checks if `value` is `NaN`. +     * +     * Note: This is not the same as native `isNaN`, which will return `true` for +     * `undefined` and other values. See http://es5.github.com/#x15.1.2.4. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Mixed} value The value to check. +     * @returns {Boolean} Returns `true`, if the `value` is `NaN`, else `false`. +     * @example +     * +     * _.isNaN(NaN); +     * // => true +     * +     * _.isNaN(new Number(NaN)); +     * // => true +     * +     * isNaN(undefined); +     * // => true +     * +     * _.isNaN(undefined); +     * // => false +     */ +    function isNaN(value) { +      // `NaN` as a primitive is the only value that is not equal to itself +      // (perform the [[Class]] check first to avoid errors with some host objects in IE) +      return isNumber(value) && value != +value +    } + +    /** +     * Checks if `value` is `null`. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Mixed} value The value to check. +     * @returns {Boolean} Returns `true`, if the `value` is `null`, else `false`. +     * @example +     * +     * _.isNull(null); +     * // => true +     * +     * _.isNull(undefined); +     * // => false +     */ +    function isNull(value) { +      return value === null; +    } + +    /** +     * Checks if `value` is a number. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Mixed} value The value to check. +     * @returns {Boolean} Returns `true`, if the `value` is a number, else `false`. +     * @example +     * +     * _.isNumber(8.4 * 5); +     * // => true +     */ +    function isNumber(value) { +      return typeof value == 'number' || toString.call(value) == numberClass; +    } + +    /** +     * Checks if a given `value` is an object created by the `Object` constructor. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Mixed} value The value to check. +     * @returns {Boolean} Returns `true`, if `value` is a plain object, else `false`. +     * @example +     * +     * function Stooge(name, age) { +     *   this.name = name; +     *   this.age = age; +     * } +     * +     * _.isPlainObject(new Stooge('moe', 40)); +     * // => false +     * +     * _.isPlainObject([1, 2, 3]); +     * // => false +     * +     * _.isPlainObject({ 'name': 'moe', 'age': 40 }); +     * // => true +     */ +    var isPlainObject = function(value) { +      if (!(value && typeof value == 'object')) { +        return false; +      } +      var valueOf = value.valueOf, +          objProto = typeof valueOf == 'function' && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto); + +      return objProto +        ? value == objProto || (getPrototypeOf(value) == objProto && !isArguments(value)) +        : shimIsPlainObject(value); +    }; + +    /** +     * Checks if `value` is a regular expression. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Mixed} value The value to check. +     * @returns {Boolean} Returns `true`, if the `value` is a regular expression, else `false`. +     * @example +     * +     * _.isRegExp(/moe/); +     * // => true +     */ +    function isRegExp(value) { +      return value instanceof RegExp || toString.call(value) == regexpClass; +    } + +    /** +     * Checks if `value` is a string. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Mixed} value The value to check. +     * @returns {Boolean} Returns `true`, if the `value` is a string, else `false`. +     * @example +     * +     * _.isString('moe'); +     * // => true +     */ +    function isString(value) { +      return typeof value == 'string' || toString.call(value) == stringClass; +    } + +    /** +     * Checks if `value` is `undefined`. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Mixed} value The value to check. +     * @returns {Boolean} Returns `true`, if the `value` is `undefined`, else `false`. +     * @example +     * +     * _.isUndefined(void 0); +     * // => true +     */ +    function isUndefined(value) { +      return typeof value == 'undefined'; +    } + +    /** +     * Recursively merges own enumerable properties of the source object(s), that +     * don't resolve to `undefined`, into the destination object. Subsequent sources +     * will overwrite propery assignments of previous sources. If a `callback` function +     * is passed, it will be executed to produce the merged values of the destination +     * and source properties. If `callback` returns `undefined`, merging will be +     * handled by the method instead. The `callback` is bound to `thisArg` and +     * invoked with two arguments; (objectValue, sourceValue). +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Object} object The destination object. +     * @param {Object} [source1, source2, ...] The source objects. +     * @param {Function} [callback] The function to customize merging properties. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @param- {Object} [deepIndicator] Internally used to indicate that `stackA` +     *  and `stackB` are arrays of traversed objects instead of source objects. +     * @param- {Array} [stackA=[]] Internally used to track traversed source objects. +     * @param- {Array} [stackB=[]] Internally used to associate values with their +     *  source counterparts. +     * @returns {Object} Returns the destination object. +     * @example +     * +     * var names = { +     *   'stooges': [ +     *     { 'name': 'moe' }, +     *     { 'name': 'larry' } +     *   ] +     * }; +     * +     * var ages = { +     *   'stooges': [ +     *     { 'age': 40 }, +     *     { 'age': 50 } +     *   ] +     * }; +     * +     * _.merge(names, ages); +     * // => { 'stooges': [{ 'name': 'moe', 'age': 40 }, { 'name': 'larry', 'age': 50 }] } +     * +     * var food = { +     *   'fruits': ['apple'], +     *   'vegetables': ['beet'] +     * }; +     * +     * var otherFood = { +     *   'fruits': ['banana'], +     *   'vegetables': ['carrot'] +     * }; +     * +     * _.merge(food, otherFood, function(a, b) { +     *   return _.isArray(a) ? a.concat(b) : undefined; +     * }); +     * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] } +     */ +    function merge(object, source, deepIndicator) { +      var args = arguments, +          index = 0, +          length = 2; + +      if (!isObject(object)) { +        return object; +      } +      if (deepIndicator === indicatorObject) { +        var callback = args[3], +            stackA = args[4], +            stackB = args[5]; +      } else { +        stackA = []; +        stackB = []; + +        // allows working with `_.reduce` and `_.reduceRight` without +        // using their `callback` arguments, `index|key` and `collection` +        if (typeof deepIndicator != 'number') { +          length = args.length; +        } +        if (length > 3 && typeof args[length - 2] == 'function') { +          callback = createCallback(args[--length - 1], args[length--], 2); +        } else if (length > 2 && typeof args[length - 1] == 'function') { +          callback = args[--length]; +        } +      } +      while (++index < length) { +        (isArray(args[index]) ? forEach : forOwn)(args[index], function(source, key) { +          var found, +              isArr, +              result = source, +              value = object[key]; + +          if (source && ((isArr = isArray(source)) || isPlainObject(source))) { +            // avoid merging previously merged cyclic sources +            var stackLength = stackA.length; +            while (stackLength--) { +              if ((found = stackA[stackLength] == source)) { +                value = stackB[stackLength]; +                break; +              } +            } +            if (!found) { +              value = isArr +                ? (isArray(value) ? value : []) +                : (isPlainObject(value) ? value : {}); + +              if (callback) { +                result = callback(value, source); +                if (typeof result != 'undefined') { +                  value = result; +                } +              } +              // add `source` and associated `value` to the stack of traversed objects +              stackA.push(source); +              stackB.push(value); + +              // recursively merge objects and arrays (susceptible to call stack limits) +              if (!callback) { +                value = merge(value, source, indicatorObject, callback, stackA, stackB); +              } +            } +          } +          else { +            if (callback) { +              result = callback(value, source); +              if (typeof result == 'undefined') { +                result = source; +              } +            } +            if (typeof result != 'undefined') { +              value = result; +            } +          } +          object[key] = value; +        }); +      } +      return object; +    } + +    /** +     * Creates a shallow clone of `object` excluding the specified properties. +     * Property names may be specified as individual arguments or as arrays of +     * property names. If a `callback` function is passed, it will be executed +     * for each property in the `object`, omitting the properties `callback` +     * returns truthy for. The `callback` is bound to `thisArg` and invoked +     * with three arguments; (value, key, object). +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Object} object The source object. +     * @param {Function|String} callback|[prop1, prop2, ...] The properties to omit +     *  or the function called per iteration. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Object} Returns an object without the omitted properties. +     * @example +     * +     * _.omit({ 'name': 'moe', 'age': 40 }, 'age'); +     * // => { 'name': 'moe' } +     * +     * _.omit({ 'name': 'moe', 'age': 40 }, function(value) { +     *   return typeof value == 'number'; +     * }); +     * // => { 'name': 'moe' } +     */ +    function omit(object, callback, thisArg) { +      var isFunc = typeof callback == 'function', +          result = {}; + +      if (isFunc) { +        callback = createCallback(callback, thisArg); +      } else { +        var props = concat.apply(arrayRef, arguments); +      } +      forIn(object, function(value, key, object) { +        if (isFunc +              ? !callback(value, key, object) +              : indexOf(props, key, 1) < 0 +            ) { +          result[key] = value; +        } +      }); +      return result; +    } + +    /** +     * Creates a two dimensional array of the given object's key-value pairs, +     * i.e. `[[key1, value1], [key2, value2]]`. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Object} object The object to inspect. +     * @returns {Array} Returns new array of key-value pairs. +     * @example +     * +     * _.pairs({ 'moe': 30, 'larry': 40 }); +     * // => [['moe', 30], ['larry', 40]] (order is not guaranteed) +     */ +    function pairs(object) { +      var index = -1, +          props = keys(object), +          length = props.length, +          result = Array(length); + +      while (++index < length) { +        var key = props[index]; +        result[index] = [key, object[key]]; +      } +      return result; +    } + +    /** +     * Converts the given `value` into an integer of the specified `radix`. +     * +     * Note: This method avoids differences in native ES3 and ES5 `parseInt` +     * implementations. See http://es5.github.com/#E. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Mixed} value The value to parse. +     * @returns {Number} Returns the new integer value. +     * @example +     * +     * _.parseInt('08'); +     * // => 8 +     */ +    var parseInt = nativeParseInt('08') == 8 ? nativeParseInt : function(value, radix) { +      // Firefox and Opera still follow the ES3 specified implementation of `parseInt` +      return nativeParseInt(isString(value) ? value.replace(/^0+(?=.$)/, '') : value, radix || 0); +    }; + +    /** +     * Creates a shallow clone of `object` composed of the specified properties. +     * Property names may be specified as individual arguments or as arrays of property +     * names. If `callback` is passed, it will be executed for each property in the +     * `object`, picking the properties `callback` returns truthy for. The `callback` +     * is bound to `thisArg` and invoked with three arguments; (value, key, object). +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Object} object The source object. +     * @param {Array|Function|String} callback|[prop1, prop2, ...] The function called +     *  per iteration or properties to pick, either as individual arguments or arrays. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Object} Returns an object composed of the picked properties. +     * @example +     * +     * _.pick({ 'name': 'moe', '_userid': 'moe1' }, 'name'); +     * // => { 'name': 'moe' } +     * +     * _.pick({ 'name': 'moe', '_userid': 'moe1' }, function(value, key) { +     *   return key.charAt(0) != '_'; +     * }); +     * // => { 'name': 'moe' } +     */ +    function pick(object, callback, thisArg) { +      var result = {}; +      if (typeof callback != 'function') { +        var index = 0, +            props = concat.apply(arrayRef, arguments), +            length = isObject(object) ? props.length : 0; + +        while (++index < length) { +          var key = props[index]; +          if (key in object) { +            result[key] = object[key]; +          } +        } +      } else { +        callback = createCallback(callback, thisArg); +        forIn(object, function(value, key, object) { +          if (callback(value, key, object)) { +            result[key] = value; +          } +        }); +      } +      return result; +    } + +    /** +     * Creates an array composed of the own enumerable property values of `object`. +     * +     * @static +     * @memberOf _ +     * @category Objects +     * @param {Object} object The object to inspect. +     * @returns {Array} Returns a new array of property values. +     * @example +     * +     * _.values({ 'one': 1, 'two': 2, 'three': 3 }); +     * // => [1, 2, 3] +     */ +    function values(object) { +      var index = -1, +          props = keys(object), +          length = props.length, +          result = Array(length); + +      while (++index < length) { +        result[index] = object[props[index]]; +      } +      return result; +    } + +    /*--------------------------------------------------------------------------*/ + +    /** +     * Creates an array of elements from the specified indexes, or keys, of the +     * `collection`. Indexes may be specified as individual arguments or as arrays +     * of indexes. +     * +     * @static +     * @memberOf _ +     * @category Collections +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {Array|Number|String} [index1, index2, ...] The indexes of +     *  `collection` to retrieve, either as individual arguments or arrays. +     * @returns {Array} Returns a new array of elements corresponding to the +     *  provided indexes. +     * @example +     * +     * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]); +     * // => ['a', 'c', 'e'] +     * +     * _.at(['moe', 'larry', 'curly'], 0, 2); +     * // => ['moe', 'curly'] +     */ +    function at(collection) { +      var index = -1, +          props = concat.apply(arrayRef, slice(arguments, 1)), +          length = props.length, +          result = Array(length); + +      while(++index < length) { +        result[index] = collection[props[index]]; +      } +      return result; +    } + +    /** +     * Checks if a given `target` element is present in a `collection` using strict +     * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used +     * as the offset from the end of the collection. +     * +     * @static +     * @memberOf _ +     * @alias include +     * @category Collections +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {Mixed} target The value to check for. +     * @param {Number} [fromIndex=0] The index to search from. +     * @returns {Boolean} Returns `true` if the `target` element is found, else `false`. +     * @example +     * +     * _.contains([1, 2, 3], 1); +     * // => true +     * +     * _.contains([1, 2, 3], 1, 2); +     * // => false +     * +     * _.contains({ 'name': 'moe', 'age': 40 }, 'moe'); +     * // => true +     * +     * _.contains('curly', 'ur'); +     * // => true +     */ +    function contains(collection, target, fromIndex) { +      var index = -1, +          length = collection ? collection.length : 0, +          result = false; + +      fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0; +      if (typeof length == 'number') { +        result = (isString(collection) +          ? collection.indexOf(target, fromIndex) +          : indexOf(collection, target, fromIndex) +        ) > -1; +      } else { +        each(collection, function(value) { +          if (++index >= fromIndex) { +            return !(result = value === target); +          } +        }); +      } +      return result; +    } + +    /** +     * Creates an object composed of keys returned from running each element of the +     * `collection` through the given `callback`. The corresponding value of each key +     * is the number of times the key was returned by the `callback`. The `callback` +     * is bound to `thisArg` and invoked with three arguments; (value, index|key, collection). +     * +     * If a property name is passed for `callback`, the created "_.pluck" style +     * callback will return the property value of the given element. +     * +     * If an object is passed for `callback`, the created "_.where" style callback +     * will return `true` for elements that have the propeties of the given object, +     * else `false`. +     * +     * @static +     * @memberOf _ +     * @category Collections +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {Function|Object|String} [callback=identity] The function called per +     *  iteration. If a property name or object is passed, it will be used to create +     *  a "_.pluck" or "_.where" style callback, respectively. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Object} Returns the composed aggregate object. +     * @example +     * +     * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); }); +     * // => { '4': 1, '6': 2 } +     * +     * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math); +     * // => { '4': 1, '6': 2 } +     * +     * _.countBy(['one', 'two', 'three'], 'length'); +     * // => { '3': 2, '5': 1 } +     */ +    function countBy(collection, callback, thisArg) { +      var result = {}; +      callback = createCallback(callback, thisArg); + +      forEach(collection, function(value, key, collection) { +        key = callback(value, key, collection) + ''; +        (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1); +      }); +      return result; +    } + +    /** +     * Checks if the `callback` returns a truthy value for **all** elements of a +     * `collection`. The `callback` is bound to `thisArg` and invoked with three +     * arguments; (value, index|key, collection). +     * +     * If a property name is passed for `callback`, the created "_.pluck" style +     * callback will return the property value of the given element. +     * +     * If an object is passed for `callback`, the created "_.where" style callback +     * will return `true` for elements that have the propeties of the given object, +     * else `false`. +     * +     * @static +     * @memberOf _ +     * @alias all +     * @category Collections +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {Function|Object|String} [callback=identity] The function called per +     *  iteration. If a property name or object is passed, it will be used to create +     *  a "_.pluck" or "_.where" style callback, respectively. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Boolean} Returns `true` if all elements pass the callback check, +     *  else `false`. +     * @example +     * +     * _.every([true, 1, null, 'yes'], Boolean); +     * // => false +     * +     * var stooges = [ +     *   { 'name': 'moe', 'age': 40 }, +     *   { 'name': 'larry', 'age': 50 } +     * ]; +     * +     * // using "_.pluck" callback shorthand +     * _.every(stooges, 'age'); +     * // => true +     * +     * // using "_.where" callback shorthand +     * _.every(stooges, { 'age': 50 }); +     * // => false +     */ +    function every(collection, callback, thisArg) { +      var result = true; +      callback = createCallback(callback, thisArg); + +      if (isArray(collection)) { +        var index = -1, +            length = collection.length; + +        while (++index < length) { +          if (!(result = !!callback(collection[index], index, collection))) { +            break; +          } +        } +      } else { +        each(collection, function(value, index, collection) { +          return (result = !!callback(value, index, collection)); +        }); +      } +      return result; +    } + +    /** +     * Examines each element in a `collection`, returning an array of all elements +     * the `callback` returns truthy for. The `callback` is bound to `thisArg` and +     * invoked with three arguments; (value, index|key, collection). +     * +     * If a property name is passed for `callback`, the created "_.pluck" style +     * callback will return the property value of the given element. +     * +     * If an object is passed for `callback`, the created "_.where" style callback +     * will return `true` for elements that have the propeties of the given object, +     * else `false`. +     * +     * @static +     * @memberOf _ +     * @alias select +     * @category Collections +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {Function|Object|String} [callback=identity] The function called per +     *  iteration. If a property name or object is passed, it will be used to create +     *  a "_.pluck" or "_.where" style callback, respectively. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Array} Returns a new array of elements that passed the callback check. +     * @example +     * +     * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); +     * // => [2, 4, 6] +     * +     * var food = [ +     *   { 'name': 'apple',  'organic': false, 'type': 'fruit' }, +     *   { 'name': 'carrot', 'organic': true,  'type': 'vegetable' } +     * ]; +     * +     * // using "_.pluck" callback shorthand +     * _.filter(food, 'organic'); +     * // => [{ 'name': 'carrot', 'organic': true, 'type': 'vegetable' }] +     * +     * // using "_.where" callback shorthand +     * _.filter(food, { 'type': 'fruit' }); +     * // => [{ 'name': 'apple', 'organic': false, 'type': 'fruit' }] +     */ +    function filter(collection, callback, thisArg) { +      var result = []; +      callback = createCallback(callback, thisArg); + +      if (isArray(collection)) { +        var index = -1, +            length = collection.length; + +        while (++index < length) { +          var value = collection[index]; +          if (callback(value, index, collection)) { +            result.push(value); +          } +        } +      } else { +        each(collection, function(value, index, collection) { +          if (callback(value, index, collection)) { +            result.push(value); +          } +        }); +      } +      return result; +    } + +    /** +     * Examines each element in a `collection`, returning the first that the `callback` +     * returns truthy for. The `callback` is bound to `thisArg` and invoked with three +     * arguments; (value, index|key, collection). +     * +     * If a property name is passed for `callback`, the created "_.pluck" style +     * callback will return the property value of the given element. +     * +     * If an object is passed for `callback`, the created "_.where" style callback +     * will return `true` for elements that have the propeties of the given object, +     * else `false`. +     * +     * @static +     * @memberOf _ +     * @alias detect +     * @category Collections +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {Function|Object|String} [callback=identity] The function called per +     *  iteration. If a property name or object is passed, it will be used to create +     *  a "_.pluck" or "_.where" style callback, respectively. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Mixed} Returns the element that passed the callback check, +     *  else `undefined`. +     * @example +     * +     * var even = _.find([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); +     * // => 2 +     * +     * var food = [ +     *   { 'name': 'apple',  'organic': false, 'type': 'fruit' }, +     *   { 'name': 'banana', 'organic': true,  'type': 'fruit' }, +     *   { 'name': 'beet',   'organic': false, 'type': 'vegetable' }, +     *   { 'name': 'carrot', 'organic': true,  'type': 'vegetable' } +     * ]; +     * +     * // using "_.where" callback shorthand +     * var veggie = _.find(food, { 'type': 'vegetable' }); +     * // => { 'name': 'beet', 'organic': false, 'type': 'vegetable' } +     * +     * // using "_.pluck" callback shorthand +     * var healthy = _.find(food, 'organic'); +     * // => { 'name': 'banana', 'organic': true, 'type': 'fruit' } +     */ +    function find(collection, callback, thisArg) { +      var result; +      callback = createCallback(callback, thisArg); + +      forEach(collection, function(value, index, collection) { +        if (callback(value, index, collection)) { +          result = value; +          return false; +        } +      }); +      return result; +    } + +    /** +     * Iterates over a `collection`, executing the `callback` for each element in +     * the `collection`. The `callback` is bound to `thisArg` and invoked with three +     * arguments; (value, index|key, collection). Callbacks may exit iteration early +     * by explicitly returning `false`. +     * +     * @static +     * @memberOf _ +     * @alias each +     * @category Collections +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {Function} [callback=identity] The function called per iteration. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Array|Object|String} Returns `collection`. +     * @example +     * +     * _([1, 2, 3]).forEach(alert).join(','); +     * // => alerts each number and returns '1,2,3' +     * +     * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, alert); +     * // => alerts each number value (order is not guaranteed) +     */ +    function forEach(collection, callback, thisArg) { +      if (callback && typeof thisArg == 'undefined' && isArray(collection)) { +        var index = -1, +            length = collection.length; + +        while (++index < length) { +          if (callback(collection[index], index, collection) === false) { +            break; +          } +        } +      } else { +        each(collection, callback, thisArg); +      } +      return collection; +    } + +    /** +     * Creates an object composed of keys returned from running each element of the +     * `collection` through the `callback`. The corresponding value of each key is +     * an array of elements passed to `callback` that returned the key. The `callback` +     * is bound to `thisArg` and invoked with three arguments; (value, index|key, collection). +     * +     * If a property name is passed for `callback`, the created "_.pluck" style +     * callback will return the property value of the given element. +     * +     * If an object is passed for `callback`, the created "_.where" style callback +     * will return `true` for elements that have the propeties of the given object, +     * else `false` +     * +     * @static +     * @memberOf _ +     * @category Collections +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {Function|Object|String} [callback=identity] The function called per +     *  iteration. If a property name or object is passed, it will be used to create +     *  a "_.pluck" or "_.where" style callback, respectively. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Object} Returns the composed aggregate object. +     * @example +     * +     * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); }); +     * // => { '4': [4.2], '6': [6.1, 6.4] } +     * +     * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math); +     * // => { '4': [4.2], '6': [6.1, 6.4] } +     * +     * // using "_.pluck" callback shorthand +     * _.groupBy(['one', 'two', 'three'], 'length'); +     * // => { '3': ['one', 'two'], '5': ['three'] } +     */ +    function groupBy(collection, callback, thisArg) { +      var result = {}; +      callback = createCallback(callback, thisArg); + +      forEach(collection, function(value, key, collection) { +        key = callback(value, key, collection) + ''; +        (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value); +      }); +      return result; +    } + +    /** +     * Invokes the method named by `methodName` on each element in the `collection`, +     * returning an array of the results of each invoked method. Additional arguments +     * will be passed to each invoked method. If `methodName` is a function, it will +     * be invoked for, and `this` bound to, each element in the `collection`. +     * +     * @static +     * @memberOf _ +     * @category Collections +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {Function|String} methodName The name of the method to invoke or +     *  the function invoked per iteration. +     * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with. +     * @returns {Array} Returns a new array of the results of each invoked method. +     * @example +     * +     * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); +     * // => [[1, 5, 7], [1, 2, 3]] +     * +     * _.invoke([123, 456], String.prototype.split, ''); +     * // => [['1', '2', '3'], ['4', '5', '6']] +     */ +    function invoke(collection, methodName) { +      var args = slice(arguments, 2), +          index = -1, +          isFunc = typeof methodName == 'function', +          length = collection ? collection.length : 0, +          result = Array(typeof length == 'number' ? length : 0); + +      forEach(collection, function(value) { +        result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args); +      }); +      return result; +    } + +    /** +     * Creates an array of values by running each element in the `collection` +     * through the `callback`. The `callback` is bound to `thisArg` and invoked with +     * three arguments; (value, index|key, collection). +     * +     * If a property name is passed for `callback`, the created "_.pluck" style +     * callback will return the property value of the given element. +     * +     * If an object is passed for `callback`, the created "_.where" style callback +     * will return `true` for elements that have the propeties of the given object, +     * else `false`. +     * +     * @static +     * @memberOf _ +     * @alias collect +     * @category Collections +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {Function|Object|String} [callback=identity] The function called per +     *  iteration. If a property name or object is passed, it will be used to create +     *  a "_.pluck" or "_.where" style callback, respectively. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Array} Returns a new array of the results of each `callback` execution. +     * @example +     * +     * _.map([1, 2, 3], function(num) { return num * 3; }); +     * // => [3, 6, 9] +     * +     * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; }); +     * // => [3, 6, 9] (order is not guaranteed) +     * +     * var stooges = [ +     *   { 'name': 'moe', 'age': 40 }, +     *   { 'name': 'larry', 'age': 50 } +     * ]; +     * +     * // using "_.pluck" callback shorthand +     * _.map(stooges, 'name'); +     * // => ['moe', 'larry'] +     */ +    function map(collection, callback, thisArg) { +      var index = -1, +          length = collection ? collection.length : 0, +          result = Array(typeof length == 'number' ? length : 0); + +      callback = createCallback(callback, thisArg); +      if (isArray(collection)) { +        while (++index < length) { +          result[index] = callback(collection[index], index, collection); +        } +      } else { +        each(collection, function(value, key, collection) { +          result[++index] = callback(value, key, collection); +        }); +      } +      return result; +    } + +    /** +     * Retrieves the maximum value of an `array`. If `callback` is passed, +     * it will be executed for each value in the `array` to generate the +     * criterion by which the value is ranked. The `callback` is bound to +     * `thisArg` and invoked with three arguments; (value, index, collection). +     * +     * If a property name is passed for `callback`, the created "_.pluck" style +     * callback will return the property value of the given element. +     * +     * If an object is passed for `callback`, the created "_.where" style callback +     * will return `true` for elements that have the propeties of the given object, +     * else `false`. +     * +     * @static +     * @memberOf _ +     * @category Collections +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {Function|Object|String} [callback=identity] The function called per +     *  iteration. If a property name or object is passed, it will be used to create +     *  a "_.pluck" or "_.where" style callback, respectively. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Mixed} Returns the maximum value. +     * @example +     * +     * _.max([4, 2, 8, 6]); +     * // => 8 +     * +     * var stooges = [ +     *   { 'name': 'moe', 'age': 40 }, +     *   { 'name': 'larry', 'age': 50 } +     * ]; +     * +     * _.max(stooges, function(stooge) { return stooge.age; }); +     * // => { 'name': 'larry', 'age': 50 }; +     * +     * // using "_.pluck" callback shorthand +     * _.max(stooges, 'age'); +     * // => { 'name': 'larry', 'age': 50 }; +     */ +    function max(collection, callback, thisArg) { +      var computed = -Infinity, +          result = computed; + +      if (!callback && isArray(collection)) { +        var index = -1, +            length = collection.length; + +        while (++index < length) { +          var value = collection[index]; +          if (value > result) { +            result = value; +          } +        } +      } else { +        callback = !callback && isString(collection) +          ? charAtCallback +          : createCallback(callback, thisArg); + +        each(collection, function(value, index, collection) { +          var current = callback(value, index, collection); +          if (current > computed) { +            computed = current; +            result = value; +          } +        }); +      } +      return result; +    } + +    /** +     * Retrieves the minimum value of an `array`. If `callback` is passed, +     * it will be executed for each value in the `array` to generate the +     * criterion by which the value is ranked. The `callback` is bound to `thisArg` +     * and invoked with three arguments; (value, index, collection). +     * +     * If a property name is passed for `callback`, the created "_.pluck" style +     * callback will return the property value of the given element. +     * +     * If an object is passed for `callback`, the created "_.where" style callback +     * will return `true` for elements that have the propeties of the given object, +     * else `false`. +     * +     * @static +     * @memberOf _ +     * @category Collections +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {Function|Object|String} [callback=identity] The function called per +     *  iteration. If a property name or object is passed, it will be used to create +     *  a "_.pluck" or "_.where" style callback, respectively. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Mixed} Returns the minimum value. +     * @example +     * +     * _.min([4, 2, 8, 6]); +     * // => 2 +     * +     * var stooges = [ +     *   { 'name': 'moe', 'age': 40 }, +     *   { 'name': 'larry', 'age': 50 } +     * ]; +     * +     * _.min(stooges, function(stooge) { return stooge.age; }); +     * // => { 'name': 'moe', 'age': 40 }; +     * +     * // using "_.pluck" callback shorthand +     * _.min(stooges, 'age'); +     * // => { 'name': 'moe', 'age': 40 }; +     */ +    function min(collection, callback, thisArg) { +      var computed = Infinity, +          result = computed; + +      if (!callback && isArray(collection)) { +        var index = -1, +            length = collection.length; + +        while (++index < length) { +          var value = collection[index]; +          if (value < result) { +            result = value; +          } +        } +      } else { +        callback = !callback && isString(collection) +          ? charAtCallback +          : createCallback(callback, thisArg); + +        each(collection, function(value, index, collection) { +          var current = callback(value, index, collection); +          if (current < computed) { +            computed = current; +            result = value; +          } +        }); +      } +      return result; +    } + +    /** +     * Retrieves the value of a specified property from all elements in the `collection`. +     * +     * @static +     * @memberOf _ +     * @type Function +     * @category Collections +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {String} property The property to pluck. +     * @returns {Array} Returns a new array of property values. +     * @example +     * +     * var stooges = [ +     *   { 'name': 'moe', 'age': 40 }, +     *   { 'name': 'larry', 'age': 50 } +     * ]; +     * +     * _.pluck(stooges, 'name'); +     * // => ['moe', 'larry'] +     */ +    var pluck = map; + +    /** +     * Reduces a `collection` to a value that is the accumulated result of running +     * each element in the `collection` through the `callback`, where each successive +     * `callback` execution consumes the return value of the previous execution. +     * If `accumulator` is not passed, the first element of the `collection` will be +     * used as the initial `accumulator` value. The `callback` is bound to `thisArg` +     * and invoked with four arguments; (accumulator, value, index|key, collection). +     * +     * @static +     * @memberOf _ +     * @alias foldl, inject +     * @category Collections +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {Function} [callback=identity] The function called per iteration. +     * @param {Mixed} [accumulator] Initial value of the accumulator. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Mixed} Returns the accumulated value. +     * @example +     * +     * var sum = _.reduce([1, 2, 3], function(sum, num) { +     *   return sum + num; +     * }); +     * // => 6 +     * +     * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) { +     *   result[key] = num * 3; +     *   return result; +     * }, {}); +     * // => { 'a': 3, 'b': 6, 'c': 9 } +     */ +    function reduce(collection, callback, accumulator, thisArg) { +      var noaccum = arguments.length < 3; +      callback = createCallback(callback, thisArg, 4); + +      if (isArray(collection)) { +        var index = -1, +            length = collection.length; + +        if (noaccum) { +          accumulator = collection[++index]; +        } +        while (++index < length) { +          accumulator = callback(accumulator, collection[index], index, collection); +        } +      } else { +        each(collection, function(value, index, collection) { +          accumulator = noaccum +            ? (noaccum = false, value) +            : callback(accumulator, value, index, collection) +        }); +      } +      return accumulator; +    } + +    /** +     * This method is similar to `_.reduce`, except that it iterates over a +     * `collection` from right to left. +     * +     * @static +     * @memberOf _ +     * @alias foldr +     * @category Collections +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {Function} [callback=identity] The function called per iteration. +     * @param {Mixed} [accumulator] Initial value of the accumulator. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Mixed} Returns the accumulated value. +     * @example +     * +     * var list = [[0, 1], [2, 3], [4, 5]]; +     * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []); +     * // => [4, 5, 2, 3, 0, 1] +     */ +    function reduceRight(collection, callback, accumulator, thisArg) { +      var iterable = collection, +          length = collection ? collection.length : 0, +          noaccum = arguments.length < 3; + +      if (typeof length != 'number') { +        var props = keys(collection); +        length = props.length; +      } +      callback = createCallback(callback, thisArg, 4); +      forEach(collection, function(value, index, collection) { +        index = props ? props[--length] : --length; +        accumulator = noaccum +          ? (noaccum = false, iterable[index]) +          : callback(accumulator, iterable[index], index, collection); +      }); +      return accumulator; +    } + +    /** +     * The opposite of `_.filter`, this method returns the elements of a +     * `collection` that `callback` does **not** return truthy for. +     * +     * If a property name is passed for `callback`, the created "_.pluck" style +     * callback will return the property value of the given element. +     * +     * If an object is passed for `callback`, the created "_.where" style callback +     * will return `true` for elements that have the propeties of the given object, +     * else `false`. +     * +     * @static +     * @memberOf _ +     * @category Collections +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {Function|Object|String} [callback=identity] The function called per +     *  iteration. If a property name or object is passed, it will be used to create +     *  a "_.pluck" or "_.where" style callback, respectively. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Array} Returns a new array of elements that did **not** pass the +     *  callback check. +     * @example +     * +     * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); +     * // => [1, 3, 5] +     * +     * var food = [ +     *   { 'name': 'apple',  'organic': false, 'type': 'fruit' }, +     *   { 'name': 'carrot', 'organic': true,  'type': 'vegetable' } +     * ]; +     * +     * // using "_.pluck" callback shorthand +     * _.reject(food, 'organic'); +     * // => [{ 'name': 'apple', 'organic': false, 'type': 'fruit' }] +     * +     * // using "_.where" callback shorthand +     * _.reject(food, { 'type': 'fruit' }); +     * // => [{ 'name': 'carrot', 'organic': true, 'type': 'vegetable' }] +     */ +    function reject(collection, callback, thisArg) { +      callback = createCallback(callback, thisArg); +      return filter(collection, function(value, index, collection) { +        return !callback(value, index, collection); +      }); +    } + +    /** +     * Creates an array of shuffled `array` values, using a version of the +     * Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle. +     * +     * @static +     * @memberOf _ +     * @category Collections +     * @param {Array|Object|String} collection The collection to shuffle. +     * @returns {Array} Returns a new shuffled collection. +     * @example +     * +     * _.shuffle([1, 2, 3, 4, 5, 6]); +     * // => [4, 1, 6, 3, 5, 2] +     */ +    function shuffle(collection) { +      var index = -1, +          length = collection ? collection.length : 0, +          result = Array(typeof length == 'number' ? length : 0); + +      forEach(collection, function(value) { +        var rand = floor(nativeRandom() * (++index + 1)); +        result[index] = result[rand]; +        result[rand] = value; +      }); +      return result; +    } + +    /** +     * Gets the size of the `collection` by returning `collection.length` for arrays +     * and array-like objects or the number of own enumerable properties for objects. +     * +     * @static +     * @memberOf _ +     * @category Collections +     * @param {Array|Object|String} collection The collection to inspect. +     * @returns {Number} Returns `collection.length` or number of own enumerable properties. +     * @example +     * +     * _.size([1, 2]); +     * // => 2 +     * +     * _.size({ 'one': 1, 'two': 2, 'three': 3 }); +     * // => 3 +     * +     * _.size('curly'); +     * // => 5 +     */ +    function size(collection) { +      var length = collection ? collection.length : 0; +      return typeof length == 'number' ? length : keys(collection).length; +    } + +    /** +     * Checks if the `callback` returns a truthy value for **any** element of a +     * `collection`. The function returns as soon as it finds passing value, and +     * does not iterate over the entire `collection`. The `callback` is bound to +     * `thisArg` and invoked with three arguments; (value, index|key, collection). +     * +     * If a property name is passed for `callback`, the created "_.pluck" style +     * callback will return the property value of the given element. +     * +     * If an object is passed for `callback`, the created "_.where" style callback +     * will return `true` for elements that have the propeties of the given object, +     * else `false`. +     * +     * @static +     * @memberOf _ +     * @alias any +     * @category Collections +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {Function|Object|String} [callback=identity] The function called per +     *  iteration. If a property name or object is passed, it will be used to create +     *  a "_.pluck" or "_.where" style callback, respectively. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Boolean} Returns `true` if any element passes the callback check, +     *  else `false`. +     * @example +     * +     * _.some([null, 0, 'yes', false], Boolean); +     * // => true +     * +     * var food = [ +     *   { 'name': 'apple',  'organic': false, 'type': 'fruit' }, +     *   { 'name': 'carrot', 'organic': true,  'type': 'vegetable' } +     * ]; +     * +     * // using "_.pluck" callback shorthand +     * _.some(food, 'organic'); +     * // => true +     * +     * // using "_.where" callback shorthand +     * _.some(food, { 'type': 'meat' }); +     * // => false +     */ +    function some(collection, callback, thisArg) { +      var result; +      callback = createCallback(callback, thisArg); + +      if (isArray(collection)) { +        var index = -1, +            length = collection.length; + +        while (++index < length) { +          if ((result = callback(collection[index], index, collection))) { +            break; +          } +        } +      } else { +        each(collection, function(value, index, collection) { +          return !(result = callback(value, index, collection)); +        }); +      } +      return !!result; +    } + +    /** +     * Creates an array of elements, sorted in ascending order by the results of +     * running each element in the `collection` through the `callback`. This method +     * performs a stable sort, that is, it will preserve the original sort order of +     * equal elements. The `callback` is bound to `thisArg` and invoked with three +     * arguments; (value, index|key, collection). +     * +     * If a property name is passed for `callback`, the created "_.pluck" style +     * callback will return the property value of the given element. +     * +     * If an object is passed for `callback`, the created "_.where" style callback +     * will return `true` for elements that have the propeties of the given object, +     * else `false`. +     * +     * @static +     * @memberOf _ +     * @category Collections +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {Function|Object|String} [callback=identity] The function called per +     *  iteration. If a property name or object is passed, it will be used to create +     *  a "_.pluck" or "_.where" style callback, respectively. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Array} Returns a new array of sorted elements. +     * @example +     * +     * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); }); +     * // => [3, 1, 2] +     * +     * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math); +     * // => [3, 1, 2] +     * +     * // using "_.pluck" callback shorthand +     * _.sortBy(['banana', 'strawberry', 'apple'], 'length'); +     * // => ['apple', 'banana', 'strawberry'] +     */ +    function sortBy(collection, callback, thisArg) { +      var index = -1, +          length = collection ? collection.length : 0, +          result = Array(typeof length == 'number' ? length : 0); + +      callback = createCallback(callback, thisArg); +      forEach(collection, function(value, key, collection) { +        result[++index] = { +          'criteria': callback(value, key, collection), +          'index': index, +          'value': value +        }; +      }); + +      length = result.length; +      result.sort(compareAscending); +      while (length--) { +        result[length] = result[length].value; +      } +      return result; +    } + +    /** +     * Converts the `collection` to an array. +     * +     * @static +     * @memberOf _ +     * @category Collections +     * @param {Array|Object|String} collection The collection to convert. +     * @returns {Array} Returns the new converted array. +     * @example +     * +     * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4); +     * // => [2, 3, 4] +     */ +    function toArray(collection) { +      if (collection && typeof collection.length == 'number') { +        return  slice(collection); +      } +      return values(collection); +    } + +    /** +     * Examines each element in a `collection`, returning an array of all elements +     * that have the given `properties`. When checking `properties`, this method +     * performs a deep comparison between values to determine if they are equivalent +     * to each other. +     * +     * @static +     * @memberOf _ +     * @type Function +     * @category Collections +     * @param {Array|Object|String} collection The collection to iterate over. +     * @param {Object} properties The object of property values to filter by. +     * @returns {Array} Returns a new array of elements that have the given `properties`. +     * @example +     * +     * var stooges = [ +     *   { 'name': 'moe', 'age': 40 }, +     *   { 'name': 'larry', 'age': 50 } +     * ]; +     * +     * _.where(stooges, { 'age': 40 }); +     * // => [{ 'name': 'moe', 'age': 40 }] +     */ +    var where = filter; + +    /*--------------------------------------------------------------------------*/ + +    /** +     * Creates an array with all falsey values of `array` removed. The values +     * `false`, `null`, `0`, `""`, `undefined` and `NaN` are all falsey. +     * +     * @static +     * @memberOf _ +     * @category Arrays +     * @param {Array} array The array to compact. +     * @returns {Array} Returns a new filtered array. +     * @example +     * +     * _.compact([0, 1, false, 2, '', 3]); +     * // => [1, 2, 3] +     */ +    function compact(array) { +      var index = -1, +          length = array ? array.length : 0, +          result = []; + +      while (++index < length) { +        var value = array[index]; +        if (value) { +          result.push(value); +        } +      } +      return result; +    } + +    /** +     * Creates an array of `array` elements not present in the other arrays +     * using strict equality for comparisons, i.e. `===`. +     * +     * @static +     * @memberOf _ +     * @category Arrays +     * @param {Array} array The array to process. +     * @param {Array} [array1, array2, ...] Arrays to check. +     * @returns {Array} Returns a new array of `array` elements not present in the +     *  other arrays. +     * @example +     * +     * _.difference([1, 2, 3, 4, 5], [5, 2, 10]); +     * // => [1, 3, 4] +     */ +    function difference(array) { +      var index = -1, +          length = array ? array.length : 0, +          flattened = concat.apply(arrayRef, arguments), +          contains = cachedContains(flattened, length), +          result = []; + +      while (++index < length) { +        var value = array[index]; +        if (!contains(value)) { +          result.push(value); +        } +      } +      return result; +    } + +    /** +     * Gets the first element of the `array`. If a number `n` is passed, the first +     * `n` elements of the `array` are returned. If a `callback` function is passed, +     * elements at the beginning of the array are returned as long as the `callback` +     * returns truthy. The `callback` is bound to `thisArg` and invoked with three +     * arguments; (value, index, array). +     * +     * If a property name is passed for `callback`, the created "_.pluck" style +     * callback will return the property value of the given element. +     * +     * If an object is passed for `callback`, the created "_.where" style callback +     * will return `true` for elements that have the propeties of the given object, +     * else `false`. +     * +     * @static +     * @memberOf _ +     * @alias head, take +     * @category Arrays +     * @param {Array} array The array to query. +     * @param {Function|Object|Number|String} [callback|n] The function called +     *  per element or the number of elements to return. If a property name or +     *  object is passed, it will be used to create a "_.pluck" or "_.where" +     *  style callback, respectively. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Mixed} Returns the first element(s) of `array`. +     * @example +     * +     * _.first([1, 2, 3]); +     * // => 1 +     * +     * _.first([1, 2, 3], 2); +     * // => [1, 2] +     * +     * _.first([1, 2, 3], function(num) { +     *   return num < 3; +     * }); +     * // => [1, 2] +     * +     * var food = [ +     *   { 'name': 'banana', 'organic': true }, +     *   { 'name': 'beet',   'organic': false }, +     * ]; +     * +     * // using "_.pluck" callback shorthand +     * _.first(food, 'organic'); +     * // => [{ 'name': 'banana', 'organic': true }] +     * +     * var food = [ +     *   { 'name': 'apple',  'type': 'fruit' }, +     *   { 'name': 'banana', 'type': 'fruit' }, +     *   { 'name': 'beet',   'type': 'vegetable' } +     * ]; +     * +     * // using "_.where" callback shorthand +     * _.first(food, { 'type': 'fruit' }); +     * // => [{ 'name': 'apple', 'type': 'fruit' }, { 'name': 'banana', 'type': 'fruit' }] +     */ +    function first(array, callback, thisArg) { +      if (array) { +        var n = 0, +            length = array.length; + +        if (typeof callback != 'number' && callback != null) { +          var index = -1; +          callback = createCallback(callback, thisArg); +          while (++index < length && callback(array[index], index, array)) { +            n++; +          } +        } else { +          n = callback; +          if (n == null || thisArg) { +            return array[0]; +          } +        } +        return slice(array, 0, nativeMin(nativeMax(0, n), length)); +      } +    } + +    /** +     * Flattens a nested array (the nesting can be to any depth). If `shallow` is +     * truthy, `array` will only be flattened a single level. +     * +     * @static +     * @memberOf _ +     * @category Arrays +     * @param {Array} array The array to compact. +     * @param {Boolean} shallow A flag to indicate only flattening a single level. +     * @returns {Array} Returns a new flattened array. +     * @example +     * +     * _.flatten([1, [2], [3, [[4]]]]); +     * // => [1, 2, 3, 4]; +     * +     * _.flatten([1, [2], [3, [[4]]]], true); +     * // => [1, 2, 3, [[4]]]; +     */ +    function flatten(array, shallow) { +      var index = -1, +          length = array ? array.length : 0, +          result = []; + +      while (++index < length) { +        var value = array[index]; + +        // recursively flatten arrays (susceptible to call stack limits) +        if (isArray(value)) { +          push.apply(result, shallow ? value : flatten(value)); +        } else { +          result.push(value); +        } +      } +      return result; +    } + +    /** +     * Gets the index at which the first occurrence of `value` is found using +     * strict equality for comparisons, i.e. `===`. If the `array` is already +     * sorted, passing `true` for `fromIndex` will run a faster binary search. +     * +     * @static +     * @memberOf _ +     * @category Arrays +     * @param {Array} array The array to search. +     * @param {Mixed} value The value to search for. +     * @param {Boolean|Number} [fromIndex=0] The index to search from or `true` to +     *  perform a binary search on a sorted `array`. +     * @returns {Number} Returns the index of the matched value or `-1`. +     * @example +     * +     * _.indexOf([1, 2, 3, 1, 2, 3], 2); +     * // => 1 +     * +     * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3); +     * // => 4 +     * +     * _.indexOf([1, 1, 2, 2, 3, 3], 2, true); +     * // => 2 +     */ +    function indexOf(array, value, fromIndex) { +      var index = -1, +          length = array ? array.length : 0; + +      if (typeof fromIndex == 'number') { +        index = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0) - 1; +      } else if (fromIndex) { +        index = sortedIndex(array, value); +        return array[index] === value ? index : -1; +      } +      while (++index < length) { +        if (array[index] === value) { +          return index; +        } +      } +      return -1; +    } + +    /** +     * Gets all but the last element of `array`. If a number `n` is passed, the +     * last `n` elements are excluded from the result. If a `callback` function +     * is passed, elements at the end of the array are excluded from the result +     * as long as the `callback` returns truthy. The `callback` is bound to +     * `thisArg` and invoked with three arguments; (value, index, array). +     * +     * If a property name is passed for `callback`, the created "_.pluck" style +     * callback will return the property value of the given element. +     * +     * If an object is passed for `callback`, the created "_.where" style callback +     * will return `true` for elements that have the propeties of the given object, +     * else `false`. +     * +     * @static +     * @memberOf _ +     * @category Arrays +     * @param {Array} array The array to query. +     * @param {Function|Object|Number|String} [callback|n=1] The function called +     *  per element or the number of elements to exclude. If a property name or +     *  object is passed, it will be used to create a "_.pluck" or "_.where" +     *  style callback, respectively. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Array} Returns a slice of `array`. +     * @example +     * +     * _.initial([1, 2, 3]); +     * // => [1, 2] +     * +     * _.initial([1, 2, 3], 2); +     * // => [1] +     * +     * _.initial([1, 2, 3], function(num) { +     *   return num > 1; +     * }); +     * // => [1] +     * +     * var food = [ +     *   { 'name': 'beet',   'organic': false }, +     *   { 'name': 'carrot', 'organic': true } +     * ]; +     * +     * // using "_.pluck" callback shorthand +     * _.initial(food, 'organic'); +     * // => [{ 'name': 'beet',   'organic': false }] +     * +     * var food = [ +     *   { 'name': 'banana', 'type': 'fruit' }, +     *   { 'name': 'beet',   'type': 'vegetable' }, +     *   { 'name': 'carrot', 'type': 'vegetable' } +     * ]; +     * +     * // using "_.where" callback shorthand +     * _.initial(food, { 'type': 'vegetable' }); +     * // => [{ 'name': 'banana', 'type': 'fruit' }] +     */ +    function initial(array, callback, thisArg) { +      if (!array) { +        return []; +      } +      var n = 0, +          length = array.length; + +      if (typeof callback != 'number' && callback != null) { +        var index = length; +        callback = createCallback(callback, thisArg); +        while (index-- && callback(array[index], index, array)) { +          n++; +        } +      } else { +        n = (callback == null || thisArg) ? 1 : callback || n; +      } +      return slice(array, 0, nativeMin(nativeMax(0, length - n), length)); +    } + +    /** +     * Computes the intersection of all the passed-in arrays using strict equality +     * for comparisons, i.e. `===`. +     * +     * @static +     * @memberOf _ +     * @category Arrays +     * @param {Array} [array1, array2, ...] Arrays to process. +     * @returns {Array} Returns a new array of unique elements that are present +     *  in **all** of the arrays. +     * @example +     * +     * _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]); +     * // => [1, 2] +     */ +    function intersection(array) { +      var args = arguments, +          argsLength = args.length, +          cache = { '0': {} }, +          index = -1, +          length = array ? array.length : 0, +          isLarge = length >= 100, +          result = [], +          seen = result; + +      outer: +      while (++index < length) { +        var value = array[index]; +        if (isLarge) { +          var key = value + ''; +          var inited = hasOwnProperty.call(cache[0], key) +            ? !(seen = cache[0][key]) +            : (seen = cache[0][key] = []); +        } +        if (inited || indexOf(seen, value) < 0) { +          if (isLarge) { +            seen.push(value); +          } +          var argsIndex = argsLength; +          while (--argsIndex) { +            if (!(cache[argsIndex] || (cache[argsIndex] = cachedContains(args[argsIndex], 0, 100)))(value)) { +              continue outer; +            } +          } +          result.push(value); +        } +      } +      return result; +    } + +    /** +     * Gets the last element of the `array`. If a number `n` is passed, the +     * last `n` elements of the `array` are returned. If a `callback` function +     * is passed, elements at the end of the array are returned as long as the +     * `callback` returns truthy. The `callback` is bound to `thisArg` and +     * invoked with three arguments;(value, index, array). +     * +     * +     * If a property name is passed for `callback`, the created "_.pluck" style +     * callback will return the property value of the given element. +     * +     * If an object is passed for `callback`, the created "_.where" style callback +     * will return `true` for elements that have the propeties of the given object, +     * else `false`. +     * +     * @static +     * @memberOf _ +     * @category Arrays +     * @param {Array} array The array to query. +     * @param {Function|Object|Number|String} [callback|n] The function called +     *  per element or the number of elements to return. If a property name or +     *  object is passed, it will be used to create a "_.pluck" or "_.where" +     *  style callback, respectively. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Mixed} Returns the last element(s) of `array`. +     * @example +     * +     * _.last([1, 2, 3]); +     * // => 3 +     * +     * _.last([1, 2, 3], 2); +     * // => [2, 3] +     * +     * _.last([1, 2, 3], function(num) { +     *   return num > 1; +     * }); +     * // => [2, 3] +     * +     * var food = [ +     *   { 'name': 'beet',   'organic': false }, +     *   { 'name': 'carrot', 'organic': true } +     * ]; +     * +     * // using "_.pluck" callback shorthand +     * _.last(food, 'organic'); +     * // => [{ 'name': 'carrot', 'organic': true }] +     * +     * var food = [ +     *   { 'name': 'banana', 'type': 'fruit' }, +     *   { 'name': 'beet',   'type': 'vegetable' }, +     *   { 'name': 'carrot', 'type': 'vegetable' } +     * ]; +     * +     * // using "_.where" callback shorthand +     * _.last(food, { 'type': 'vegetable' }); +     * // => [{ 'name': 'beet', 'type': 'vegetable' }, { 'name': 'carrot', 'type': 'vegetable' }] +     */ +    function last(array, callback, thisArg) { +      if (array) { +        var n = 0, +            length = array.length; + +        if (typeof callback != 'number' && callback != null) { +          var index = length; +          callback = createCallback(callback, thisArg); +          while (index-- && callback(array[index], index, array)) { +            n++; +          } +        } else { +          n = callback; +          if (n == null || thisArg) { +            return array[length - 1]; +          } +        } +        return slice(array, nativeMax(0, length - n)); +      } +    } + +    /** +     * Gets the index at which the last occurrence of `value` is found using strict +     * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used +     * as the offset from the end of the collection. +     * +     * @static +     * @memberOf _ +     * @category Arrays +     * @param {Array} array The array to search. +     * @param {Mixed} value The value to search for. +     * @param {Number} [fromIndex=array.length-1] The index to search from. +     * @returns {Number} Returns the index of the matched value or `-1`. +     * @example +     * +     * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2); +     * // => 4 +     * +     * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3); +     * // => 1 +     */ +    function lastIndexOf(array, value, fromIndex) { +      var index = array ? array.length : 0; +      if (typeof fromIndex == 'number') { +        index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1; +      } +      while (index--) { +        if (array[index] === value) { +          return index; +        } +      } +      return -1; +    } + +    /** +     * Creates an object composed from arrays of `keys` and `values`. Pass either +     * a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`, or +     * two arrays, one of `keys` and one of corresponding `values`. +     * +     * @static +     * @memberOf _ +     * @category Arrays +     * @param {Array} keys The array of keys. +     * @param {Array} [values=[]] The array of values. +     * @returns {Object} Returns an object composed of the given keys and +     *  corresponding values. +     * @example +     * +     * _.object(['moe', 'larry'], [30, 40]); +     * // => { 'moe': 30, 'larry': 40 } +     */ +    function object(keys, values) { +      var index = -1, +          length = keys ? keys.length : 0, +          result = {}; + +      while (++index < length) { +        var key = keys[index]; +        if (values) { +          result[key] = values[index]; +        } else { +          result[key[0]] = key[1]; +        } +      } +      return result; +    } + +    /** +     * Creates an array of numbers (positive and/or negative) progressing from +     * `start` up to but not including `end`. +     * +     * @static +     * @memberOf _ +     * @category Arrays +     * @param {Number} [start=0] The start of the range. +     * @param {Number} end The end of the range. +     * @param {Number} [step=1] The value to increment or descrement by. +     * @returns {Array} Returns a new range array. +     * @example +     * +     * _.range(10); +     * // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +     * +     * _.range(1, 11); +     * // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +     * +     * _.range(0, 30, 5); +     * // => [0, 5, 10, 15, 20, 25] +     * +     * _.range(0, -10, -1); +     * // => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] +     * +     * _.range(0); +     * // => [] +     */ +    function range(start, end, step) { +      start = +start || 0; +      step = +step || 1; + +      if (end == null) { +        end = start; +        start = 0; +      } +      // use `Array(length)` so V8 will avoid the slower "dictionary" mode +      // http://youtu.be/XAqIpGU8ZZk#t=17m25s +      var index = -1, +          length = nativeMax(0, ceil((end - start) / step)), +          result = Array(length); + +      while (++index < length) { +        result[index] = start; +        start += step; +      } +      return result; +    } + +    /** +     * The opposite of `_.initial`, this method gets all but the first value of +     * `array`. If a number `n` is passed, the first `n` values are excluded from +     * the result. If a `callback` function is passed, elements at the beginning +     * of the array are excluded from the result as long as the `callback` returns +     * truthy. The `callback` is bound to `thisArg` and invoked with three +     * arguments; (value, index, array). +     * +     * If a property name is passed for `callback`, the created "_.pluck" style +     * callback will return the property value of the given element. +     * +     * If an object is passed for `callback`, the created "_.where" style callback +     * will return `true` for elements that have the propeties of the given object, +     * else `false`. +     * +     * @static +     * @memberOf _ +     * @alias drop, tail +     * @category Arrays +     * @param {Array} array The array to query. +     * @param {Function|Object|Number|String} [callback|n=1] The function called +     *  per element or the number of elements to exclude. If a property name or +     *  object is passed, it will be used to create a "_.pluck" or "_.where" +     *  style callback, respectively. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Array} Returns a slice of `array`. +     * @example +     * +     * _.rest([1, 2, 3]); +     * // => [2, 3] +     * +     * _.rest([1, 2, 3], 2); +     * // => [3] +     * +     * _.rest([1, 2, 3], function(num) { +     *   return num < 3; +     * }); +     * // => [3] +     * +     * var food = [ +     *   { 'name': 'banana', 'organic': true }, +     *   { 'name': 'beet',   'organic': false }, +     * ]; +     * +     * // using "_.pluck" callback shorthand +     * _.rest(food, 'organic'); +     * // => [{ 'name': 'beet', 'organic': false }] +     * +     * var food = [ +     *   { 'name': 'apple',  'type': 'fruit' }, +     *   { 'name': 'banana', 'type': 'fruit' }, +     *   { 'name': 'beet',   'type': 'vegetable' } +     * ]; +     * +     * // using "_.where" callback shorthand +     * _.rest(food, { 'type': 'fruit' }); +     * // => [{ 'name': 'beet', 'type': 'vegetable' }] +     */ +    function rest(array, callback, thisArg) { +      if (typeof callback != 'number' && callback != null) { +        var n = 0, +            index = -1, +            length = array ? array.length : 0; + +        callback = createCallback(callback, thisArg); +        while (++index < length && callback(array[index], index, array)) { +          n++; +        } +      } else { +        n = (callback == null || thisArg) ? 1 : nativeMax(0, callback); +      } +      return slice(array, n); +    } + +    /** +     * Uses a binary search to determine the smallest index at which the `value` +     * should be inserted into `array` in order to maintain the sort order of the +     * sorted `array`. If `callback` is passed, it will be executed for `value` and +     * each element in `array` to compute their sort ranking. The `callback` is +     * bound to `thisArg` and invoked with one argument; (value). +     * +     * If a property name is passed for `callback`, the created "_.pluck" style +     * callback will return the property value of the given element. +     * +     * If an object is passed for `callback`, the created "_.where" style callback +     * will return `true` for elements that have the propeties of the given object, +     * else `false`. +     * +     * @static +     * @memberOf _ +     * @category Arrays +     * @param {Array} array The array to iterate over. +     * @param {Mixed} value The value to evaluate. +     * @param {Function|Object|String} [callback=identity] The function called per +     *  iteration. If a property name or object is passed, it will be used to create +     *  a "_.pluck" or "_.where" style callback, respectively. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Number} Returns the index at which the value should be inserted +     *  into `array`. +     * @example +     * +     * _.sortedIndex([20, 30, 50], 40); +     * // => 2 +     * +     * // using "_.pluck" callback shorthand +     * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x'); +     * // => 2 +     * +     * var dict = { +     *   'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 } +     * }; +     * +     * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) { +     *   return dict.wordToNumber[word]; +     * }); +     * // => 2 +     * +     * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) { +     *   return this.wordToNumber[word]; +     * }, dict); +     * // => 2 +     */ +    function sortedIndex(array, value, callback, thisArg) { +      var low = 0, +          high = array ? array.length : low; + +      // explicitly reference `identity` for better inlining in Firefox +      callback = callback ? createCallback(callback, thisArg, 1) : identity; +      value = callback(value); + +      while (low < high) { +        var mid = (low + high) >>> 1; +        callback(array[mid]) < value +          ? low = mid + 1 +          : high = mid; +      } +      return low; +    } + +    /** +     * Computes the union of the passed-in arrays using strict equality for +     * comparisons, i.e. `===`. +     * +     * @static +     * @memberOf _ +     * @category Arrays +     * @param {Array} [array1, array2, ...] Arrays to process. +     * @returns {Array} Returns a new array of unique values, in order, that are +     *  present in one or more of the arrays. +     * @example +     * +     * _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]); +     * // => [1, 2, 3, 101, 10] +     */ +    function union() { +      return uniq(concat.apply(arrayRef, arguments)); +    } + +    /** +     * Creates a duplicate-value-free version of the `array` using strict equality +     * for comparisons, i.e. `===`. If the `array` is already sorted, passing `true` +     * for `isSorted` will run a faster algorithm. If `callback` is passed, each +     * element of `array` is passed through a callback` before uniqueness is computed. +     * The `callback` is bound to `thisArg` and invoked with three arguments; (value, index, array). +     * +     * If a property name is passed for `callback`, the created "_.pluck" style +     * callback will return the property value of the given element. +     * +     * If an object is passed for `callback`, the created "_.where" style callback +     * will return `true` for elements that have the propeties of the given object, +     * else `false`. +     * +     * @static +     * @memberOf _ +     * @alias unique +     * @category Arrays +     * @param {Array} array The array to process. +     * @param {Boolean} [isSorted=false] A flag to indicate that the `array` is already sorted. +     * @param {Function|Object|String} [callback=identity] The function called per +     *  iteration. If a property name or object is passed, it will be used to create +     *  a "_.pluck" or "_.where" style callback, respectively. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Array} Returns a duplicate-value-free array. +     * @example +     * +     * _.uniq([1, 2, 1, 3, 1]); +     * // => [1, 2, 3] +     * +     * _.uniq([1, 1, 2, 2, 3], true); +     * // => [1, 2, 3] +     * +     * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return Math.floor(num); }); +     * // => [1, 2, 3] +     * +     * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return this.floor(num); }, Math); +     * // => [1, 2, 3] +     * +     * // using "_.pluck" callback shorthand +     * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); +     * // => [{ 'x': 1 }, { 'x': 2 }] +     */ +    function uniq(array, isSorted, callback, thisArg) { +      var index = -1, +          length = array ? array.length : 0, +          result = [], +          seen = result; + +      // juggle arguments +      if (typeof isSorted == 'function') { +        thisArg = callback; +        callback = isSorted; +        isSorted = false; +      } +      // init value cache for large arrays +      var isLarge = !isSorted && length >= 75; +      if (isLarge) { +        var cache = {}; +      } +      if (callback) { +        seen = []; +        callback = createCallback(callback, thisArg); +      } +      while (++index < length) { +        var value = array[index], +            computed = callback ? callback(value, index, array) : value; + +        if (isLarge) { +          var key = computed + ''; +          var inited = hasOwnProperty.call(cache, key) +            ? !(seen = cache[key]) +            : (seen = cache[key] = []); +        } +        if (isSorted +              ? !index || seen[seen.length - 1] !== computed +              : inited || indexOf(seen, computed) < 0 +            ) { +          if (callback || isLarge) { +            seen.push(computed); +          } +          result.push(value); +        } +      } +      return result; +    } + +    /** +     * Creates an array with all occurrences of the passed values removed using +     * strict equality for comparisons, i.e. `===`. +     * +     * @static +     * @memberOf _ +     * @category Arrays +     * @param {Array} array The array to filter. +     * @param {Mixed} [value1, value2, ...] Values to remove. +     * @returns {Array} Returns a new filtered array. +     * @example +     * +     * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1); +     * // => [2, 3, 4] +     */ +    function without(array) { +      var index = -1, +          length = array ? array.length : 0, +          contains = cachedContains(arguments, 1), +          result = []; + +      while (++index < length) { +        var value = array[index]; +        if (!contains(value)) { +          result.push(value); +        } +      } +      return result; +    } + +    /** +     * Groups the elements of each array at their corresponding indexes. Useful for +     * separate data sources that are coordinated through matching array indexes. +     * For a matrix of nested arrays, `_.zip.apply(...)` can transpose the matrix +     * in a similar fashion. +     * +     * @static +     * @memberOf _ +     * @category Arrays +     * @param {Array} [array1, array2, ...] Arrays to process. +     * @returns {Array} Returns a new array of grouped elements. +     * @example +     * +     * _.zip(['moe', 'larry'], [30, 40], [true, false]); +     * // => [['moe', 30, true], ['larry', 40, false]] +     */ +    function zip(array) { +      var index = -1, +          length = array ? max(pluck(arguments, 'length')) : 0, +          result = Array(length); + +      while (++index < length) { +        result[index] = pluck(arguments, index); +      } +      return result; +    } + +    /*--------------------------------------------------------------------------*/ + +    /** +     * Creates a function that is restricted to executing `func` only after it is +     * called `n` times. The `func` is executed with the `this` binding of the +     * created function. +     * +     * @static +     * @memberOf _ +     * @category Functions +     * @param {Number} n The number of times the function must be called before +     * it is executed. +     * @param {Function} func The function to restrict. +     * @returns {Function} Returns the new restricted function. +     * @example +     * +     * var renderNotes = _.after(notes.length, render); +     * _.forEach(notes, function(note) { +     *   note.asyncSave({ 'success': renderNotes }); +     * }); +     * // `renderNotes` is run once, after all notes have saved +     */ +    function after(n, func) { +      if (n < 1) { +        return func(); +      } +      return function() { +        if (--n < 1) { +          return func.apply(this, arguments); +        } +      }; +    } + +    /** +     * Creates a function that, when called, invokes `func` with the `this` +     * binding of `thisArg` and prepends any additional `bind` arguments to those +     * passed to the bound function. +     * +     * @static +     * @memberOf _ +     * @category Functions +     * @param {Function} func The function to bind. +     * @param {Mixed} [thisArg] The `this` binding of `func`. +     * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied. +     * @returns {Function} Returns the new bound function. +     * @example +     * +     * var func = function(greeting) { +     *   return greeting + ' ' + this.name; +     * }; +     * +     * func = _.bind(func, { 'name': 'moe' }, 'hi'); +     * func(); +     * // => 'hi moe' +     */ +    function bind(func, thisArg) { +      // use `Function#bind` if it exists and is fast +      // (in V8 `Function#bind` is slower except when partially applied) +      return isBindFast || (nativeBind && arguments.length > 2) +        ? nativeBind.call.apply(nativeBind, arguments) +        : createBound(func, thisArg, slice(arguments, 2)); +    } + +    /** +     * Binds methods on `object` to `object`, overwriting the existing method. +     * Method names may be specified as individual arguments or as arrays of method +     * names. If no method names are provided, all the function properties of `object` +     * will be bound. +     * +     * @static +     * @memberOf _ +     * @category Functions +     * @param {Object} object The object to bind and assign the bound methods to. +     * @param {String} [methodName1, methodName2, ...] Method names on the object to bind. +     * @returns {Object} Returns `object`. +     * @example +     * +     * var view = { +     *  'label': 'docs', +     *  'onClick': function() { alert('clicked ' + this.label); } +     * }; +     * +     * _.bindAll(view); +     * jQuery('#docs').on('click', view.onClick); +     * // => alerts 'clicked docs', when the button is clicked +     */ +    function bindAll(object) { +      var funcs = concat.apply(arrayRef, arguments), +          index = funcs.length > 1 ? 0 : (funcs = functions(object), -1), +          length = funcs.length; + +      while (++index < length) { +        var key = funcs[index]; +        object[key] = bind(object[key], object); +      } +      return object; +    } + +    /** +     * Creates a function that, when called, invokes the method at `object[key]` +     * and prepends any additional `bindKey` arguments to those passed to the bound +     * function. This method differs from `_.bind` by allowing bound functions to +     * reference methods that will be redefined or don't yet exist. +     * See http://michaux.ca/articles/lazy-function-definition-pattern. +     * +     * @static +     * @memberOf _ +     * @category Functions +     * @param {Object} object The object the method belongs to. +     * @param {String} key The key of the method. +     * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied. +     * @returns {Function} Returns the new bound function. +     * @example +     * +     * var object = { +     *   'name': 'moe', +     *   'greet': function(greeting) { +     *     return greeting + ' ' + this.name; +     *   } +     * }; +     * +     * var func = _.bindKey(object, 'greet', 'hi'); +     * func(); +     * // => 'hi moe' +     * +     * object.greet = function(greeting) { +     *   return greeting + ', ' + this.name + '!'; +     * }; +     * +     * func(); +     * // => 'hi, moe!' +     */ +    function bindKey(object, key) { +      return createBound(object, key, slice(arguments, 2)); +    } + +    /** +     * Creates a function that is the composition of the passed functions, +     * where each function consumes the return value of the function that follows. +     * For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`. +     * Each function is executed with the `this` binding of the composed function. +     * +     * @static +     * @memberOf _ +     * @category Functions +     * @param {Function} [func1, func2, ...] Functions to compose. +     * @returns {Function} Returns the new composed function. +     * @example +     * +     * var greet = function(name) { return 'hi ' + name; }; +     * var exclaim = function(statement) { return statement + '!'; }; +     * var welcome = _.compose(exclaim, greet); +     * welcome('moe'); +     * // => 'hi moe!' +     */ +    function compose() { +      var funcs = arguments; +      return function() { +        var args = arguments, +            length = funcs.length; + +        while (length--) { +          args = [funcs[length].apply(this, args)]; +        } +        return args[0]; +      }; +    } + +    /** +     * Creates a function that will delay the execution of `func` until after +     * `wait` milliseconds have elapsed since the last time it was invoked. Pass +     * `true` for `immediate` to cause debounce to invoke `func` on the leading, +     * instead of the trailing, edge of the `wait` timeout. Subsequent calls to +     * the debounced function will return the result of the last `func` call. +     * +     * @static +     * @memberOf _ +     * @category Functions +     * @param {Function} func The function to debounce. +     * @param {Number} wait The number of milliseconds to delay. +     * @param {Boolean} immediate A flag to indicate execution is on the leading +     *  edge of the timeout. +     * @returns {Function} Returns the new debounced function. +     * @example +     * +     * var lazyLayout = _.debounce(calculateLayout, 300); +     * jQuery(window).on('resize', lazyLayout); +     */ +    function debounce(func, wait, immediate) { +      var args, +          result, +          thisArg, +          timeoutId; + +      function delayed() { +        timeoutId = null; +        if (!immediate) { +          result = func.apply(thisArg, args); +        } +      } +      return function() { +        var isImmediate = immediate && !timeoutId; +        args = arguments; +        thisArg = this; + +        clearTimeout(timeoutId); +        timeoutId = setTimeout(delayed, wait); + +        if (isImmediate) { +          result = func.apply(thisArg, args); +        } +        return result; +      }; +    } + +    /** +     * Executes the `func` function after `wait` milliseconds. Additional arguments +     * will be passed to `func` when it is invoked. +     * +     * @static +     * @memberOf _ +     * @category Functions +     * @param {Function} func The function to delay. +     * @param {Number} wait The number of milliseconds to delay execution. +     * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with. +     * @returns {Number} Returns the timer id. +     * @example +     * +     * var log = _.bind(console.log, console); +     * _.delay(log, 1000, 'logged later'); +     * // => 'logged later' (Appears after one second.) +     */ +    function delay(func, wait) { +      var args = slice(arguments, 2); +      return setTimeout(function() { func.apply(undefined, args); }, wait); +    } + +    /** +     * Defers executing the `func` function until the current call stack has cleared. +     * Additional arguments will be passed to `func` when it is invoked. +     * +     * @static +     * @memberOf _ +     * @category Functions +     * @param {Function} func The function to defer. +     * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with. +     * @returns {Number} Returns the timer id. +     * @example +     * +     * _.defer(function() { alert('deferred'); }); +     * // returns from the function before `alert` is called +     */ +    function defer(func) { +      var args = slice(arguments, 1); +      return setTimeout(function() { func.apply(undefined, args); }, 1); +    } +    // use `setImmediate` if it's available in Node.js +    if (isV8 && freeModule && typeof setImmediate == 'function') { +      defer = bind(setImmediate, context); +    } + +    /** +     * Creates a function that memoizes the result of `func`. If `resolver` is +     * passed, it will be used to determine the cache key for storing the result +     * based on the arguments passed to the memoized function. By default, the first +     * argument passed to the memoized function is used as the cache key. The `func` +     * is executed with the `this` binding of the memoized function. +     * +     * @static +     * @memberOf _ +     * @category Functions +     * @param {Function} func The function to have its output memoized. +     * @param {Function} [resolver] A function used to resolve the cache key. +     * @returns {Function} Returns the new memoizing function. +     * @example +     * +     * var fibonacci = _.memoize(function(n) { +     *   return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); +     * }); +     */ +    function memoize(func, resolver) { +      var cache = {}; +      return function() { +        var key = (resolver ? resolver.apply(this, arguments) : arguments[0]) + ''; +        return hasOwnProperty.call(cache, key) +          ? cache[key] +          : (cache[key] = func.apply(this, arguments)); +      }; +    } + +    /** +     * Creates a function that is restricted to execute `func` once. Repeat calls to +     * the function will return the value of the first call. The `func` is executed +     * with the `this` binding of the created function. +     * +     * @static +     * @memberOf _ +     * @category Functions +     * @param {Function} func The function to restrict. +     * @returns {Function} Returns the new restricted function. +     * @example +     * +     * var initialize = _.once(createApplication); +     * initialize(); +     * initialize(); +     * // `initialize` executes `createApplication` once +     */ +    function once(func) { +      var ran, +          result; + +      return function() { +        if (ran) { +          return result; +        } +        ran = true; +        result = func.apply(this, arguments); + +        // clear the `func` variable so the function may be garbage collected +        func = null; +        return result; +      }; +    } + +    /** +     * Creates a function that, when called, invokes `func` with any additional +     * `partial` arguments prepended to those passed to the new function. This +     * method is similar to `_.bind`, except it does **not** alter the `this` binding. +     * +     * @static +     * @memberOf _ +     * @category Functions +     * @param {Function} func The function to partially apply arguments to. +     * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied. +     * @returns {Function} Returns the new partially applied function. +     * @example +     * +     * var greet = function(greeting, name) { return greeting + ' ' + name; }; +     * var hi = _.partial(greet, 'hi'); +     * hi('moe'); +     * // => 'hi moe' +     */ +    function partial(func) { +      return createBound(func, slice(arguments, 1)); +    } + +    /** +     * This method is similar to `_.partial`, except that `partial` arguments are +     * appended to those passed to the new function. +     * +     * @static +     * @memberOf _ +     * @category Functions +     * @param {Function} func The function to partially apply arguments to. +     * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied. +     * @returns {Function} Returns the new partially applied function. +     * @example +     * +     * var defaultsDeep = _.partialRight(_.merge, _.defaults); +     * +     * var options = { +     *   'variable': 'data', +     *   'imports': { 'jq': $ } +     * }; +     * +     * defaultsDeep(options, _.templateSettings); +     * +     * options.variable +     * // => 'data' +     * +     * options.imports +     * // => { '_': _, 'jq': $ } +     */ +    function partialRight(func) { +      return createBound(func, slice(arguments, 1), null, indicatorObject); +    } + +    /** +     * Creates a function that, when executed, will only call the `func` +     * function at most once per every `wait` milliseconds. If the throttled +     * function is invoked more than once during the `wait` timeout, `func` will +     * also be called on the trailing edge of the timeout. Subsequent calls to the +     * throttled function will return the result of the last `func` call. +     * +     * @static +     * @memberOf _ +     * @category Functions +     * @param {Function} func The function to throttle. +     * @param {Number} wait The number of milliseconds to throttle executions to. +     * @returns {Function} Returns the new throttled function. +     * @example +     * +     * var throttled = _.throttle(updatePosition, 100); +     * jQuery(window).on('scroll', throttled); +     */ +    function throttle(func, wait) { +      var args, +          result, +          thisArg, +          timeoutId, +          lastCalled = 0; + +      function trailingCall() { +        lastCalled = new Date; +        timeoutId = null; +        result = func.apply(thisArg, args); +      } +      return function() { +        var now = new Date, +            remaining = wait - (now - lastCalled); + +        args = arguments; +        thisArg = this; + +        if (remaining <= 0) { +          clearTimeout(timeoutId); +          timeoutId = null; +          lastCalled = now; +          result = func.apply(thisArg, args); +        } +        else if (!timeoutId) { +          timeoutId = setTimeout(trailingCall, remaining); +        } +        return result; +      }; +    } + +    /** +     * Creates a function that passes `value` to the `wrapper` function as its +     * first argument. Additional arguments passed to the function are appended +     * to those passed to the `wrapper` function. The `wrapper` is executed with +     * the `this` binding of the created function. +     * +     * @static +     * @memberOf _ +     * @category Functions +     * @param {Mixed} value The value to wrap. +     * @param {Function} wrapper The wrapper function. +     * @returns {Function} Returns the new function. +     * @example +     * +     * var hello = function(name) { return 'hello ' + name; }; +     * hello = _.wrap(hello, function(func) { +     *   return 'before, ' + func('moe') + ', after'; +     * }); +     * hello(); +     * // => 'before, hello moe, after' +     */ +    function wrap(value, wrapper) { +      return function() { +        var args = [value]; +        push.apply(args, arguments); +        return wrapper.apply(this, args); +      }; +    } + +    /*--------------------------------------------------------------------------*/ + +    /** +     * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their +     * corresponding HTML entities. +     * +     * @static +     * @memberOf _ +     * @category Utilities +     * @param {String} string The string to escape. +     * @returns {String} Returns the escaped string. +     * @example +     * +     * _.escape('Moe, Larry & Curly'); +     * // => 'Moe, Larry & Curly' +     */ +    function escape(string) { +      return string == null ? '' : (string + '').replace(reUnescapedHtml, escapeHtmlChar); +    } + +    /** +     * This function returns the first argument passed to it. +     * +     * @static +     * @memberOf _ +     * @category Utilities +     * @param {Mixed} value Any value. +     * @returns {Mixed} Returns `value`. +     * @example +     * +     * var moe = { 'name': 'moe' }; +     * moe === _.identity(moe); +     * // => true +     */ +    function identity(value) { +      return value; +    } + +    /** +     * Adds functions properties of `object` to the `lodash` function and chainable +     * wrapper. +     * +     * @static +     * @memberOf _ +     * @category Utilities +     * @param {Object} object The object of function properties to add to `lodash`. +     * @example +     * +     * _.mixin({ +     *   'capitalize': function(string) { +     *     return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase(); +     *   } +     * }); +     * +     * _.capitalize('moe'); +     * // => 'Moe' +     * +     * _('moe').capitalize(); +     * // => 'Moe' +     */ +    function mixin(object) { +      forEach(functions(object), function(methodName) { +        var func = lodash[methodName] = object[methodName]; + +        lodash.prototype[methodName] = function() { +          var args = [this.__wrapped__]; +          push.apply(args, arguments); +          return new lodash(func.apply(lodash, args)); +        }; +      }); +    } + +    /** +     * Reverts the '_' variable to its previous value and returns a reference to +     * the `lodash` function. +     * +     * @static +     * @memberOf _ +     * @category Utilities +     * @returns {Function} Returns the `lodash` function. +     * @example +     * +     * var lodash = _.noConflict(); +     */ +    function noConflict() { +      context._ = oldDash; +      return this; +    } + +    /** +     * Produces a random number between `min` and `max` (inclusive). If only one +     * argument is passed, a number between `0` and the given number will be returned. +     * +     * @static +     * @memberOf _ +     * @category Utilities +     * @param {Number} [min=0] The minimum possible value. +     * @param {Number} [max=1] The maximum possible value. +     * @returns {Number} Returns a random number. +     * @example +     * +     * _.random(0, 5); +     * // => a number between 0 and 5 +     * +     * _.random(5); +     * // => also a number between 0 and 5 +     */ +    function random(min, max) { +      if (min == null && max == null) { +        max = 1; +      } +      min = +min || 0; +      if (max == null) { +        max = min; +        min = 0; +      } +      return min + floor(nativeRandom() * ((+max || 0) - min + 1)); +    } + +    /** +     * Resolves the value of `property` on `object`. If `property` is a function, +     * it will be invoked and its result returned, else the property value is +     * returned. If `object` is falsey, then `null` is returned. +     * +     * @static +     * @memberOf _ +     * @category Utilities +     * @param {Object} object The object to inspect. +     * @param {String} property The property to get the value of. +     * @returns {Mixed} Returns the resolved value. +     * @example +     * +     * var object = { +     *   'cheese': 'crumpets', +     *   'stuff': function() { +     *     return 'nonsense'; +     *   } +     * }; +     * +     * _.result(object, 'cheese'); +     * // => 'crumpets' +     * +     * _.result(object, 'stuff'); +     * // => 'nonsense' +     */ +    function result(object, property) { +      var value = object ? object[property] : undefined; +      return isFunction(value) ? object[property]() : value; +    } + +    /** +     * A micro-templating method that handles arbitrary delimiters, preserves +     * whitespace, and correctly escapes quotes within interpolated code. +     * +     * Note: In the development build, `_.template` utilizes sourceURLs for easier +     * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl +     * +     * Note: Lo-Dash may be used in Chrome extensions by either creating a `lodash csp` +     * build and using precompiled templates, or loading Lo-Dash in a sandbox. +     * +     * For more information on precompiling templates see: +     * http://lodash.com/#custom-builds +     * +     * For more information on Chrome extension sandboxes see: +     * http://developer.chrome.com/stable/extensions/sandboxingEval.html +     * +     * @static +     * @memberOf _ +     * @category Utilities +     * @param {String} text The template text. +     * @param {Obect} data The data object used to populate the text. +     * @param {Object} options The options object. +     *  escape - The "escape" delimiter regexp. +     *  evaluate - The "evaluate" delimiter regexp. +     *  interpolate - The "interpolate" delimiter regexp. +     *  sourceURL - The sourceURL of the template's compiled source. +     *  variable - The data object variable name. +     * @returns {Function|String} Returns a compiled function when no `data` object +     *  is given, else it returns the interpolated text. +     * @example +     * +     * // using a compiled template +     * var compiled = _.template('hello <%= name %>'); +     * compiled({ 'name': 'moe' }); +     * // => 'hello moe' +     * +     * var list = '<% _.forEach(people, function(name) { %><li><%= name %></li><% }); %>'; +     * _.template(list, { 'people': ['moe', 'larry'] }); +     * // => '<li>moe</li><li>larry</li>' +     * +     * // using the "escape" delimiter to escape HTML in data property values +     * _.template('<b><%- value %></b>', { 'value': '<script>' }); +     * // => '<b><script></b>' +     * +     * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter +     * _.template('hello ${ name }', { 'name': 'curly' }); +     * // => 'hello curly' +     * +     * // using the internal `print` function in "evaluate" delimiters +     * _.template('<% print("hello " + epithet); %>!', { 'epithet': 'stooge' }); +     * // => 'hello stooge!' +     * +     * // using custom template delimiters +     * _.templateSettings = { +     *   'interpolate': /{{([\s\S]+?)}}/g +     * }; +     * +     * _.template('hello {{ name }}!', { 'name': 'mustache' }); +     * // => 'hello mustache!' +     * +     * // using the `sourceURL` option to specify a custom sourceURL for the template +     * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' }); +     * compiled(data); +     * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector +     * +     * // using the `variable` option to ensure a with-statement isn't used in the compiled template +     * var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' }); +     * compiled.source; +     * // => function(data) { +     *   var __t, __p = '', __e = _.escape; +     *   __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!'; +     *   return __p; +     * } +     * +     * // using the `source` property to inline compiled templates for meaningful +     * // line numbers in error messages and a stack trace +     * fs.writeFileSync(path.join(cwd, 'jst.js'), '\ +     *   var JST = {\ +     *     "main": ' + _.template(mainText).source + '\ +     *   };\ +     * '); +     */ +    function template(text, data, options) { +      // based on John Resig's `tmpl` implementation +      // http://ejohn.org/blog/javascript-micro-templating/ +      // and Laura Doktorova's doT.js +      // https://github.com/olado/doT +      var settings = lodash.templateSettings; +      text || (text = ''); + +      // avoid missing dependencies when `iteratorTemplate` is not defined +      options = defaults({}, options, settings); + +      var imports = defaults({}, options.imports, settings.imports), +          importsKeys = keys(imports), +          importsValues = values(imports); + +      var isEvaluating, +          index = 0, +          interpolate = options.interpolate || reNoMatch, +          source = "__p += '"; + +      // compile the regexp to match each delimiter +      var reDelimiters = RegExp( +        (options.escape || reNoMatch).source + '|' + +        interpolate.source + '|' + +        (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' + +        (options.evaluate || reNoMatch).source + '|$' +      , 'g'); + +      text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) { +        interpolateValue || (interpolateValue = esTemplateValue); + +        // escape characters that cannot be included in string literals +        source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar); + +        // replace delimiters with snippets +        if (escapeValue) { +          source += "' +\n__e(" + escapeValue + ") +\n'"; +        } +        if (evaluateValue) { +          isEvaluating = true; +          source += "';\n" + evaluateValue + ";\n__p += '"; +        } +        if (interpolateValue) { +          source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'"; +        } +        index = offset + match.length; + +        // the JS engine embedded in Adobe products requires returning the `match` +        // string in order to produce the correct `offset` value +        return match; +      }); + +      source += "';\n"; + +      // if `variable` is not specified, wrap a with-statement around the generated +      // code to add the data object to the top of the scope chain +      var variable = options.variable, +          hasVariable = variable; + +      if (!hasVariable) { +        variable = 'obj'; +        source = 'with (' + variable + ') {\n' + source + '\n}\n'; +      } +      // cleanup code by stripping empty strings +      source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source) +        .replace(reEmptyStringMiddle, '$1') +        .replace(reEmptyStringTrailing, '$1;'); + +      // frame code as the function body +      source = 'function(' + variable + ') {\n' + +        (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') + +        "var __t, __p = '', __e = _.escape" + +        (isEvaluating +          ? ', __j = Array.prototype.join;\n' + +            "function print() { __p += __j.call(arguments, '') }\n" +          : ';\n' +        ) + +        source + +        'return __p\n}'; + +      // Use a sourceURL for easier debugging and wrap in a multi-line comment to +      // avoid issues with Narwhal, IE conditional compilation, and the JS engine +      // embedded in Adobe products. +      // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl +      var sourceURL = '\n/*\n//@ sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/'; + +      try { +        var result = Function(importsKeys, 'return ' + source + sourceURL).apply(undefined, importsValues); +      } catch(e) { +        e.source = source; +        throw e; +      } +      if (data) { +        return result(data); +      } +      // provide the compiled function's source via its `toString` method, in +      // supported environments, or the `source` property as a convenience for +      // inlining compiled templates during the build process +      result.source = source; +      return result; +    } + +    /** +     * Executes the `callback` function `n` times, returning an array of the results +     * of each `callback` execution. The `callback` is bound to `thisArg` and invoked +     * with one argument; (index). +     * +     * @static +     * @memberOf _ +     * @category Utilities +     * @param {Number} n The number of times to execute the callback. +     * @param {Function} callback The function called per iteration. +     * @param {Mixed} [thisArg] The `this` binding of `callback`. +     * @returns {Array} Returns a new array of the results of each `callback` execution. +     * @example +     * +     * var diceRolls = _.times(3, _.partial(_.random, 1, 6)); +     * // => [3, 6, 4] +     * +     * _.times(3, function(n) { mage.castSpell(n); }); +     * // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively +     * +     * _.times(3, function(n) { this.cast(n); }, mage); +     * // => also calls `mage.castSpell(n)` three times +     */ +    function times(n, callback, thisArg) { +      n = +n || 0; +      var index = -1, +          result = Array(n); + +      while (++index < n) { +        result[index] = callback.call(thisArg, index); +      } +      return result; +    } + +    /** +     * The opposite of `_.escape`, this method converts the HTML entities +     * `&`, `<`, `>`, `"`, and `'` in `string` to their +     * corresponding characters. +     * +     * @static +     * @memberOf _ +     * @category Utilities +     * @param {String} string The string to unescape. +     * @returns {String} Returns the unescaped string. +     * @example +     * +     * _.unescape('Moe, Larry & Curly'); +     * // => 'Moe, Larry & Curly' +     */ +    function unescape(string) { +      return string == null ? '' : (string + '').replace(reEscapedHtml, unescapeHtmlChar); +    } + +    /** +     * Generates a unique ID. If `prefix` is passed, the ID will be appended to it. +     * +     * @static +     * @memberOf _ +     * @category Utilities +     * @param {String} [prefix] The value to prefix the ID with. +     * @returns {String} Returns the unique ID. +     * @example +     * +     * _.uniqueId('contact_'); +     * // => 'contact_104' +     * +     * _.uniqueId(); +     * // => '105' +     */ +    function uniqueId(prefix) { +      var id = ++idCounter; +      return (prefix == null ? '' : prefix + '') + id; +    } + +    /*--------------------------------------------------------------------------*/ + +    /** +     * Invokes `interceptor` with the `value` as the first argument, and then +     * returns `value`. The purpose of this method is to "tap into" a method chain, +     * in order to perform operations on intermediate results within the chain. +     * +     * @static +     * @memberOf _ +     * @category Chaining +     * @param {Mixed} value The value to pass to `interceptor`. +     * @param {Function} interceptor The function to invoke. +     * @returns {Mixed} Returns `value`. +     * @example +     * +     * _([1, 2, 3, 4]) +     *  .filter(function(num) { return num % 2 == 0; }) +     *  .tap(alert) +     *  .map(function(num) { return num * num; }) +     *  .value(); +     * // => // [2, 4] (alerted) +     * // => [4, 16] +     */ +    function tap(value, interceptor) { +      interceptor(value); +      return value; +    } + +    /** +     * Produces the `toString` result of the wrapped value. +     * +     * @name toString +     * @memberOf _ +     * @category Chaining +     * @returns {String} Returns the string result. +     * @example +     * +     * _([1, 2, 3]).toString(); +     * // => '1,2,3' +     */ +    function wrapperToString() { +      return this.__wrapped__ + ''; +    } + +    /** +     * Extracts the wrapped value. +     * +     * @name valueOf +     * @memberOf _ +     * @alias value +     * @category Chaining +     * @returns {Mixed} Returns the wrapped value. +     * @example +     * +     * _([1, 2, 3]).valueOf(); +     * // => [1, 2, 3] +     */ +    function wrapperValueOf() { +      return this.__wrapped__; +    } + +    /*--------------------------------------------------------------------------*/ + +    // add functions that return wrapped values when chaining +    lodash.after = after; +    lodash.assign = assign; +    lodash.at = at; +    lodash.bind = bind; +    lodash.bindAll = bindAll; +    lodash.bindKey = bindKey; +    lodash.compact = compact; +    lodash.compose = compose; +    lodash.countBy = countBy; +    lodash.debounce = debounce; +    lodash.defaults = defaults; +    lodash.defer = defer; +    lodash.delay = delay; +    lodash.difference = difference; +    lodash.filter = filter; +    lodash.flatten = flatten; +    lodash.forEach = forEach; +    lodash.forIn = forIn; +    lodash.forOwn = forOwn; +    lodash.functions = functions; +    lodash.groupBy = groupBy; +    lodash.initial = initial; +    lodash.intersection = intersection; +    lodash.invert = invert; +    lodash.invoke = invoke; +    lodash.keys = keys; +    lodash.map = map; +    lodash.max = max; +    lodash.memoize = memoize; +    lodash.merge = merge; +    lodash.min = min; +    lodash.object = object; +    lodash.omit = omit; +    lodash.once = once; +    lodash.pairs = pairs; +    lodash.partial = partial; +    lodash.partialRight = partialRight; +    lodash.pick = pick; +    lodash.pluck = pluck; +    lodash.range = range; +    lodash.reject = reject; +    lodash.rest = rest; +    lodash.shuffle = shuffle; +    lodash.sortBy = sortBy; +    lodash.tap = tap; +    lodash.throttle = throttle; +    lodash.times = times; +    lodash.toArray = toArray; +    lodash.union = union; +    lodash.uniq = uniq; +    lodash.values = values; +    lodash.where = where; +    lodash.without = without; +    lodash.wrap = wrap; +    lodash.zip = zip; + +    // add aliases +    lodash.collect = map; +    lodash.drop = rest; +    lodash.each = forEach; +    lodash.extend = assign; +    lodash.methods = functions; +    lodash.select = filter; +    lodash.tail = rest; +    lodash.unique = uniq; + +    // add functions to `lodash.prototype` +    mixin(lodash); + +    /*--------------------------------------------------------------------------*/ + +    // add functions that return unwrapped values when chaining +    lodash.clone = clone; +    lodash.cloneDeep = cloneDeep; +    lodash.contains = contains; +    lodash.escape = escape; +    lodash.every = every; +    lodash.find = find; +    lodash.has = has; +    lodash.identity = identity; +    lodash.indexOf = indexOf; +    lodash.isArguments = isArguments; +    lodash.isArray = isArray; +    lodash.isBoolean = isBoolean; +    lodash.isDate = isDate; +    lodash.isElement = isElement; +    lodash.isEmpty = isEmpty; +    lodash.isEqual = isEqual; +    lodash.isFinite = isFinite; +    lodash.isFunction = isFunction; +    lodash.isNaN = isNaN; +    lodash.isNull = isNull; +    lodash.isNumber = isNumber; +    lodash.isObject = isObject; +    lodash.isPlainObject = isPlainObject; +    lodash.isRegExp = isRegExp; +    lodash.isString = isString; +    lodash.isUndefined = isUndefined; +    lodash.lastIndexOf = lastIndexOf; +    lodash.mixin = mixin; +    lodash.noConflict = noConflict; +    lodash.parseInt = parseInt; +    lodash.random = random; +    lodash.reduce = reduce; +    lodash.reduceRight = reduceRight; +    lodash.result = result; +    lodash.runInContext = runInContext; +    lodash.size = size; +    lodash.some = some; +    lodash.sortedIndex = sortedIndex; +    lodash.template = template; +    lodash.unescape = unescape; +    lodash.uniqueId = uniqueId; + +    // add aliases +    lodash.all = every; +    lodash.any = some; +    lodash.detect = find; +    lodash.foldl = reduce; +    lodash.foldr = reduceRight; +    lodash.include = contains; +    lodash.inject = reduce; + +    forOwn(lodash, function(func, methodName) { +      if (!lodash.prototype[methodName]) { +        lodash.prototype[methodName] = function() { +          var args = [this.__wrapped__]; +          push.apply(args, arguments); +          return func.apply(lodash, args); +        }; +      } +    }); + +    /*--------------------------------------------------------------------------*/ + +    // add functions capable of returning wrapped and unwrapped values when chaining +    lodash.first = first; +    lodash.last = last; + +    // add aliases +    lodash.take = first; +    lodash.head = first; + +    forOwn(lodash, function(func, methodName) { +      if (!lodash.prototype[methodName]) { +        lodash.prototype[methodName]= function(callback, thisArg) { +          var result = func(this.__wrapped__, callback, thisArg); +          return callback == null || (thisArg && typeof callback != 'function') +            ? result +            : new lodash(result); +        }; +      } +    }); + +    /*--------------------------------------------------------------------------*/ + +    /** +     * The semantic version number. +     * +     * @static +     * @memberOf _ +     * @type String +     */ +    lodash.VERSION = '1.0.1'; + +    // add "Chaining" functions to the wrapper +    lodash.prototype.toString = wrapperToString; +    lodash.prototype.value = wrapperValueOf; +    lodash.prototype.valueOf = wrapperValueOf; + +    // add `Array` functions that return unwrapped values +    each(['join', 'pop', 'shift'], function(methodName) { +      var func = arrayRef[methodName]; +      lodash.prototype[methodName] = function() { +        return func.apply(this.__wrapped__, arguments); +      }; +    }); + +    // add `Array` functions that return the wrapped value +    each(['push', 'reverse', 'sort', 'unshift'], function(methodName) { +      var func = arrayRef[methodName]; +      lodash.prototype[methodName] = function() { +        func.apply(this.__wrapped__, arguments); +        return this; +      }; +    }); + +    // add `Array` functions that return new wrapped values +    each(['concat', 'slice', 'splice'], function(methodName) { +      var func = arrayRef[methodName]; +      lodash.prototype[methodName] = function() { +        return new lodash(func.apply(this.__wrapped__, arguments)); +      }; +    }); + +    return lodash; +  } + +  /*--------------------------------------------------------------------------*/ + +  // expose Lo-Dash +  var _ = runInContext(); + +  // some AMD build optimizers, like r.js, check for specific condition patterns like the following: +  if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { +    // Expose Lo-Dash to the global object even when an AMD loader is present in +    // case Lo-Dash was injected by a third-party script and not intended to be +    // loaded as a module. The global assignment can be reverted in the Lo-Dash +    // module via its `noConflict()` method. +    window._ = _; + +    // define as an anonymous module so, through path mapping, it can be +    // referenced as the "underscore" module +    define(function() { +      return _; +    }); +  } +  // check for `exports` after `define` in case a build optimizer adds an `exports` object +  else if (freeExports && !freeExports.nodeType) { +    // in Node.js or RingoJS v0.8.0+ +    if (freeModule) { +      (freeModule.exports = _)._ = _; +    } +    // in Narwhal or RingoJS v0.7.0- +    else { +      freeExports._ = _; +    } +  } +  else { +    // in a browser or Rhino +    window._ = _; +  } +}(this)); diff --git a/module/web/static/js/libs/lodash-1.0.rc3.js b/module/web/static/js/libs/lodash-1.0.rc3.js deleted file mode 100644 index f4a8bb12d..000000000 --- a/module/web/static/js/libs/lodash-1.0.rc3.js +++ /dev/null @@ -1,4454 +0,0 @@ -/*! - * Lo-Dash 1.0.0-rc.3 <http://lodash.com> - * (c) 2012 John-David Dalton <http://allyoucanleet.com/> - * Based on Underscore.js 1.4.3 <http://underscorejs.org> - * (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. - * Available under MIT license <http://lodash.com/license> - */ -;(function(window, undefined) { - -  /** Detect free variable `exports` */ -  var freeExports = typeof exports == 'object' && exports; - -  /** Detect free variable `global` and use it as `window` */ -  var freeGlobal = typeof global == 'object' && global; -  if (freeGlobal.global === freeGlobal) { -    window = freeGlobal; -  } - -  /** Used for array and object method references */ -  var arrayRef = [], -      // avoid a Closure Compiler bug by creatively creating an object -      objectRef = new function(){}; - -  /** Used to generate unique IDs */ -  var idCounter = 0; - -  /** Used internally to indicate various things */ -  var indicatorObject = objectRef; - -  /** Used by `cachedContains` as the default size when optimizations are enabled for large arrays */ -  var largeArraySize = 30; - -  /** Used to restore the original `_` reference in `noConflict` */ -  var oldDash = window._; - -  /** Used to detect template delimiter values that require a with-statement */ -  var reComplexDelimiter = /[-?+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/; - -  /** Used to match HTML entities */ -  var reEscapedHtml = /&(?:amp|lt|gt|quot|#x27);/g; - -  /** Used to match empty string literals in compiled template source */ -  var reEmptyStringLeading = /\b__p \+= '';/g, -      reEmptyStringMiddle = /\b(__p \+=) '' \+/g, -      reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; - -  /** Used to match regexp flags from their coerced string values */ -  var reFlags = /\w*$/; - -  /** Used to insert the data object variable into compiled template source */ -  var reInsertVariable = /(?:__e|__t = )\(\s*(?![\d\s"']|this\.)/g; - -  /** Used to detect if a method is native */ -  var reNative = RegExp('^' + -    (objectRef.valueOf + '') -      .replace(/[.*+?^=!:${}()|[\]\/\\]/g, '\\$&') -      .replace(/valueOf|for [^\]]+/g, '.+?') + '$' -  ); - -  /** -   * Used to match ES6 template delimiters -   * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-7.8.6 -   */ -  var reEsTemplate = /\$\{((?:(?=\\?)\\?[\s\S])*?)}/g; - -  /** Used to match "interpolate" template delimiters */ -  var reInterpolate = /<%=([\s\S]+?)%>/g; - -  /** Used to ensure capturing order of template delimiters */ -  var reNoMatch = /($^)/; - -  /** Used to match HTML characters */ -  var reUnescapedHtml = /[&<>"']/g; - -  /** Used to match unescaped characters in compiled string literals */ -  var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g; - -  /** Used to fix the JScript [[DontEnum]] bug */ -  var shadowed = [ -    'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', -    'toLocaleString', 'toString', 'valueOf' -  ]; - -  /** Used to make template sourceURLs easier to identify */ -  var templateCounter = 0; - -  /** Native method shortcuts */ -  var ceil = Math.ceil, -      concat = arrayRef.concat, -      floor = Math.floor, -      getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf, -      hasOwnProperty = objectRef.hasOwnProperty, -      push = arrayRef.push, -      propertyIsEnumerable = objectRef.propertyIsEnumerable, -      toString = objectRef.toString; - -  /* Native method shortcuts for methods with the same name as other `lodash` methods */ -  var nativeBind = reNative.test(nativeBind = slice.bind) && nativeBind, -      nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray, -      nativeIsFinite = window.isFinite, -      nativeIsNaN = window.isNaN, -      nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys, -      nativeMax = Math.max, -      nativeMin = Math.min, -      nativeRandom = Math.random; - -  /** `Object#toString` result shortcuts */ -  var argsClass = '[object Arguments]', -      arrayClass = '[object Array]', -      boolClass = '[object Boolean]', -      dateClass = '[object Date]', -      funcClass = '[object Function]', -      numberClass = '[object Number]', -      objectClass = '[object Object]', -      regexpClass = '[object RegExp]', -      stringClass = '[object String]'; - -  /** Detect various environments */ -  var isIeOpera = !!window.attachEvent, -      isV8 = nativeBind && !/\n|true/.test(nativeBind + isIeOpera); - -  /* Detect if `Function#bind` exists and is inferred to be fast (all but V8) */ -  var isBindFast = nativeBind && !isV8; - -  /* Detect if `Object.keys` exists and is inferred to be fast (IE, Opera, V8) */ -  var isKeysFast = nativeKeys && (isIeOpera || isV8); - -  /** -   * Detect the JScript [[DontEnum]] bug: -   * -   * In IE < 9 an objects own properties, shadowing non-enumerable ones, are -   * made non-enumerable as well. -   */ -  var hasDontEnumBug; - -  /** Detect if own properties are iterated after inherited properties (IE < 9) */ -  var iteratesOwnLast; - -  /** -   * Detect if `Array#shift` and `Array#splice` augment array-like objects -   * incorrectly: -   * -   * Firefox < 10, IE compatibility mode, and IE < 9 have buggy Array `shift()` -   * and `splice()` functions that fail to remove the last element, `value[0]`, -   * of array-like objects even though the `length` property is set to `0`. -   * The `shift()` method is buggy in IE 8 compatibility mode, while `splice()` -   * is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9. -   */ -  var hasObjectSpliceBug = (hasObjectSpliceBug = { '0': 1, 'length': 1 }, -    arrayRef.splice.call(hasObjectSpliceBug, 0, 1), hasObjectSpliceBug[0]); - -  /** Detect if an `arguments` object's indexes are non-enumerable (IE < 9) */ -  var nonEnumArgs = true; - -  (function() { -    var props = []; -    function ctor() { this.x = 1; } -    ctor.prototype = { 'valueOf': 1, 'y': 1 }; -    for (var prop in new ctor) { props.push(prop); } -    for (prop in arguments) { nonEnumArgs = !prop; } - -    hasDontEnumBug = !/valueOf/.test(props); -    iteratesOwnLast = props[0] != 'x'; -  }(1)); - -  /** Detect if `arguments` objects are `Object` objects (all but Opera < 10.5) */ -  var argsAreObjects = arguments.constructor == Object; - -  /** Detect if `arguments` objects [[Class]] is unresolvable (Firefox < 4, IE < 9) */ -  var noArgsClass = !isArguments(arguments); - -  /** -   * Detect lack of support for accessing string characters by index: -   * -   * IE < 8 can't access characters by index and IE 8 can only access -   * characters by index on string literals. -   */ -  var noCharByIndex = ('x'[0] + Object('x')[0]) != 'xx'; - -  /** -   * Detect if a node's [[Class]] is unresolvable (IE < 9) -   * and that the JS engine won't error when attempting to coerce an object to -   * a string without a `toString` property value of `typeof` "function". -   */ -  try { -    var noNodeClass = ({ 'toString': 0 } + '', toString.call(document) == objectClass); -  } catch(e) { } - -  /** -   * Detect if sourceURL syntax is usable without erroring: -   * -   * The JS engine embedded in Adobe products will throw a syntax error when -   * it encounters a single line comment beginning with the `@` symbol. -   * -   * The JS engine in Narwhal will generate the function `function anonymous(){//}` -   * and throw a syntax error. -   * -   * Avoid comments beginning `@` symbols in IE because they are part of its -   * non-standard conditional compilation support. -   * http://msdn.microsoft.com/en-us/library/121hztk3(v=vs.94).aspx -   */ -  try { -    var useSourceURL = (Function('//@')(), !isIeOpera); -  } catch(e) { } - -  /** Used to identify object classifications that `_.clone` supports */ -  var cloneableClasses = {}; -  cloneableClasses[funcClass] = false; -  cloneableClasses[argsClass] = cloneableClasses[arrayClass] = -  cloneableClasses[boolClass] = cloneableClasses[dateClass] = -  cloneableClasses[numberClass] = cloneableClasses[objectClass] = -  cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true; - -  /** Used to lookup a built-in constructor by [[Class]] */ -  var ctorByClass = {}; -  ctorByClass[arrayClass] = Array; -  ctorByClass[boolClass] = Boolean; -  ctorByClass[dateClass] = Date; -  ctorByClass[objectClass] = Object; -  ctorByClass[numberClass] = Number; -  ctorByClass[regexpClass] = RegExp; -  ctorByClass[stringClass] = String; - -  /** Used to determine if values are of the language type Object */ -  var objectTypes = { -    'boolean': false, -    'function': true, -    'object': true, -    'number': false, -    'string': false, -    'undefined': false -  }; - -  /** Used to escape characters for inclusion in compiled string literals */ -  var stringEscapes = { -    '\\': '\\', -    "'": "'", -    '\n': 'n', -    '\r': 'r', -    '\t': 't', -    '\u2028': 'u2028', -    '\u2029': 'u2029' -  }; - -  /*--------------------------------------------------------------------------*/ - -  /** -   * Creates a `lodash` object, that wraps the given `value`, to enable -   * method chaining. -   * -   * The chainable wrapper functions are: -   * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`, `compose`, -   * `concat`, `countBy`, `debounce`, `defaults`, `defer`, `delay`, `difference`, -   * `filter`, `flatten`, `forEach`, `forIn`, `forOwn`, `functions`, `groupBy`, -   * `initial`, `intersection`, `invert`, `invoke`, `keys`, `map`, `max`, `memoize`, -   * `merge`, `min`, `object`, `omit`, `once`, `pairs`, `partial`, `pick`, `pluck`, -   * `push`, `range`, `reject`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, -   * `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `union`, `uniq`, -   * `unshift`, `values`, `where`, `without`, `wrap`, and `zip` -   * -   * The non-chainable wrapper functions are: -   * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `has`, `identity`, -   * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, `isEmpty`, -   * `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`, `isObject`, -   * `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`, `lastIndexOf`, -   * `mixin`, `noConflict`, `pop`, `random`, `reduce`, `reduceRight`, `result`, -   * `shift`, `size`, `some`, `sortedIndex`, `template`, `unescape`, and `uniqueId` -   * -   * The wrapper functions `first` and `last` return wrapped values when `n` is -   * passed, otherwise they return unwrapped values. -   * -   * @name _ -   * @constructor -   * @category Chaining -   * @param {Mixed} value The value to wrap in a `lodash` instance. -   * @returns {Object} Returns a `lodash` instance. -   */ -  function lodash(value) { -    // exit early if already wrapped, even if wrapped by a different `lodash` constructor -    if (value && typeof value == 'object' && value.__wrapped__) { -      return value; -    } -    // allow invoking `lodash` without the `new` operator -    if (!(this instanceof lodash)) { -      return new lodash(value); -    } -    this.__wrapped__ = value; -  } - -  /** -   * By default, the template delimiters used by Lo-Dash are similar to those in -   * embedded Ruby (ERB). Change the following template settings to use alternative -   * delimiters. -   * -   * @static -   * @memberOf _ -   * @type Object -   */ -  lodash.templateSettings = { - -    /** -     * Used to detect `data` property values to be HTML-escaped. -     * -     * @static -     * @memberOf _.templateSettings -     * @type RegExp -     */ -    'escape': /<%-([\s\S]+?)%>/g, - -    /** -     * Used to detect code to be evaluated. -     * -     * @static -     * @memberOf _.templateSettings -     * @type RegExp -     */ -    'evaluate': /<%([\s\S]+?)%>/g, - -    /** -     * Used to detect `data` property values to inject. -     * -     * @static -     * @memberOf _.templateSettings -     * @type RegExp -     */ -    'interpolate': reInterpolate, - -    /** -     * Used to reference the data object in the template text. -     * -     * @static -     * @memberOf _.templateSettings -     * @type String -     */ -    'variable': '' -  }; - -  /*--------------------------------------------------------------------------*/ - -  /** -   * The template used to create iterator functions. -   * -   * @private -   * @param {Obect} data The data object used to populate the text. -   * @returns {String} Returns the interpolated text. -   */ -  var iteratorTemplate = template( -    // conditional strict mode -    "<% if (obj.useStrict) { %>'use strict';\n<% } %>" + - -    // the `iteratee` may be reassigned by the `top` snippet -    'var index, iteratee = <%= firstArg %>, ' + -    // assign the `result` variable an initial value -    'result = <%= firstArg %>;\n' + -    // exit early if the first argument is falsey -    'if (!<%= firstArg %>) return result;\n' + -    // add code before the iteration branches -    '<%= top %>;\n' + - -    // array-like iteration: -    '<% if (arrayLoop) { %>' + -    'var length = iteratee.length; index = -1;\n' + -    "if (typeof length == 'number') {" + - -    // add support for accessing string characters by index if needed -    '  <% if (noCharByIndex) { %>\n' + -    '  if (isString(iteratee)) {\n' + -    "    iteratee = iteratee.split('')\n" + -    '  }' + -    '  <% } %>\n' + - -    // iterate over the array-like value -    '  while (++index < length) {\n' + -    '    <%= arrayLoop %>\n' + -    '  }\n' + -    '}\n' + -    'else {' + - -    // object iteration: -    // add support for iterating over `arguments` objects if needed -    '  <%  } else if (nonEnumArgs) { %>\n' + -    '  var length = iteratee.length; index = -1;\n' + -    '  if (length && isArguments(iteratee)) {\n' + -    '    while (++index < length) {\n' + -    "      index += '';\n" + -    '      <%= objectLoop %>\n' + -    '    }\n' + -    '  } else {' + -    '  <% } %>' + - -    // Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1 -    // (if the prototype or a property on the prototype has been set) -    // incorrectly sets a function's `prototype` property [[Enumerable]] -    // value to `true`. Because of this Lo-Dash standardizes on skipping -    // the the `prototype` property of functions regardless of its -    // [[Enumerable]] value. -    '  <% if (!hasDontEnumBug) { %>\n' + -    "  var skipProto = typeof iteratee == 'function' && \n" + -    "    propertyIsEnumerable.call(iteratee, 'prototype');\n" + -    '  <% } %>' + - -    // iterate own properties using `Object.keys` if it's fast -    '  <% if (isKeysFast && useHas) { %>\n' + -    '  var ownIndex = -1,\n' + -    '      ownProps = objectTypes[typeof iteratee] ? nativeKeys(iteratee) : [],\n' + -    '      length = ownProps.length;\n\n' + -    '  while (++ownIndex < length) {\n' + -    '    index = ownProps[ownIndex];\n' + -    "    <% if (!hasDontEnumBug) { %>if (!(skipProto && index == 'prototype')) {\n  <% } %>" + -    '    <%= objectLoop %>\n' + -    '    <% if (!hasDontEnumBug) { %>}\n<% } %>' + -    '  }' + - -    // else using a for-in loop -    '  <% } else { %>\n' + -    '  for (index in iteratee) {<%' + -    '    if (!hasDontEnumBug || useHas) { %>\n    if (<%' + -    "      if (!hasDontEnumBug) { %>!(skipProto && index == 'prototype')<% }" + -    '      if (!hasDontEnumBug && useHas) { %> && <% }' + -    '      if (useHas) { %>hasOwnProperty.call(iteratee, index)<% }' + -    '    %>) {' + -    '    <% } %>\n' + -    '    <%= objectLoop %>;' + -    '    <% if (!hasDontEnumBug || useHas) { %>\n    }<% } %>\n' + -    '  }' + -    '  <% } %>' + - -    // Because IE < 9 can't set the `[[Enumerable]]` attribute of an -    // existing property and the `constructor` property of a prototype -    // defaults to non-enumerable, Lo-Dash skips the `constructor` -    // property when it infers it's iterating over a `prototype` object. -    '  <% if (hasDontEnumBug) { %>\n\n' + -    '  var ctor = iteratee.constructor;\n' + -    '    <% for (var k = 0; k < 7; k++) { %>\n' + -    "  index = '<%= shadowed[k] %>';\n" + -    '  if (<%' + -    "      if (shadowed[k] == 'constructor') {" + -    '        %>!(ctor && ctor.prototype === iteratee) && <%' + -    '      } %>hasOwnProperty.call(iteratee, index)) {\n' + -    '    <%= objectLoop %>\n' + -    '  }' + -    '    <% } %>' + -    '  <% } %>' + -    '  <% if (arrayLoop || nonEnumArgs) { %>\n}<% } %>\n' + - -    // add code to the bottom of the iteration function -    '<%= bottom %>;\n' + -    // finally, return the `result` -    'return result' -  ); - -  /** Reusable iterator options for `assign` and `defaults` */ -  var assignIteratorOptions = { -    'args': 'object, source, guard', -    'top': -      "for (var argsIndex = 1, argsLength = typeof guard == 'number' ? 2 : arguments.length; argsIndex < argsLength; argsIndex++) {\n" + -      '  if ((iteratee = arguments[argsIndex])) {', -    'objectLoop': 'result[index] = iteratee[index]', -    'bottom': '  }\n}' -  }; - -  /** -   * Reusable iterator options shared by `each`, `forIn`, and `forOwn`. -   */ -  var eachIteratorOptions = { -    'args': 'collection, callback, thisArg', -    'top': "callback = callback && typeof thisArg == 'undefined' ? callback : createCallback(callback, thisArg)", -    'arrayLoop': 'if (callback(iteratee[index], index, collection) === false) return result', -    'objectLoop': 'if (callback(iteratee[index], index, collection) === false) return result' -  }; - -  /** Reusable iterator options for `forIn` and `forOwn` */ -  var forOwnIteratorOptions = { -    'arrayLoop': null -  }; - -  /*--------------------------------------------------------------------------*/ - -  /** -   * Creates a function optimized to search large arrays for a given `value`, -   * starting at `fromIndex`, using strict equality for comparisons, i.e. `===`. -   * -   * @private -   * @param {Array} array The array to search. -   * @param {Mixed} value The value to search for. -   * @param {Number} [fromIndex=0] The index to search from. -   * @param {Number} [largeSize=30] The length at which an array is considered large. -   * @returns {Boolean} Returns `true` if `value` is found, else `false`. -   */ -  function cachedContains(array, fromIndex, largeSize) { -    fromIndex || (fromIndex = 0); - -    var length = array.length, -        isLarge = (length - fromIndex) >= (largeSize || largeArraySize); - -    if (isLarge) { -      var cache = {}, -          index = fromIndex - 1; - -      while (++index < length) { -        // manually coerce `value` to a string because `hasOwnProperty`, in some -        // older versions of Firefox, coerces objects incorrectly -        var key = array[index] + ''; -        (hasOwnProperty.call(cache, key) ? cache[key] : (cache[key] = [])).push(array[index]); -      } -    } -    return function(value) { -      if (isLarge) { -        var key = value + ''; -        return hasOwnProperty.call(cache, key) && indexOf(cache[key], value) > -1; -      } -      return indexOf(array, value, fromIndex) > -1; -    } -  } - -  /** -   * Used by `_.max` and `_.min` as the default `callback` when a given -   * `collection` is a string value. -   * -   * @private -   * @param {String} value The character to inspect. -   * @returns {Number} Returns the code unit of given character. -   */ -  function charAtCallback(value) { -    return value.charCodeAt(0); -  } - -  /** -   * Used by `sortBy` to compare transformed `collection` values, stable sorting -   * them in ascending order. -   * -   * @private -   * @param {Object} a The object to compare to `b`. -   * @param {Object} b The object to compare to `a`. -   * @returns {Number} Returns the sort order indicator of `1` or `-1`. -   */ -  function compareAscending(a, b) { -    var ai = a.index, -        bi = b.index; - -    a = a.criteria; -    b = b.criteria; - -    // ensure a stable sort in V8 and other engines -    // http://code.google.com/p/v8/issues/detail?id=90 -    if (a !== b) { -      if (a > b || typeof a == 'undefined') { -        return 1; -      } -      if (a < b || typeof b == 'undefined') { -        return -1; -      } -    } -    return ai < bi ? -1 : 1; -  } - -  /** -   * Creates a function that, when called, invokes `func` with the `this` -   * binding of `thisArg` and prepends any `partailArgs` to the arguments passed -   * to the bound function. -   * -   * @private -   * @param {Function|String} func The function to bind or the method name. -   * @param {Mixed} [thisArg] The `this` binding of `func`. -   * @param {Array} partialArgs An array of arguments to be partially applied. -   * @returns {Function} Returns the new bound function. -   */ -  function createBound(func, thisArg, partialArgs) { -    var isFunc = isFunction(func), -        isPartial = !partialArgs, -        key = thisArg; - -    // juggle arguments -    if (isPartial) { -      partialArgs = thisArg; -    } -    if (!isFunc) { -      thisArg = func; -    } - -    function bound() { -      // `Function#bind` spec -      // http://es5.github.com/#x15.3.4.5 -      var args = arguments, -          thisBinding = isPartial ? this : thisArg; - -      if (!isFunc) { -        func = thisArg[key]; -      } -      if (partialArgs.length) { -        args = args.length -          ? partialArgs.concat(slice(args)) -          : partialArgs; -      } -      if (this instanceof bound) { -        // ensure `new bound` is an instance of `bound` and `func` -        noop.prototype = func.prototype; -        thisBinding = new noop; -        noop.prototype = null; - -        // mimic the constructor's `return` behavior -        // http://es5.github.com/#x13.2.2 -        var result = func.apply(thisBinding, args); -        return isObject(result) ? result : thisBinding; -      } -      return func.apply(thisBinding, args); -    } -    return bound; -  } - -  /** -   * Produces an iteration callback bound to an optional `thisArg`. If `func` is -   * a property name, the callback will return the property value for a given element. -   * -   * @private -   * @param {Function|String} [func=identity|property] The function called per -   * iteration or property name to query. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @param {Object} [accumulating] Used to indicate that the callback should -   *  accept an `accumulator` argument. -   * @returns {Function} Returns a callback function. -   */ -  function createCallback(func, thisArg, accumulating) { -    if (!func) { -      return identity; -    } -    if (typeof func != 'function') { -      return function(object) { -        return object[func]; -      }; -    } -    if (typeof thisArg != 'undefined') { -      if (accumulating) { -        return function(accumulator, value, index, object) { -          return func.call(thisArg, accumulator, value, index, object); -        }; -      } -      return function(value, index, object) { -        return func.call(thisArg, value, index, object); -      }; -    } -    return func; -  } - -  /** -   * Creates compiled iteration functions. -   * -   * @private -   * @param {Object} [options1, options2, ...] The compile options object(s). -   *  useHas - A boolean to specify using `hasOwnProperty` checks in the object loop. -   *  args - A string of comma separated arguments the iteration function will accept. -   *  top - A string of code to execute before the iteration branches. -   *  arrayLoop - A string of code to execute in the array loop. -   *  objectLoop - A string of code to execute in the object loop. -   *  bottom - A string of code to execute after the iteration branches. -   * -   * @returns {Function} Returns the compiled function. -   */ -  function createIterator() { -    var data = { -      'arrayLoop': '', -      'bottom': '', -      'hasDontEnumBug': hasDontEnumBug, -      'isKeysFast': isKeysFast, -      'objectLoop': '', -      'nonEnumArgs': nonEnumArgs, -      'noCharByIndex': noCharByIndex, -      'shadowed': shadowed, -      'top': '', -      'useHas': true -    }; - -    // merge options into a template data object -    for (var object, index = 0; object = arguments[index]; index++) { -      for (var key in object) { -        data[key] = object[key]; -      } -    } -    var args = data.args; -    data.firstArg = /^[^,]+/.exec(args)[0]; - -    // create the function factory -    var factory = Function( -        'createCallback, hasOwnProperty, isArguments, isString, objectTypes, ' + -        'nativeKeys, propertyIsEnumerable', -      'return function(' + args + ') {\n' + iteratorTemplate(data) + '\n}' -    ); -    // return the compiled function -    return factory( -      createCallback, hasOwnProperty, isArguments, isString, objectTypes, -      nativeKeys, propertyIsEnumerable -    ); -  } - -  /** -   * A function compiled to iterate `arguments` objects, arrays, objects, and -   * strings consistenly across environments, executing the `callback` for each -   * element in the `collection`. The `callback` is bound to `thisArg` and invoked -   * with three arguments; (value, index|key, collection). Callbacks may exit -   * iteration early by explicitly returning `false`. -   * -   * @private -   * @param {Array|Object|String} collection The collection to iterate over. -   * @param {Function} [callback=identity] The function called per iteration. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Array|Object|String} Returns `collection`. -   */ -  var each = createIterator(eachIteratorOptions); - -  /** -   * Used by `template` to escape characters for inclusion in compiled -   * string literals. -   * -   * @private -   * @param {String} match The matched character to escape. -   * @returns {String} Returns the escaped character. -   */ -  function escapeStringChar(match) { -    return '\\' + stringEscapes[match]; -  } - -  /** -   * Used by `escape` to convert characters to HTML entities. -   * -   * @private -   * @param {String} match The matched character to escape. -   * @returns {String} Returns the escaped character. -   */ -  function escapeHtmlChar(match) { -    return htmlEscapes[match]; -  } - -  /** -   * Checks if `value` is a DOM node in IE < 9. -   * -   * @private -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is a DOM node, else `false`. -   */ -  function isNode(value) { -    // IE < 9 presents DOM nodes as `Object` objects except they have `toString` -    // methods that are `typeof` "string" and still can coerce nodes to strings -    return typeof value.toString != 'function' && typeof (value + '') == 'string'; -  } - -  /** -   * A no-operation function. -   * -   * @private -   */ -  function noop() { -    // no operation performed -  } - -  /** -   * Slices the `collection` from the `start` index up to, but not including, -   * the `end` index. -   * -   * Note: This function is used, instead of `Array#slice`, to support node lists -   * in IE < 9 and to ensure dense arrays are returned. -   * -   * @private -   * @param {Array|Object|String} collection The collection to slice. -   * @param {Number} start The start index. -   * @param {Number} end The end index. -   * @returns {Array} Returns the new array. -   */ -  function slice(array, start, end) { -    start || (start = 0); -    if (typeof end == 'undefined') { -      end = array ? array.length : 0; -    } -    var index = -1, -        length = end - start || 0, -        result = Array(length < 0 ? 0 : length); - -    while (++index < length) { -      result[index] = array[start + index]; -    } -    return result; -  } - -  /** -   * Used by `unescape` to convert HTML entities to characters. -   * -   * @private -   * @param {String} match The matched character to unescape. -   * @returns {String} Returns the unescaped character. -   */ -  function unescapeHtmlChar(match) { -    return htmlUnescapes[match]; -  } - -  /*--------------------------------------------------------------------------*/ - -  /** -   * Assigns own enumerable properties of source object(s) to the `destination` -   * object. Subsequent sources will overwrite propery assignments of previous -   * sources. -   * -   * @static -   * @memberOf _ -   * @alias extend -   * @category Objects -   * @param {Object} object The destination object. -   * @param {Object} [source1, source2, ...] The source objects. -   * @returns {Object} Returns the destination object. -   * @example -   * -   * _.assign({ 'name': 'moe' }, { 'age': 40 }); -   * // => { 'name': 'moe', 'age': 40 } -   */ -  var assign = createIterator(assignIteratorOptions); - -  /** -   * Checks if `value` is an `arguments` object. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is an `arguments` object, else `false`. -   * @example -   * -   * (function() { return _.isArguments(arguments); })(1, 2, 3); -   * // => true -   * -   * _.isArguments([1, 2, 3]); -   * // => false -   */ -  function isArguments(value) { -    return toString.call(value) == argsClass; -  } -  // fallback for browsers that can't detect `arguments` objects by [[Class]] -  if (noArgsClass) { -    isArguments = function(value) { -      return value ? hasOwnProperty.call(value, 'callee') : false; -    }; -  } - -  /** -   * Iterates over `object`'s own and inherited enumerable properties, executing -   * the `callback` for each property. The `callback` is bound to `thisArg` and -   * invoked with three arguments; (value, key, object). Callbacks may exit iteration -   * early by explicitly returning `false`. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Object} object The object to iterate over. -   * @param {Function} [callback=identity] The function called per iteration. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Object} Returns `object`. -   * @example -   * -   * function Dog(name) { -   *   this.name = name; -   * } -   * -   * Dog.prototype.bark = function() { -   *   alert('Woof, woof!'); -   * }; -   * -   * _.forIn(new Dog('Dagny'), function(value, key) { -   *   alert(key); -   * }); -   * // => alerts 'name' and 'bark' (order is not guaranteed) -   */ -  var forIn = createIterator(eachIteratorOptions, forOwnIteratorOptions, { -    'useHas': false -  }); - -  /** -   * Iterates over an object's own enumerable properties, executing the `callback` -   * for each property. The `callback` is bound to `thisArg` and invoked with three -   * arguments; (value, key, object). Callbacks may exit iteration early by explicitly -   * returning `false`. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Object} object The object to iterate over. -   * @param {Function} [callback=identity] The function called per iteration. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Object} Returns `object`. -   * @example -   * -   * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) { -   *   alert(key); -   * }); -   * // => alerts '0', '1', and 'length' (order is not guaranteed) -   */ -  var forOwn = createIterator(eachIteratorOptions, forOwnIteratorOptions); - -  /** -   * A fallback implementation of `isPlainObject` that checks if a given `value` -   * is an object created by the `Object` constructor, assuming objects created -   * by the `Object` constructor have no inherited enumerable properties and that -   * there are no `Object.prototype` extensions. -   * -   * @private -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if `value` is a plain object, else `false`. -   */ -  function shimIsPlainObject(value) { -    // avoid non-objects and false positives for `arguments` objects -    var result = false; -    if (!(value && typeof value == 'object') || isArguments(value)) { -      return result; -    } -    // check that the constructor is `Object` (i.e. `Object instanceof Object`) -    var ctor = value.constructor; -    if ((!isFunction(ctor) && (!noNodeClass || !isNode(value))) || ctor instanceof ctor) { -      // IE < 9 iterates inherited properties before own properties. If the first -      // iterated property is an object's own property then there are no inherited -      // enumerable properties. -      if (iteratesOwnLast) { -        forIn(value, function(value, key, object) { -          result = !hasOwnProperty.call(object, key); -          return false; -        }); -        return result === false; -      } -      // In most environments an object's own properties are iterated before -      // its inherited properties. If the last iterated property is an object's -      // own property then there are no inherited enumerable properties. -      forIn(value, function(value, key) { -        result = key; -      }); -      return result === false || hasOwnProperty.call(value, result); -    } -    return result; -  } - -  /** -   * A fallback implementation of `Object.keys` that produces an array of the -   * given object's own enumerable property names. -   * -   * @private -   * @param {Object} object The object to inspect. -   * @returns {Array} Returns a new array of property names. -   */ -  function shimKeys(object) { -    var result = []; -    forOwn(object, function(value, key) { -      result.push(key); -    }); -    return result; -  } - -  /** -   * Used to convert characters to HTML entities: -   * -   * Though the `>` character is escaped for symmetry, characters like `>` and `/` -   * don't require escaping in HTML and have no special meaning unless they're part -   * of a tag or an unquoted attribute value. -   * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact") -   */ -  var htmlEscapes = { -    '&': '&', -    '<': '<', -    '>': '>', -    '"': '"', -    "'": ''' -  }; - -  /** Used to convert HTML entities to characters */ -  var htmlUnescapes = invert(htmlEscapes); - -  /*--------------------------------------------------------------------------*/ - -  /** -   * Creates a clone of `value`. If `deep` is `true`, nested objects will also -   * be cloned, otherwise they will be assigned by reference. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to clone. -   * @param {Boolean} deep A flag to indicate a deep clone. -   * @param- {Object} [guard] Internally used to allow this method to work with -   *  others like `_.map` without using their callback `index` argument for `deep`. -   * @param- {Array} [stackA=[]] Internally used to track traversed source objects. -   * @param- {Array} [stackB=[]] Internally used to associate clones with their -   *  source counterparts. -   * @returns {Mixed} Returns the cloned `value`. -   * @example -   * -   * var stooges = [ -   *   { 'name': 'moe', 'age': 40 }, -   *   { 'name': 'larry', 'age': 50 }, -   *   { 'name': 'curly', 'age': 60 } -   * ]; -   * -   * var shallow = _.clone(stooges); -   * shallow[0] === stooges[0]; -   * // => true -   * -   * var deep = _.clone(stooges, true); -   * deep[0] === stooges[0]; -   * // => false -   */ -  function clone(value, deep, guard, stackA, stackB) { -    if (value == null) { -      return value; -    } -    if (guard) { -      deep = false; -    } -    // inspect [[Class]] -    var isObj = isObject(value); -    if (isObj) { -      var className = toString.call(value); -      if (!cloneableClasses[className] || (noNodeClass && isNode(value))) { -        return value; -      } -      var isArr = isArray(value); -    } -    // shallow clone -    if (!isObj || !deep) { -      return isObj -        ? (isArr ? slice(value) : assign({}, value)) -        : value; -    } -    var ctor = ctorByClass[className]; -    switch (className) { -      case boolClass: -      case dateClass: -        return new ctor(+value); - -      case numberClass: -      case stringClass: -        return new ctor(value); - -      case regexpClass: -        return ctor(value.source, reFlags.exec(value)); -    } -    // check for circular references and return corresponding clone -    stackA || (stackA = []); -    stackB || (stackB = []); - -    var length = stackA.length; -    while (length--) { -      if (stackA[length] == value) { -        return stackB[length]; -      } -    } -    // init cloned object -    var result = isArr ? ctor(value.length) : {}; - -    // add the source value to the stack of traversed objects -    // and associate it with its clone -    stackA.push(value); -    stackB.push(result); - -    // recursively populate clone (susceptible to call stack limits) -    (isArr ? forEach : forOwn)(value, function(objValue, key) { -      result[key] = clone(objValue, deep, null, stackA, stackB); -    }); - -    // add array properties assigned by `RegExp#exec` -    if (isArr) { -      if (hasOwnProperty.call(value, 'index')) { -        result.index = value.index; -      } -      if (hasOwnProperty.call(value, 'input')) { -        result.input = value.input; -      } -    } -    return result; -  } - -  /** -   * Creates a deep clone of `value`. Functions and DOM nodes are **not** cloned. -   * The enumerable properties of `arguments` objects and objects created by -   * constructors other than `Object` are cloned to plain `Object` objects. -   * -   * Note: This function is loosely based on the structured clone algorithm. -   * See http://www.w3.org/TR/html5/common-dom-interfaces.html#internal-structured-cloning-algorithm. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to deep clone. -   * @returns {Mixed} Returns the deep cloned `value`. -   * @example -   * -   * var stooges = [ -   *   { 'name': 'moe', 'age': 40 }, -   *   { 'name': 'larry', 'age': 50 }, -   *   { 'name': 'curly', 'age': 60 } -   * ]; -   * -   * var deep = _.cloneDeep(stooges); -   * deep[0] === stooges[0]; -   * // => false -   */ -  function cloneDeep(value) { -    return clone(value, true); -  } - -  /** -   * Assigns own enumerable properties of source object(s) to the `destination` -   * object for all `destination` properties that resolve to `null`/`undefined`. -   * Once a property is set, additional defaults of the same property will be -   * ignored. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Object} object The destination object. -   * @param {Object} [default1, default2, ...] The default objects. -   * @returns {Object} Returns the destination object. -   * @example -   * -   * var iceCream = { 'flavor': 'chocolate' }; -   * _.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'rainbow' }); -   * // => { 'flavor': 'chocolate', 'sprinkles': 'rainbow' } -   */ -  var defaults = createIterator(assignIteratorOptions, { -    'objectLoop': 'if (result[index] == null) ' + assignIteratorOptions.objectLoop -  }); - -  /** -   * Creates a sorted array of all enumerable properties, own and inherited, -   * of `object` that have function values. -   * -   * @static -   * @memberOf _ -   * @alias methods -   * @category Objects -   * @param {Object} object The object to inspect. -   * @returns {Array} Returns a new array of property names that have function values. -   * @example -   * -   * _.functions(_); -   * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...] -   */ -  function functions(object) { -    var result = []; -    forIn(object, function(value, key) { -      if (isFunction(value)) { -        result.push(key); -      } -    }); -    return result.sort(); -  } - -  /** -   * Checks if the specified object `property` exists and is a direct property, -   * instead of an inherited property. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Object} object The object to check. -   * @param {String} property The property to check for. -   * @returns {Boolean} Returns `true` if key is a direct property, else `false`. -   * @example -   * -   * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b'); -   * // => true -   */ -  function has(object, property) { -    return object ? hasOwnProperty.call(object, property) : false; -  } - -  /** -   * Creates an object composed of the inverted keys and values of the given `object`. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Object} object The object to invert. -   * @returns {Object} Returns the created inverted object. -   * @example -   * -   *  _.invert({ 'first': 'Moe', 'second': 'Larry', 'third': 'Curly' }); -   * // => { 'Moe': 'first', 'Larry': 'second', 'Curly': 'third' } (order is not guaranteed) -   */ -  function invert(object) { -    var result = {}; -    forOwn(object, function(value, key) { -      result[value] = key; -    }); -    return result; -  } - -  /** -   * Checks if `value` is an array. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is an array, else `false`. -   * @example -   * -   * (function() { return _.isArray(arguments); })(); -   * // => false -   * -   * _.isArray([1, 2, 3]); -   * // => true -   */ -  var isArray = nativeIsArray || function(value) { -    // `instanceof` may cause a memory leak in IE 7 if `value` is a host object -    // http://ajaxian.com/archives/working-aroung-the-instanceof-memory-leak -    return (argsAreObjects && value instanceof Array) || toString.call(value) == arrayClass; -  }; - -  /** -   * Checks if `value` is a boolean (`true` or `false`) value. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is a boolean value, else `false`. -   * @example -   * -   * _.isBoolean(null); -   * // => false -   */ -  function isBoolean(value) { -    return value === true || value === false || toString.call(value) == boolClass; -  } - -  /** -   * Checks if `value` is a date. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is a date, else `false`. -   * @example -   * -   * _.isDate(new Date); -   * // => true -   */ -  function isDate(value) { -    return value instanceof Date || toString.call(value) == dateClass; -  } - -  /** -   * Checks if `value` is a DOM element. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is a DOM element, else `false`. -   * @example -   * -   * _.isElement(document.body); -   * // => true -   */ -  function isElement(value) { -    return value ? value.nodeType === 1 : false; -  } - -  /** -   * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a -   * length of `0` and objects with no own enumerable properties are considered -   * "empty". -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Array|Object|String} value The value to inspect. -   * @returns {Boolean} Returns `true` if the `value` is empty, else `false`. -   * @example -   * -   * _.isEmpty([1, 2, 3]); -   * // => false -   * -   * _.isEmpty({}); -   * // => true -   * -   * _.isEmpty(''); -   * // => true -   */ -  function isEmpty(value) { -    var result = true; -    if (!value) { -      return result; -    } -    var className = toString.call(value), -        length = value.length; - -    if ((className == arrayClass || className == stringClass || -        className == argsClass || (noArgsClass && isArguments(value))) || -        (className == objectClass && typeof length == 'number' && isFunction(value.splice))) { -      return !length; -    } -    forOwn(value, function() { -      return (result = false); -    }); -    return result; -  } - -  /** -   * Performs a deep comparison between two values to determine if they are -   * equivalent to each other. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} a The value to compare. -   * @param {Mixed} b The other value to compare. -   * @param- {Object} [stackA=[]] Internally used track traversed `a` objects. -   * @param- {Object} [stackB=[]] Internally used track traversed `b` objects. -   * @returns {Boolean} Returns `true` if the values are equvalent, else `false`. -   * @example -   * -   * var moe = { 'name': 'moe', 'luckyNumbers': [13, 27, 34] }; -   * var clone = { 'name': 'moe', 'luckyNumbers': [13, 27, 34] }; -   * -   * moe == clone; -   * // => false -   * -   * _.isEqual(moe, clone); -   * // => true -   */ -  function isEqual(a, b, stackA, stackB) { -    // exit early for identical values -    if (a === b) { -      // treat `+0` vs. `-0` as not equal -      return a !== 0 || (1 / a == 1 / b); -    } -    // a strict comparison is necessary because `null == undefined` -    if (a == null || b == null) { -      return a === b; -    } -    // compare [[Class]] names -    var className = toString.call(a), -        otherName = toString.call(b); - -    if (className == argsClass) { -      className = objectClass; -    } -    if (otherName == argsClass) { -      otherName = objectClass; -    } -    if (className != otherName) { -      return false; -    } -    switch (className) { -      case boolClass: -      case dateClass: -        // 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 +a == +b; - -      case numberClass: -        // treat `NaN` vs. `NaN` as equal -        return a != +a -          ? b != +b -          // but treat `+0` vs. `-0` as not equal -          : (a == 0 ? (1 / a == 1 / b) : a == +b); - -      case regexpClass: -      case stringClass: -        // coerce regexes to strings (http://es5.github.com/#x15.10.6.4) -        // treat string primitives and their corresponding object instances as equal -        return a == b + ''; -    } -    var isArr = className == arrayClass; -    if (!isArr) { -      // unwrap any `lodash` wrapped values -      if (a.__wrapped__ || b.__wrapped__) { -        return isEqual(a.__wrapped__ || a, b.__wrapped__ || b); -      } -      // exit for functions and DOM nodes -      if (className != objectClass || (noNodeClass && (isNode(a) || isNode(b)))) { -        return false; -      } -      // in older versions of Opera, `arguments` objects have `Array` constructors -      var ctorA = !argsAreObjects && isArguments(a) ? Object : a.constructor, -          ctorB = !argsAreObjects && isArguments(b) ? Object : b.constructor; - -      // non `Object` object instances with different constructors are not equal -      if (ctorA != ctorB && !( -            isFunction(ctorA) && ctorA instanceof ctorA && -            isFunction(ctorB) && ctorB instanceof ctorB -          )) { -        return false; -      } -    } -    // assume cyclic structures are equal -    // the algorithm for detecting cyclic structures is adapted from ES 5.1 -    // section 15.12.3, abstract operation `JO` (http://es5.github.com/#x15.12.3) -    stackA || (stackA = []); -    stackB || (stackB = []); - -    var length = stackA.length; -    while (length--) { -      if (stackA[length] == a) { -        return stackB[length] == b; -      } -    } -    var index = -1, -        result = true, -        size = 0; - -    // add `a` and `b` to the stack of traversed objects -    stackA.push(a); -    stackB.push(b); - -    // recursively compare objects and arrays (susceptible to call stack limits) -    if (isArr) { -      // compare lengths to determine if a deep comparison is necessary -      size = a.length; -      result = size == b.length; - -      if (result) { -        // deep compare the contents, ignoring non-numeric properties -        while (size--) { -          if (!(result = isEqual(a[size], b[size], stackA, stackB))) { -            break; -          } -        } -      } -      return result; -    } -    // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys` -    // which, in this case, is more costly -    forIn(a, function(value, key, a) { -      if (hasOwnProperty.call(a, key)) { -        // count the number of properties. -        size++; -        // deep compare each property value. -        return (result = hasOwnProperty.call(b, key) && isEqual(value, b[key], stackA, stackB)); -      } -    }); - -    if (result) { -      // ensure both objects have the same number of properties -      forIn(b, function(value, key, b) { -        if (hasOwnProperty.call(b, key)) { -          // `size` will be `-1` if `b` has more properties than `a` -          return (result = --size > -1); -        } -      }); -    } -    return result; -  } - -  /** -   * Checks if `value` is, or can be coerced to, a finite number. -   * -   * Note: This is not the same as native `isFinite`, which will return true for -   * booleans and empty strings. See http://es5.github.com/#x15.1.2.5. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is a finite number, else `false`. -   * @example -   * -   * _.isFinite(-101); -   * // => true -   * -   * _.isFinite('10'); -   * // => true -   * -   * _.isFinite(true); -   * // => false -   * -   * _.isFinite(''); -   * // => false -   * -   * _.isFinite(Infinity); -   * // => false -   */ -  function isFinite(value) { -    return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value)); -  } - -  /** -   * Checks if `value` is a function. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is a function, else `false`. -   * @example -   * -   * _.isFunction(_); -   * // => true -   */ -  function isFunction(value) { -    return typeof value == 'function'; -  } -  // fallback for older versions of Chrome and Safari -  if (isFunction(/x/)) { -    isFunction = function(value) { -      return value instanceof Function || toString.call(value) == funcClass; -    }; -  } - -  /** -   * Checks if `value` is the language type of Object. -   * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is an object, else `false`. -   * @example -   * -   * _.isObject({}); -   * // => true -   * -   * _.isObject([1, 2, 3]); -   * // => true -   * -   * _.isObject(1); -   * // => false -   */ -  function isObject(value) { -    // check if the value is the ECMAScript language type of Object -    // http://es5.github.com/#x8 -    // and avoid a V8 bug -    // http://code.google.com/p/v8/issues/detail?id=2291 -    return value ? objectTypes[typeof value] : false; -  } - -  /** -   * Checks if `value` is `NaN`. -   * -   * Note: This is not the same as native `isNaN`, which will return `true` for -   * `undefined` and other values. See http://es5.github.com/#x15.1.2.4. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is `NaN`, else `false`. -   * @example -   * -   * _.isNaN(NaN); -   * // => true -   * -   * _.isNaN(new Number(NaN)); -   * // => true -   * -   * isNaN(undefined); -   * // => true -   * -   * _.isNaN(undefined); -   * // => false -   */ -  function isNaN(value) { -    // `NaN` as a primitive is the only value that is not equal to itself -    // (perform the [[Class]] check first to avoid errors with some host objects in IE) -    return isNumber(value) && value != +value -  } - -  /** -   * Checks if `value` is `null`. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is `null`, else `false`. -   * @example -   * -   * _.isNull(null); -   * // => true -   * -   * _.isNull(undefined); -   * // => false -   */ -  function isNull(value) { -    return value === null; -  } - -  /** -   * Checks if `value` is a number. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is a number, else `false`. -   * @example -   * -   * _.isNumber(8.4 * 5); -   * // => true -   */ -  function isNumber(value) { -    return typeof value == 'number' || toString.call(value) == numberClass; -  } - -  /** -   * Checks if a given `value` is an object created by the `Object` constructor. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if `value` is a plain object, else `false`. -   * @example -   * -   * function Stooge(name, age) { -   *   this.name = name; -   *   this.age = age; -   * } -   * -   * _.isPlainObject(new Stooge('moe', 40)); -   * // => false -   * -   * _.isPlainObject([1, 2, 3]); -   * // => false -   * -   * _.isPlainObject({ 'name': 'moe', 'age': 40 }); -   * // => true -   */ -  var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) { -    if (!(value && typeof value == 'object')) { -      return false; -    } -    var valueOf = value.valueOf, -        objProto = typeof valueOf == 'function' && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto); - -    return objProto -      ? value == objProto || (getPrototypeOf(value) == objProto && !isArguments(value)) -      : shimIsPlainObject(value); -  }; - -  /** -   * Checks if `value` is a regular expression. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is a regular expression, else `false`. -   * @example -   * -   * _.isRegExp(/moe/); -   * // => true -   */ -  function isRegExp(value) { -    return value instanceof RegExp || toString.call(value) == regexpClass; -  } - -  /** -   * Checks if `value` is a string. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is a string, else `false`. -   * @example -   * -   * _.isString('moe'); -   * // => true -   */ -  function isString(value) { -    return typeof value == 'string' || toString.call(value) == stringClass; -  } - -  /** -   * Checks if `value` is `undefined`. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is `undefined`, else `false`. -   * @example -   * -   * _.isUndefined(void 0); -   * // => true -   */ -  function isUndefined(value) { -    return typeof value == 'undefined'; -  } - -  /** -   * Creates an array composed of the own enumerable property names of `object`. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Object} object The object to inspect. -   * @returns {Array} Returns a new array of property names. -   * @example -   * -   * _.keys({ 'one': 1, 'two': 2, 'three': 3 }); -   * // => ['one', 'two', 'three'] (order is not guaranteed) -   */ -  var keys = !nativeKeys ? shimKeys : function(object) { -    // avoid iterating over the `prototype` property -    return typeof object == 'function' && propertyIsEnumerable.call(object, 'prototype') -      ? shimKeys(object) -      : (isObject(object) ? nativeKeys(object) : []); -  }; - -  /** -   * Merges enumerable properties of the source object(s) into the `destination` -   * object. Subsequent sources will overwrite propery assignments of previous -   * sources. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Object} object The destination object. -   * @param {Object} [source1, source2, ...] The source objects. -   * @param- {Object} [indicator] Internally used to indicate that the `stack` -   *  argument is an array of traversed objects instead of another source object. -   * @param- {Array} [stackA=[]] Internally used to track traversed source objects. -   * @param- {Array} [stackB=[]] Internally used to associate values with their -   *  source counterparts. -   * @returns {Object} Returns the destination object. -   * @example -   * -   * var stooges = [ -   *   { 'name': 'moe' }, -   *   { 'name': 'larry' } -   * ]; -   * -   * var ages = [ -   *   { 'age': 40 }, -   *   { 'age': 50 } -   * ]; -   * -   * _.merge(stooges, ages); -   * // => [{ 'name': 'moe', 'age': 40 }, { 'name': 'larry', 'age': 50 }] -   */ -  function merge(object, source, indicator) { -    var args = arguments, -        index = 0, -        length = 2, -        stackA = args[3], -        stackB = args[4]; - -    if (indicator !== indicatorObject) { -      stackA = []; -      stackB = []; - -      // work with `_.reduce` by only using its callback `accumulator` and `value` arguments -      if (typeof indicator != 'number') { -        length = args.length; -      } -    } -    while (++index < length) { -      forOwn(args[index], function(source, key) { -        var found, isArr, value; -        if (source && ((isArr = isArray(source)) || isPlainObject(source))) { -          // avoid merging previously merged cyclic sources -          var stackLength = stackA.length; -          while (stackLength--) { -            found = stackA[stackLength] == source; -            if (found) { -              break; -            } -          } -          if (found) { -            object[key] = stackB[stackLength]; -          } -          else { -            // add `source` and associated `value` to the stack of traversed objects -            stackA.push(source); -            stackB.push(value = (value = object[key], isArr) -              ? (isArray(value) ? value : []) -              : (isPlainObject(value) ? value : {}) -            ); -            // recursively merge objects and arrays (susceptible to call stack limits) -            object[key] = merge(value, source, indicatorObject, stackA, stackB); -          } -        } else if (source != null) { -          object[key] = source; -        } -      }); -    } -    return object; -  } - -  /** -   * Creates a shallow clone of `object` excluding the specified properties. -   * Property names may be specified as individual arguments or as arrays of -   * property names. If `callback` is passed, it will be executed for each property -   * in the `object`, omitting the properties `callback` returns truthy for. The -   * `callback` is bound to `thisArg` and invoked with three arguments; (value, key, object). -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Object} object The source object. -   * @param {Function|String} callback|[prop1, prop2, ...] The properties to omit -   *  or the function called per iteration. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Object} Returns an object without the omitted properties. -   * @example -   * -   * _.omit({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'userid'); -   * // => { 'name': 'moe', 'age': 40 } -   * -   * _.omit({ 'name': 'moe', '_hint': 'knucklehead', '_seed': '96c4eb' }, function(value, key) { -   *   return key.charAt(0) == '_'; -   * }); -   * // => { 'name': 'moe' } -   */ -  function omit(object, callback, thisArg) { -    var isFunc = typeof callback == 'function', -        result = {}; - -    if (isFunc) { -      callback = createCallback(callback, thisArg); -    } else { -      var props = concat.apply(arrayRef, arguments); -    } -    forIn(object, function(value, key, object) { -      if (isFunc -            ? !callback(value, key, object) -            : indexOf(props, key, 1) < 0 -          ) { -        result[key] = value; -      } -    }); -    return result; -  } - -  /** -   * Creates a two dimensional array of the given object's key-value pairs, -   * i.e. `[[key1, value1], [key2, value2]]`. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Object} object The object to inspect. -   * @returns {Array} Returns new array of key-value pairs. -   * @example -   * -   * _.pairs({ 'moe': 30, 'larry': 40, 'curly': 50 }); -   * // => [['moe', 30], ['larry', 40], ['curly', 50]] (order is not guaranteed) -   */ -  function pairs(object) { -    var result = []; -    forOwn(object, function(value, key) { -      result.push([key, value]); -    }); -    return result; -  } - -  /** -   * Creates a shallow clone of `object` composed of the specified properties. -   * Property names may be specified as individual arguments or as arrays of -   * property names. If `callback` is passed, it will be executed for each property -   * in the `object`, picking the properties `callback` returns truthy for. The -   * `callback` is bound to `thisArg` and invoked with three arguments; (value, key, object). -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Object} object The source object. -   * @param {Function|String} callback|[prop1, prop2, ...] The properties to pick -   *  or the function called per iteration. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Object} Returns an object composed of the picked properties. -   * @example -   * -   * _.pick({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'name', 'age'); -   * // => { 'name': 'moe', 'age': 40 } -   * -   * _.pick({ 'name': 'moe', '_hint': 'knucklehead', '_seed': '96c4eb' }, function(value, key) { -   *   return key.charAt(0) != '_'; -   * }); -   * // => { 'name': 'moe' } -   */ -  function pick(object, callback, thisArg) { -    var result = {}; -    if (typeof callback != 'function') { -      var index = 0, -          props = concat.apply(arrayRef, arguments), -          length = props.length; - -      while (++index < length) { -        var key = props[index]; -        if (key in object) { -          result[key] = object[key]; -        } -      } -    } else { -      callback = createCallback(callback, thisArg); -      forIn(object, function(value, key, object) { -        if (callback(value, key, object)) { -          result[key] = value; -        } -      }); -    } -    return result; -  } - -  /** -   * Creates an array composed of the own enumerable property values of `object`. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Object} object The object to inspect. -   * @returns {Array} Returns a new array of property values. -   * @example -   * -   * _.values({ 'one': 1, 'two': 2, 'three': 3 }); -   * // => [1, 2, 3] -   */ -  function values(object) { -    var result = []; -    forOwn(object, function(value) { -      result.push(value); -    }); -    return result; -  } - -  /*--------------------------------------------------------------------------*/ - -  /** -   * Checks if a given `target` element is present in a `collection` using strict -   * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used -   * as the offset from the end of the collection. -   * -   * @static -   * @memberOf _ -   * @alias include -   * @category Collections -   * @param {Array|Object|String} collection The collection to iterate over. -   * @param {Mixed} target The value to check for. -   * @param {Number} [fromIndex=0] The index to search from. -   * @returns {Boolean} Returns `true` if the `target` element is found, else `false`. -   * @example -   * -   * _.contains([1, 2, 3], 1); -   * // => true -   * -   * _.contains([1, 2, 3], 1, 2); -   * // => false -   * -   * _.contains({ 'name': 'moe', 'age': 40 }, 'moe'); -   * // => true -   * -   * _.contains('curly', 'ur'); -   * // => true -   */ -  function contains(collection, target, fromIndex) { -    var index = -1, -        length = collection ? collection.length : 0, -        result = false; - -    fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0; -    if (typeof length == 'number') { -      result = (isString(collection) -        ? collection.indexOf(target, fromIndex) -        : indexOf(collection, target, fromIndex) -      ) > -1; -    } else { -      each(collection, function(value) { -        if (++index >= fromIndex) { -          return !(result = value === target); -        } -      }); -    } -    return result; -  } - -  /** -   * Creates an object composed of keys returned from running each element of -   * `collection` through a `callback`. The corresponding value of each key is -   * the number of times the key was returned by `callback`. The `callback` is -   * bound to `thisArg` and invoked with three arguments; (value, index|key, collection). -   * The `callback` argument may also be the name of a property to count by (e.g. 'length'). -   * -   * @static -   * @memberOf _ -   * @category Collections -   * @param {Array|Object|String} collection The collection to iterate over. -   * @param {Function|String} callback|property The function called per iteration -   *  or property name to count by. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Object} Returns the composed aggregate object. -   * @example -   * -   * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); }); -   * // => { '4': 1, '6': 2 } -   * -   * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math); -   * // => { '4': 1, '6': 2 } -   * -   * _.countBy(['one', 'two', 'three'], 'length'); -   * // => { '3': 2, '5': 1 } -   */ -  function countBy(collection, callback, thisArg) { -    var result = {}; -    callback = createCallback(callback, thisArg); - -    forEach(collection, function(value, key, collection) { -      key = callback(value, key, collection); -      (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1); -    }); -    return result; -  } - -  /** -   * Checks if the `callback` returns a truthy value for **all** elements of a -   * `collection`. The `callback` is bound to `thisArg` and invoked with three -   * arguments; (value, index|key, collection). -   * -   * @static -   * @memberOf _ -   * @alias all -   * @category Collections -   * @param {Array|Object|String} collection The collection to iterate over. -   * @param {Function} [callback=identity] The function called per iteration. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Boolean} Returns `true` if all elements pass the callback check, -   *  else `false`. -   * @example -   * -   * _.every([true, 1, null, 'yes'], Boolean); -   * // => false -   */ -  function every(collection, callback, thisArg) { -    var result = true; -    callback = createCallback(callback, thisArg); - -    if (isArray(collection)) { -      var index = -1, -          length = collection.length; - -      while (++index < length) { -        if (!(result = !!callback(collection[index], index, collection))) { -          break; -        } -      } -    } else { -      each(collection, function(value, index, collection) { -        return (result = !!callback(value, index, collection)); -      }); -    } -    return result; -  } - -  /** -   * Examines each element in a `collection`, returning an array of all elements -   * the `callback` returns truthy for. The `callback` is bound to `thisArg` and -   * invoked with three arguments; (value, index|key, collection). -   * -   * @static -   * @memberOf _ -   * @alias select -   * @category Collections -   * @param {Array|Object|String} collection The collection to iterate over. -   * @param {Function} [callback=identity] The function called per iteration. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Array} Returns a new array of elements that passed the callback check. -   * @example -   * -   * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); -   * // => [2, 4, 6] -   */ -  function filter(collection, callback, thisArg) { -    var result = []; -    callback = createCallback(callback, thisArg); - -    if (isArray(collection)) { -      var index = -1, -          length = collection.length; - -      while (++index < length) { -        var value = collection[index]; -        if (callback(value, index, collection)) { -          result.push(value); -        } -      } -    } else { -      each(collection, function(value, index, collection) { -        if (callback(value, index, collection)) { -          result.push(value); -        } -      }); -    } -    return result; -  } - -  /** -   * Examines each element in a `collection`, returning the first one the `callback` -   * returns truthy for. The function returns as soon as it finds an acceptable -   * element, and does not iterate over the entire `collection`. The `callback` is -   * bound to `thisArg` and invoked with three arguments; (value, index|key, collection). -   * -   * @static -   * @memberOf _ -   * @alias detect -   * @category Collections -   * @param {Array|Object|String} collection The collection to iterate over. -   * @param {Function} [callback=identity] The function called per iteration. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Mixed} Returns the element that passed the callback check, -   *  else `undefined`. -   * @example -   * -   * var even = _.find([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); -   * // => 2 -   */ -  function find(collection, callback, thisArg) { -    var result; -    callback = createCallback(callback, thisArg); - -    forEach(collection, function(value, index, collection) { -      if (callback(value, index, collection)) { -        result = value; -        return false; -      } -    }); -    return result; -  } - -  /** -   * Iterates over a `collection`, executing the `callback` for each element in -   * the `collection`. The `callback` is bound to `thisArg` and invoked with three -   * arguments; (value, index|key, collection). Callbacks may exit iteration early -   * by explicitly returning `false`. -   * -   * @static -   * @memberOf _ -   * @alias each -   * @category Collections -   * @param {Array|Object|String} collection The collection to iterate over. -   * @param {Function} [callback=identity] The function called per iteration. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Array|Object|String} Returns `collection`. -   * @example -   * -   * _([1, 2, 3]).forEach(alert).join(','); -   * // => alerts each number and returns '1,2,3' -   * -   * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, alert); -   * // => alerts each number value (order is not guaranteed) -   */ -  function forEach(collection, callback, thisArg) { -    if (callback && typeof thisArg == 'undefined' && isArray(collection)) { -      var index = -1, -          length = collection.length; - -      while (++index < length) { -        if (callback(collection[index], index, collection) === false) { -          break; -        } -      } -    } else { -      each(collection, callback, thisArg); -    } -    return collection; -  } - -  /** -   * Creates an object composed of keys returned from running each element of -   * `collection` through a `callback`. The corresponding value of each key is an -   * array of elements passed to `callback` that returned the key. The `callback` -   * is bound to `thisArg` and invoked with three arguments; (value, index|key, collection). -   * The `callback` argument may also be the name of a property to group by (e.g. 'length'). -   * -   * @static -   * @memberOf _ -   * @category Collections -   * @param {Array|Object|String} collection The collection to iterate over. -   * @param {Function|String} callback|property The function called per iteration -   *  or property name to group by. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Object} Returns the composed aggregate object. -   * @example -   * -   * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); }); -   * // => { '4': [4.2], '6': [6.1, 6.4] } -   * -   * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math); -   * // => { '4': [4.2], '6': [6.1, 6.4] } -   * -   * _.groupBy(['one', 'two', 'three'], 'length'); -   * // => { '3': ['one', 'two'], '5': ['three'] } -   */ -  function groupBy(collection, callback, thisArg) { -    var result = {}; -    callback = createCallback(callback, thisArg); - -    forEach(collection, function(value, key, collection) { -      key = callback(value, key, collection); -      (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value); -    }); -    return result; -  } - -  /** -   * Invokes the method named by `methodName` on each element in the `collection`, -   * returning an array of the results of each invoked method. Additional arguments -   * will be passed to each invoked method. If `methodName` is a function it will -   * be invoked for, and `this` bound to, each element in the `collection`. -   * -   * @static -   * @memberOf _ -   * @category Collections -   * @param {Array|Object|String} collection The collection to iterate over. -   * @param {Function|String} methodName The name of the method to invoke or -   *  the function invoked per iteration. -   * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with. -   * @returns {Array} Returns a new array of the results of each invoked method. -   * @example -   * -   * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); -   * // => [[1, 5, 7], [1, 2, 3]] -   * -   * _.invoke([123, 456], String.prototype.split, ''); -   * // => [['1', '2', '3'], ['4', '5', '6']] -   */ -  function invoke(collection, methodName) { -    var args = slice(arguments, 2), -        isFunc = typeof methodName == 'function', -        result = []; - -    forEach(collection, function(value) { -      result.push((isFunc ? methodName : value[methodName]).apply(value, args)); -    }); -    return result; -  } - -  /** -   * Creates an array of values by running each element in the `collection` -   * through a `callback`. The `callback` is bound to `thisArg` and invoked with -   * three arguments; (value, index|key, collection). -   * -   * @static -   * @memberOf _ -   * @alias collect -   * @category Collections -   * @param {Array|Object|String} collection The collection to iterate over. -   * @param {Function} [callback=identity] The function called per iteration. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Array} Returns a new array of the results of each `callback` execution. -   * @example -   * -   * _.map([1, 2, 3], function(num) { return num * 3; }); -   * // => [3, 6, 9] -   * -   * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; }); -   * // => [3, 6, 9] (order is not guaranteed) -   */ -  function map(collection, callback, thisArg) { -    var index = -1, -        length = collection ? collection.length : 0, -        result = Array(typeof length == 'number' ? length : 0); - -    callback = createCallback(callback, thisArg); -    if (isArray(collection)) { -      while (++index < length) { -        result[index] = callback(collection[index], index, collection); -      } -    } else { -      each(collection, function(value, key, collection) { -        result[++index] = callback(value, key, collection); -      }); -    } -    return result; -  } - -  /** -   * Retrieves the maximum value of an `array`. If `callback` is passed, -   * it will be executed for each value in the `array` to generate the -   * criterion by which the value is ranked. The `callback` is bound to -   * `thisArg` and invoked with three arguments; (value, index, collection). -   * -   * @static -   * @memberOf _ -   * @category Collections -   * @param {Array|Object|String} collection The collection to iterate over. -   * @param {Function} [callback] The function called per iteration. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Mixed} Returns the maximum value. -   * @example -   * -   * var stooges = [ -   *   { 'name': 'moe', 'age': 40 }, -   *   { 'name': 'larry', 'age': 50 }, -   *   { 'name': 'curly', 'age': 60 } -   * ]; -   * -   * _.max(stooges, function(stooge) { return stooge.age; }); -   * // => { 'name': 'curly', 'age': 60 }; -   */ -  function max(collection, callback, thisArg) { -    var computed = -Infinity, -        index = -1, -        length = collection ? collection.length : 0, -        result = computed; - -    if (callback || !isArray(collection)) { -      callback = !callback && isString(collection) -        ? charAtCallback -        : createCallback(callback, thisArg); - -      each(collection, function(value, index, collection) { -        var current = callback(value, index, collection); -        if (current > computed) { -          computed = current; -          result = value; -        } -      }); -    } else { -      while (++index < length) { -        if (collection[index] > result) { -          result = collection[index]; -        } -      } -    } -    return result; -  } - -  /** -   * Retrieves the minimum value of an `array`. If `callback` is passed, -   * it will be executed for each value in the `array` to generate the -   * criterion by which the value is ranked. The `callback` is bound to `thisArg` -   * and invoked with three arguments; (value, index, collection). -   * -   * @static -   * @memberOf _ -   * @category Collections -   * @param {Array|Object|String} collection The collection to iterate over. -   * @param {Function} [callback] The function called per iteration. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Mixed} Returns the minimum value. -   * @example -   * -   * _.min([10, 5, 100, 2, 1000]); -   * // => 2 -   */ -  function min(collection, callback, thisArg) { -    var computed = Infinity, -        index = -1, -        length = collection ? collection.length : 0, -        result = computed; - -    if (callback || !isArray(collection)) { -      callback = !callback && isString(collection) -        ? charAtCallback -        : createCallback(callback, thisArg); - -      each(collection, function(value, index, collection) { -        var current = callback(value, index, collection); -        if (current < computed) { -          computed = current; -          result = value; -        } -      }); -    } else { -      while (++index < length) { -        if (collection[index] < result) { -          result = collection[index]; -        } -      } -    } -    return result; -  } - -  /** -   * Retrieves the value of a specified property from all elements in -   * the `collection`. -   * -   * @static -   * @memberOf _ -   * @category Collections -   * @param {Array|Object|String} collection The collection to iterate over. -   * @param {String} property The property to pluck. -   * @returns {Array} Returns a new array of property values. -   * @example -   * -   * var stooges = [ -   *   { 'name': 'moe', 'age': 40 }, -   *   { 'name': 'larry', 'age': 50 }, -   *   { 'name': 'curly', 'age': 60 } -   * ]; -   * -   * _.pluck(stooges, 'name'); -   * // => ['moe', 'larry', 'curly'] -   */ -  function pluck(collection, property) { -    return map(collection, property + ''); -  } - -  /** -   * Boils down a `collection` to a single value. The initial state of the -   * reduction is `accumulator` and each successive step of it should be returned -   * by the `callback`. The `callback` is bound to `thisArg` and invoked with 4 -   * arguments; for arrays they are (accumulator, value, index|key, collection). -   * -   * @static -   * @memberOf _ -   * @alias foldl, inject -   * @category Collections -   * @param {Array|Object|String} collection The collection to iterate over. -   * @param {Function} [callback=identity] The function called per iteration. -   * @param {Mixed} [accumulator] Initial value of the accumulator. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Mixed} Returns the accumulated value. -   * @example -   * -   * var sum = _.reduce([1, 2, 3], function(memo, num) { return memo + num; }); -   * // => 6 -   */ -  function reduce(collection, callback, accumulator, thisArg) { -    var noaccum = arguments.length < 3; -    callback = createCallback(callback, thisArg, indicatorObject); - -    if (isArray(collection)) { -      var index = -1, -          length = collection.length; - -      if (noaccum) { -        accumulator = collection[++index]; -      } -      while (++index < length) { -        accumulator = callback(accumulator, collection[index], index, collection); -      } -    } else { -      each(collection, function(value, index, collection) { -        accumulator = noaccum -          ? (noaccum = false, value) -          : callback(accumulator, value, index, collection) -      }); -    } -    return accumulator; -  } - -  /** -   * The right-associative version of `_.reduce`. -   * -   * @static -   * @memberOf _ -   * @alias foldr -   * @category Collections -   * @param {Array|Object|String} collection The collection to iterate over. -   * @param {Function} [callback=identity] The function called per iteration. -   * @param {Mixed} [accumulator] Initial value of the accumulator. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Mixed} Returns the accumulated value. -   * @example -   * -   * var list = [[0, 1], [2, 3], [4, 5]]; -   * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []); -   * // => [4, 5, 2, 3, 0, 1] -   */ -  function reduceRight(collection, callback, accumulator, thisArg) { -    var iteratee = collection, -        length = collection ? collection.length : 0, -        noaccum = arguments.length < 3; - -    if (typeof length != 'number') { -      var props = keys(collection); -      length = props.length; -    } else if (noCharByIndex && isString(collection)) { -      iteratee = collection.split(''); -    } -    callback = createCallback(callback, thisArg, indicatorObject); -    forEach(collection, function(value, index, collection) { -      index = props ? props[--length] : --length; -      accumulator = noaccum -        ? (noaccum = false, iteratee[index]) -        : callback(accumulator, iteratee[index], index, collection); -    }); -    return accumulator; -  } - -  /** -   * The opposite of `_.filter`, this method returns the values of a -   * `collection` that `callback` does **not** return truthy for. -   * -   * @static -   * @memberOf _ -   * @category Collections -   * @param {Array|Object|String} collection The collection to iterate over. -   * @param {Function} [callback=identity] The function called per iteration. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Array} Returns a new array of elements that did **not** pass the -   *  callback check. -   * @example -   * -   * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); -   * // => [1, 3, 5] -   */ -  function reject(collection, callback, thisArg) { -    callback = createCallback(callback, thisArg); -    return filter(collection, function(value, index, collection) { -      return !callback(value, index, collection); -    }); -  } - -  /** -   * Creates an array of shuffled `array` values, using a version of the -   * Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle. -   * -   * @static -   * @memberOf _ -   * @category Collections -   * @param {Array|Object|String} collection The collection to shuffle. -   * @returns {Array} Returns a new shuffled collection. -   * @example -   * -   * _.shuffle([1, 2, 3, 4, 5, 6]); -   * // => [4, 1, 6, 3, 5, 2] -   */ -  function shuffle(collection) { -    var index = -1, -        result = Array(collection ? collection.length : 0); - -    forEach(collection, function(value) { -      var rand = floor(nativeRandom() * (++index + 1)); -      result[index] = result[rand]; -      result[rand] = value; -    }); -    return result; -  } - -  /** -   * Gets the size of the `collection` by returning `collection.length` for arrays -   * and array-like objects or the number of own enumerable properties for objects. -   * -   * @static -   * @memberOf _ -   * @category Collections -   * @param {Array|Object|String} collection The collection to inspect. -   * @returns {Number} Returns `collection.length` or number of own enumerable properties. -   * @example -   * -   * _.size([1, 2]); -   * // => 2 -   * -   * _.size({ 'one': 1, 'two': 2, 'three': 3 }); -   * // => 3 -   * -   * _.size('curly'); -   * // => 5 -   */ -  function size(collection) { -    var length = collection ? collection.length : 0; -    return typeof length == 'number' ? length : keys(collection).length; -  } - -  /** -   * Checks if the `callback` returns a truthy value for **any** element of a -   * `collection`. The function returns as soon as it finds passing value, and -   * does not iterate over the entire `collection`. The `callback` is bound to -   * `thisArg` and invoked with three arguments; (value, index|key, collection). -   * -   * @static -   * @memberOf _ -   * @alias any -   * @category Collections -   * @param {Array|Object|String} collection The collection to iterate over. -   * @param {Function} [callback=identity] The function called per iteration. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Boolean} Returns `true` if any element passes the callback check, -   *  else `false`. -   * @example -   * -   * _.some([null, 0, 'yes', false], Boolean); -   * // => true -   */ -  function some(collection, callback, thisArg) { -    var result; -    callback = createCallback(callback, thisArg); - -    if (isArray(collection)) { -      var index = -1, -          length = collection.length; - -      while (++index < length) { -        if ((result = callback(collection[index], index, collection))) { -          break; -        } -      } -    } else { -      each(collection, function(value, index, collection) { -        return !(result = callback(value, index, collection)); -      }); -    } -    return !!result; -  } - -  /** -   * Creates an array, stable sorted in ascending order by the results of -   * running each element of `collection` through a `callback`. The `callback` -   * is bound to `thisArg` and invoked with three arguments; (value, index|key, collection). -   * The `callback` argument may also be the name of a property to sort by (e.g. 'length'). -   * -   * @static -   * @memberOf _ -   * @category Collections -   * @param {Array|Object|String} collection The collection to iterate over. -   * @param {Function|String} callback|property The function called per iteration -   *  or property name to sort by. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Array} Returns a new array of sorted elements. -   * @example -   * -   * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); }); -   * // => [3, 1, 2] -   * -   * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math); -   * // => [3, 1, 2] -   * -   * _.sortBy(['larry', 'brendan', 'moe'], 'length'); -   * // => ['moe', 'larry', 'brendan'] -   */ -  function sortBy(collection, callback, thisArg) { -    var result = []; -    callback = createCallback(callback, thisArg); - -    forEach(collection, function(value, index, collection) { -      result.push({ -        'criteria': callback(value, index, collection), -        'index': index, -        'value': value -      }); -    }); - -    var length = result.length; -    result.sort(compareAscending); -    while (length--) { -      result[length] = result[length].value; -    } -    return result; -  } - -  /** -   * Converts the `collection` to an array. -   * -   * @static -   * @memberOf _ -   * @category Collections -   * @param {Array|Object|String} collection The collection to convert. -   * @returns {Array} Returns the new converted array. -   * @example -   * -   * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4); -   * // => [2, 3, 4] -   */ -  function toArray(collection) { -    var length = collection ? collection.length : 0; -    if (typeof length == 'number') { -      return noCharByIndex && isString(collection) -        ? collection.split('') -        : slice(collection); -    } -    return values(collection); -  } - -  /** -   * Examines each element in a `collection`, returning an array of all elements -   * that contain the given `properties`. -   * -   * @static -   * @memberOf _ -   * @category Collections -   * @param {Array|Object|String} collection The collection to iterate over. -   * @param {Object} properties The object of property values to filter by. -   * @returns {Array} Returns a new array of elements that contain the given `properties`. -   * @example -   * -   * var stooges = [ -   *   { 'name': 'moe', 'age': 40 }, -   *   { 'name': 'larry', 'age': 50 }, -   *   { 'name': 'curly', 'age': 60 } -   * ]; -   * -   * _.where(stooges, { 'age': 40 }); -   * // => [{ 'name': 'moe', 'age': 40 }] -   */ -  function where(collection, properties) { -    var props = keys(properties); -    return filter(collection, function(object) { -      var length = props.length; -      while (length--) { -        var result = object[props[length]] === properties[props[length]]; -        if (!result) { -          break; -        } -      } -      return !!result; -    }); -  } - -  /*--------------------------------------------------------------------------*/ - -  /** -   * Creates an array with all falsey values of `array` removed. The values -   * `false`, `null`, `0`, `""`, `undefined` and `NaN` are all falsey. -   * -   * @static -   * @memberOf _ -   * @category Arrays -   * @param {Array} array The array to compact. -   * @returns {Array} Returns a new filtered array. -   * @example -   * -   * _.compact([0, 1, false, 2, '', 3]); -   * // => [1, 2, 3] -   */ -  function compact(array) { -    var index = -1, -        length = array ? array.length : 0, -        result = []; - -    while (++index < length) { -      var value = array[index]; -      if (value) { -        result.push(value); -      } -    } -    return result; -  } - -  /** -   * Creates an array of `array` elements not present in the other arrays -   * using strict equality for comparisons, i.e. `===`. -   * -   * @static -   * @memberOf _ -   * @category Arrays -   * @param {Array} array The array to process. -   * @param {Array} [array1, array2, ...] Arrays to check. -   * @returns {Array} Returns a new array of `array` elements not present in the -   *  other arrays. -   * @example -   * -   * _.difference([1, 2, 3, 4, 5], [5, 2, 10]); -   * // => [1, 3, 4] -   */ -  function difference(array) { -    var index = -1, -        length = array ? array.length : 0, -        flattened = concat.apply(arrayRef, arguments), -        contains = cachedContains(flattened, length), -        result = []; - -    while (++index < length) { -      var value = array[index]; -      if (!contains(value)) { -        result.push(value); -      } -    } -    return result; -  } - -  /** -   * Gets the first element of the `array`. Pass `n` to return the first `n` -   * elements of the `array`. -   * -   * @static -   * @memberOf _ -   * @alias head, take -   * @category Arrays -   * @param {Array} array The array to query. -   * @param {Number} [n] The number of elements to return. -   * @param- {Object} [guard] Internally used to allow this method to work with -   *  others like `_.map` without using their callback `index` argument for `n`. -   * @returns {Mixed} Returns the first element, or an array of the first `n` -   *  elements, of `array`. -   * @example -   * -   * _.first([5, 4, 3, 2, 1]); -   * // => 5 -   */ -  function first(array, n, guard) { -    if (array) { -      var length = array.length; -      return (n == null || guard) -        ? array[0] -        : slice(array, 0, nativeMin(nativeMax(0, n), length)); -    } -  } - -  /** -   * Flattens a nested array (the nesting can be to any depth). If `shallow` is -   * truthy, `array` will only be flattened a single level. -   * -   * @static -   * @memberOf _ -   * @category Arrays -   * @param {Array} array The array to compact. -   * @param {Boolean} shallow A flag to indicate only flattening a single level. -   * @returns {Array} Returns a new flattened array. -   * @example -   * -   * _.flatten([1, [2], [3, [[4]]]]); -   * // => [1, 2, 3, 4]; -   * -   * _.flatten([1, [2], [3, [[4]]]], true); -   * // => [1, 2, 3, [[4]]]; -   */ -  function flatten(array, shallow) { -    var index = -1, -        length = array ? array.length : 0, -        result = []; - -    while (++index < length) { -      var value = array[index]; - -      // recursively flatten arrays (susceptible to call stack limits) -      if (isArray(value)) { -        push.apply(result, shallow ? value : flatten(value)); -      } else { -        result.push(value); -      } -    } -    return result; -  } - -  /** -   * Gets the index at which the first occurrence of `value` is found using -   * strict equality for comparisons, i.e. `===`. If the `array` is already -   * sorted, passing `true` for `fromIndex` will run a faster binary search. -   * -   * @static -   * @memberOf _ -   * @category Arrays -   * @param {Array} array The array to search. -   * @param {Mixed} value The value to search for. -   * @param {Boolean|Number} [fromIndex=0] The index to search from or `true` to -   *  perform a binary search on a sorted `array`. -   * @returns {Number} Returns the index of the matched value or `-1`. -   * @example -   * -   * _.indexOf([1, 2, 3, 1, 2, 3], 2); -   * // => 1 -   * -   * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3); -   * // => 4 -   * -   * _.indexOf([1, 1, 2, 2, 3, 3], 2, true); -   * // => 2 -   */ -  function indexOf(array, value, fromIndex) { -    var index = -1, -        length = array ? array.length : 0; - -    if (typeof fromIndex == 'number') { -      index = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0) - 1; -    } else if (fromIndex) { -      index = sortedIndex(array, value); -      return array[index] === value ? index : -1; -    } -    while (++index < length) { -      if (array[index] === value) { -        return index; -      } -    } -    return -1; -  } - -  /** -   * Gets all but the last element of `array`. Pass `n` to exclude the last `n` -   * elements from the result. -   * -   * @static -   * @memberOf _ -   * @category Arrays -   * @param {Array} array The array to query. -   * @param {Number} [n=1] The number of elements to exclude. -   * @param- {Object} [guard] Internally used to allow this method to work with -   *  others like `_.map` without using their callback `index` argument for `n`. -   * @returns {Array} Returns all but the last element, or `n` elements, of `array`. -   * @example -   * -   * _.initial([3, 2, 1]); -   * // => [3, 2] -   */ -  function initial(array, n, guard) { -    if (!array) { -      return []; -    } -    var length = array.length; -    n = n == null || guard ? 1 : n || 0; -    return slice(array, 0, nativeMin(nativeMax(0, length - n), length)); -  } - -  /** -   * Computes the intersection of all the passed-in arrays using strict equality -   * for comparisons, i.e. `===`. -   * -   * @static -   * @memberOf _ -   * @category Arrays -   * @param {Array} [array1, array2, ...] Arrays to process. -   * @returns {Array} Returns a new array of unique elements that are present -   *  in **all** of the arrays. -   * @example -   * -   * _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]); -   * // => [1, 2] -   */ -  function intersection(array) { -    var args = arguments, -        argsLength = args.length, -        cache = { '0': {} }, -        index = -1, -        length = array ? array.length : 0, -        isLarge = length >= 100, -        result = [], -        seen = result; - -    outer: -    while (++index < length) { -      var value = array[index]; -      if (isLarge) { -        var key = value + ''; -        var inited = hasOwnProperty.call(cache[0], key) -          ? !(seen = cache[0][key]) -          : (seen = cache[0][key] = []); -      } -      if (inited || indexOf(seen, value) < 0) { -        if (isLarge) { -          seen.push(value); -        } -        var argsIndex = argsLength; -        while (--argsIndex) { -          if (!(cache[argsIndex] || (cache[argsIndex] = cachedContains(args[argsIndex], 0, 100)))(value)) { -            continue outer; -          } -        } -        result.push(value); -      } -    } -    return result; -  } - -  /** -   * Gets the last element of the `array`. Pass `n` to return the last `n` -   * elements of the `array`. -   * -   * @static -   * @memberOf _ -   * @category Arrays -   * @param {Array} array The array to query. -   * @param {Number} [n] The number of elements to return. -   * @param- {Object} [guard] Internally used to allow this method to work with -   *  others like `_.map` without using their callback `index` argument for `n`. -   * @returns {Mixed} Returns the last element, or an array of the last `n` -   *  elements, of `array`. -   * @example -   * -   * _.last([3, 2, 1]); -   * // => 1 -   */ -  function last(array, n, guard) { -    if (array) { -      var length = array.length; -      return (n == null || guard) ? array[length - 1] : slice(array, nativeMax(0, length - n)); -    } -  } - -  /** -   * Gets the index at which the last occurrence of `value` is found using strict -   * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used -   * as the offset from the end of the collection. -   * -   * @static -   * @memberOf _ -   * @category Arrays -   * @param {Array} array The array to search. -   * @param {Mixed} value The value to search for. -   * @param {Number} [fromIndex=array.length-1] The index to search from. -   * @returns {Number} Returns the index of the matched value or `-1`. -   * @example -   * -   * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2); -   * // => 4 -   * -   * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3); -   * // => 1 -   */ -  function lastIndexOf(array, value, fromIndex) { -    var index = array ? array.length : 0; -    if (typeof fromIndex == 'number') { -      index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1; -    } -    while (index--) { -      if (array[index] === value) { -        return index; -      } -    } -    return -1; -  } - -  /** -   * Creates an object composed from arrays of `keys` and `values`. Pass either -   * a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`, or -   * two arrays, one of `keys` and one of corresponding `values`. -   * -   * @static -   * @memberOf _ -   * @category Arrays -   * @param {Array} keys The array of keys. -   * @param {Array} [values=[]] The array of values. -   * @returns {Object} Returns an object composed of the given keys and -   *  corresponding values. -   * @example -   * -   * _.object(['moe', 'larry', 'curly'], [30, 40, 50]); -   * // => { 'moe': 30, 'larry': 40, 'curly': 50 } -   */ -  function object(keys, values) { -    var index = -1, -        length = keys ? keys.length : 0, -        result = {}; - -    while (++index < length) { -      var key = keys[index]; -      if (values) { -        result[key] = values[index]; -      } else { -        result[key[0]] = key[1]; -      } -    } -    return result; -  } - -  /** -   * Creates an array of numbers (positive and/or negative) progressing from -   * `start` up to but not including `stop`. This method is a port of Python's -   * `range()` function. See http://docs.python.org/library/functions.html#range. -   * -   * @static -   * @memberOf _ -   * @category Arrays -   * @param {Number} [start=0] The start of the range. -   * @param {Number} end The end of the range. -   * @param {Number} [step=1] The value to increment or descrement by. -   * @returns {Array} Returns a new range array. -   * @example -   * -   * _.range(10); -   * // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] -   * -   * _.range(1, 11); -   * // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] -   * -   * _.range(0, 30, 5); -   * // => [0, 5, 10, 15, 20, 25] -   * -   * _.range(0, -10, -1); -   * // => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] -   * -   * _.range(0); -   * // => [] -   */ -  function range(start, end, step) { -    start = +start || 0; -    step = +step || 1; - -    if (end == null) { -      end = start; -      start = 0; -    } -    // use `Array(length)` so V8 will avoid the slower "dictionary" mode -    // http://youtu.be/XAqIpGU8ZZk#t=17m25s -    var index = -1, -        length = nativeMax(0, ceil((end - start) / step)), -        result = Array(length); - -    while (++index < length) { -      result[index] = start; -      start += step; -    } -    return result; -  } - -  /** -   * The opposite of `_.initial`, this method gets all but the first value of -   * `array`. Pass `n` to exclude the first `n` values from the result. -   * -   * @static -   * @memberOf _ -   * @alias drop, tail -   * @category Arrays -   * @param {Array} array The array to query. -   * @param {Number} [n=1] The number of elements to exclude. -   * @param- {Object} [guard] Internally used to allow this method to work with -   *  others like `_.map` without using their callback `index` argument for `n`. -   * @returns {Array} Returns all but the first element, or `n` elements, of `array`. -   * @example -   * -   * _.rest([3, 2, 1]); -   * // => [2, 1] -   */ -  function rest(array, n, guard) { -    return slice(array, (n == null || guard) ? 1 : nativeMax(0, n)); -  } - -  /** -   * Uses a binary search to determine the smallest index at which the `value` -   * should be inserted into `array` in order to maintain the sort order of the -   * sorted `array`. If `callback` is passed, it will be executed for `value` and -   * each element in `array` to compute their sort ranking. The `callback` is -   * bound to `thisArg` and invoked with one argument; (value). The `callback` -   * argument may also be the name of a property to order by. -   * -   * @static -   * @memberOf _ -   * @category Arrays -   * @param {Array} array The array to iterate over. -   * @param {Mixed} value The value to evaluate. -   * @param {Function|String} [callback=identity|property] The function called -   *  per iteration or property name to order by. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Number} Returns the index at which the value should be inserted -   *  into `array`. -   * @example -   * -   * _.sortedIndex([20, 30, 50], 40); -   * // => 2 -   * -   * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x'); -   * // => 2 -   * -   * var dict = { -   *   'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 } -   * }; -   * -   * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) { -   *   return dict.wordToNumber[word]; -   * }); -   * // => 2 -   * -   * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) { -   *   return this.wordToNumber[word]; -   * }, dict); -   * // => 2 -   */ -  function sortedIndex(array, value, callback, thisArg) { -    var low = 0, -        high = array ? array.length : low; - -    // explicitly reference `identity` for better inlining in Firefox -    callback = callback ? createCallback(callback, thisArg) : identity; -    value = callback(value); - -    while (low < high) { -      var mid = (low + high) >>> 1; -      callback(array[mid]) < value -        ? low = mid + 1 -        : high = mid; -    } -    return low; -  } - -  /** -   * Computes the union of the passed-in arrays using strict equality for -   * comparisons, i.e. `===`. -   * -   * @static -   * @memberOf _ -   * @category Arrays -   * @param {Array} [array1, array2, ...] Arrays to process. -   * @returns {Array} Returns a new array of unique values, in order, that are -   *  present in one or more of the arrays. -   * @example -   * -   * _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]); -   * // => [1, 2, 3, 101, 10] -   */ -  function union() { -    return uniq(concat.apply(arrayRef, arguments)); -  } - -  /** -   * Creates a duplicate-value-free version of the `array` using strict equality -   * for comparisons, i.e. `===`. If the `array` is already sorted, passing `true` -   * for `isSorted` will run a faster algorithm. If `callback` is passed, each -   * element of `array` is passed through a callback` before uniqueness is computed. -   * The `callback` is bound to `thisArg` and invoked with three arguments; (value, index, array). -   * -   * @static -   * @memberOf _ -   * @alias unique -   * @category Arrays -   * @param {Array} array The array to process. -   * @param {Boolean} [isSorted=false] A flag to indicate that the `array` is already sorted. -   * @param {Function} [callback=identity] The function called per iteration. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Array} Returns a duplicate-value-free array. -   * @example -   * -   * _.uniq([1, 2, 1, 3, 1]); -   * // => [1, 2, 3] -   * -   * _.uniq([1, 1, 2, 2, 3], true); -   * // => [1, 2, 3] -   * -   * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return Math.floor(num); }); -   * // => [1, 2, 3] -   * -   * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return this.floor(num); }, Math); -   * // => [1, 2, 3] -   */ -  function uniq(array, isSorted, callback, thisArg) { -    var index = -1, -        length = array ? array.length : 0, -        result = [], -        seen = result; - -    // juggle arguments -    if (typeof isSorted == 'function') { -      thisArg = callback; -      callback = isSorted; -      isSorted = false; -    } -    // init value cache for large arrays -    var isLarge = !isSorted && length >= 75; -    if (isLarge) { -      var cache = {}; -    } -    if (callback) { -      seen = []; -      callback = createCallback(callback, thisArg); -    } -    while (++index < length) { -      var value = array[index], -          computed = callback ? callback(value, index, array) : value; - -      if (isLarge) { -        var key = computed + ''; -        var inited = hasOwnProperty.call(cache, key) -          ? !(seen = cache[key]) -          : (seen = cache[key] = []); -      } -      if (isSorted -            ? !index || seen[seen.length - 1] !== computed -            : inited || indexOf(seen, computed) < 0 -          ) { -        if (callback || isLarge) { -          seen.push(computed); -        } -        result.push(value); -      } -    } -    return result; -  } - -  /** -   * Creates an array with all occurrences of the passed values removed using -   * strict equality for comparisons, i.e. `===`. -   * -   * @static -   * @memberOf _ -   * @category Arrays -   * @param {Array} array The array to filter. -   * @param {Mixed} [value1, value2, ...] Values to remove. -   * @returns {Array} Returns a new filtered array. -   * @example -   * -   * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1); -   * // => [2, 3, 4] -   */ -  function without(array) { -    var index = -1, -        length = array ? array.length : 0, -        contains = cachedContains(arguments, 1, 20), -        result = []; - -    while (++index < length) { -      var value = array[index]; -      if (!contains(value)) { -        result.push(value); -      } -    } -    return result; -  } - -  /** -   * Groups the elements of each array at their corresponding indexes. Useful for -   * separate data sources that are coordinated through matching array indexes. -   * For a matrix of nested arrays, `_.zip.apply(...)` can transpose the matrix -   * in a similar fashion. -   * -   * @static -   * @memberOf _ -   * @category Arrays -   * @param {Array} [array1, array2, ...] Arrays to process. -   * @returns {Array} Returns a new array of grouped elements. -   * @example -   * -   * _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]); -   * // => [['moe', 30, true], ['larry', 40, false], ['curly', 50, false]] -   */ -  function zip(array) { -    var index = -1, -        length = array ? max(pluck(arguments, 'length')) : 0, -        result = Array(length); - -    while (++index < length) { -      result[index] = pluck(arguments, index); -    } -    return result; -  } - -  /*--------------------------------------------------------------------------*/ - -  /** -   * Creates a function that is restricted to executing `func` only after it is -   * called `n` times. The `func` is executed with the `this` binding of the -   * created function. -   * -   * @static -   * @memberOf _ -   * @category Functions -   * @param {Number} n The number of times the function must be called before -   * it is executed. -   * @param {Function} func The function to restrict. -   * @returns {Function} Returns the new restricted function. -   * @example -   * -   * var renderNotes = _.after(notes.length, render); -   * _.forEach(notes, function(note) { -   *   note.asyncSave({ 'success': renderNotes }); -   * }); -   * // `renderNotes` is run once, after all notes have saved -   */ -  function after(n, func) { -    if (n < 1) { -      return func(); -    } -    return function() { -      if (--n < 1) { -        return func.apply(this, arguments); -      } -    }; -  } - -  /** -   * Creates a function that, when called, invokes `func` with the `this` -   * binding of `thisArg` and prepends any additional `bind` arguments to those -   * passed to the bound function. -   * -   * @static -   * @memberOf _ -   * @category Functions -   * @param {Function} func The function to bind. -   * @param {Mixed} [thisArg] The `this` binding of `func`. -   * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied. -   * @returns {Function} Returns the new bound function. -   * @example -   * -   * var func = function(greeting) { -   *   return greeting + ' ' + this.name; -   * }; -   * -   * func = _.bind(func, { 'name': 'moe' }, 'hi'); -   * func(); -   * // => 'hi moe' -   */ -  function bind(func, thisArg) { -    // use `Function#bind` if it exists and is fast -    // (in V8 `Function#bind` is slower except when partially applied) -    return isBindFast || (nativeBind && arguments.length > 2) -      ? nativeBind.call.apply(nativeBind, arguments) -      : createBound(func, thisArg, slice(arguments, 2)); -  } - -  /** -   * Binds methods on `object` to `object`, overwriting the existing method. -   * If no method names are provided, all the function properties of `object` -   * will be bound. -   * -   * @static -   * @memberOf _ -   * @category Functions -   * @param {Object} object The object to bind and assign the bound methods to. -   * @param {String} [methodName1, methodName2, ...] Method names on the object to bind. -   * @returns {Object} Returns `object`. -   * @example -   * -   * var buttonView = { -   *  'label': 'lodash', -   *  'onClick': function() { alert('clicked: ' + this.label); } -   * }; -   * -   * _.bindAll(buttonView); -   * jQuery('#lodash_button').on('click', buttonView.onClick); -   * // => When the button is clicked, `this.label` will have the correct value -   */ -  function bindAll(object) { -    var funcs = arguments, -        index = funcs.length > 1 ? 0 : (funcs = functions(object), -1), -        length = funcs.length; - -    while (++index < length) { -      var key = funcs[index]; -      object[key] = bind(object[key], object); -    } -    return object; -  } - -  /** -   * Creates a function that, when called, invokes the method at `object[key]` -   * and prepends any additional `bindKey` arguments to those passed to the bound -   * function. This method differs from `_.bind` by allowing bound functions to -   * reference methods that will be redefined or don't yet exist. -   * See http://michaux.ca/articles/lazy-function-definition-pattern. -   * -   * @static -   * @memberOf _ -   * @category Functions -   * @param {Object} object The object the method belongs to. -   * @param {String} key The key of the method. -   * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied. -   * @returns {Function} Returns the new bound function. -   * @example -   * -   * var object = { -   *   'name': 'moe', -   *   'greet': function(greeting) { -   *     return greeting + ' ' + this.name; -   *   } -   * }; -   * -   * var func = _.bindKey(object, 'greet', 'hi'); -   * func(); -   * // => 'hi moe' -   * -   * object.greet = function(greeting) { -   *   return greeting + ', ' + this.name + '!'; -   * }; -   * -   * func(); -   * // => 'hi, moe!' -   */ -  function bindKey(object, key) { -    return createBound(object, key, slice(arguments, 2)); -  } - -  /** -   * Creates a function that is the composition of the passed functions, -   * where each function consumes the return value of the function that follows. -   * In math terms, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`. -   * Each function is executed with the `this` binding of the composed function. -   * -   * @static -   * @memberOf _ -   * @category Functions -   * @param {Function} [func1, func2, ...] Functions to compose. -   * @returns {Function} Returns the new composed function. -   * @example -   * -   * var greet = function(name) { return 'hi: ' + name; }; -   * var exclaim = function(statement) { return statement + '!'; }; -   * var welcome = _.compose(exclaim, greet); -   * welcome('moe'); -   * // => 'hi: moe!' -   */ -  function compose() { -    var funcs = arguments; -    return function() { -      var args = arguments, -          length = funcs.length; - -      while (length--) { -        args = [funcs[length].apply(this, args)]; -      } -      return args[0]; -    }; -  } - -  /** -   * Creates a function that will delay the execution of `func` until after -   * `wait` milliseconds have elapsed since the last time it was invoked. Pass -   * `true` for `immediate` to cause debounce to invoke `func` on the leading, -   * instead of the trailing, edge of the `wait` timeout. Subsequent calls to -   * the debounced function will return the result of the last `func` call. -   * -   * @static -   * @memberOf _ -   * @category Functions -   * @param {Function} func The function to debounce. -   * @param {Number} wait The number of milliseconds to delay. -   * @param {Boolean} immediate A flag to indicate execution is on the leading -   *  edge of the timeout. -   * @returns {Function} Returns the new debounced function. -   * @example -   * -   * var lazyLayout = _.debounce(calculateLayout, 300); -   * jQuery(window).on('resize', lazyLayout); -   */ -  function debounce(func, wait, immediate) { -    var args, -        result, -        thisArg, -        timeoutId; - -    function delayed() { -      timeoutId = null; -      if (!immediate) { -        result = func.apply(thisArg, args); -      } -    } -    return function() { -      var isImmediate = immediate && !timeoutId; -      args = arguments; -      thisArg = this; - -      clearTimeout(timeoutId); -      timeoutId = setTimeout(delayed, wait); - -      if (isImmediate) { -        result = func.apply(thisArg, args); -      } -      return result; -    }; -  } - -  /** -   * Executes the `func` function after `wait` milliseconds. Additional arguments -   * will be passed to `func` when it is invoked. -   * -   * @static -   * @memberOf _ -   * @category Functions -   * @param {Function} func The function to delay. -   * @param {Number} wait The number of milliseconds to delay execution. -   * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with. -   * @returns {Number} Returns the `setTimeout` timeout id. -   * @example -   * -   * var log = _.bind(console.log, console); -   * _.delay(log, 1000, 'logged later'); -   * // => 'logged later' (Appears after one second.) -   */ -  function delay(func, wait) { -    var args = slice(arguments, 2); -    return setTimeout(function() { func.apply(undefined, args); }, wait); -  } - -  /** -   * Defers executing the `func` function until the current call stack has cleared. -   * Additional arguments will be passed to `func` when it is invoked. -   * -   * @static -   * @memberOf _ -   * @category Functions -   * @param {Function} func The function to defer. -   * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with. -   * @returns {Number} Returns the `setTimeout` timeout id. -   * @example -   * -   * _.defer(function() { alert('deferred'); }); -   * // returns from the function before `alert` is called -   */ -  function defer(func) { -    var args = slice(arguments, 1); -    return setTimeout(function() { func.apply(undefined, args); }, 1); -  } - -  /** -   * Creates a function that memoizes the result of `func`. If `resolver` is -   * passed, it will be used to determine the cache key for storing the result -   * based on the arguments passed to the memoized function. By default, the first -   * argument passed to the memoized function is used as the cache key. The `func` -   * is executed with the `this` binding of the memoized function. -   * -   * @static -   * @memberOf _ -   * @category Functions -   * @param {Function} func The function to have its output memoized. -   * @param {Function} [resolver] A function used to resolve the cache key. -   * @returns {Function} Returns the new memoizing function. -   * @example -   * -   * var fibonacci = _.memoize(function(n) { -   *   return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); -   * }); -   */ -  function memoize(func, resolver) { -    var cache = {}; -    return function() { -      var key = resolver ? resolver.apply(this, arguments) : arguments[0]; -      return hasOwnProperty.call(cache, key) -        ? cache[key] -        : (cache[key] = func.apply(this, arguments)); -    }; -  } - -  /** -   * Creates a function that is restricted to execute `func` once. Repeat calls to -   * the function will return the value of the first call. The `func` is executed -   * with the `this` binding of the created function. -   * -   * @static -   * @memberOf _ -   * @category Functions -   * @param {Function} func The function to restrict. -   * @returns {Function} Returns the new restricted function. -   * @example -   * -   * var initialize = _.once(createApplication); -   * initialize(); -   * initialize(); -   * // Application is only created once. -   */ -  function once(func) { -    var result, -        ran = false; - -    return function() { -      if (ran) { -        return result; -      } -      ran = true; -      result = func.apply(this, arguments); - -      // clear the `func` variable so the function may be garbage collected -      func = null; -      return result; -    }; -  } - -  /** -   * Creates a function that, when called, invokes `func` with any additional -   * `partial` arguments prepended to those passed to the new function. This -   * method is similar to `bind`, except it does **not** alter the `this` binding. -   * -   * @static -   * @memberOf _ -   * @category Functions -   * @param {Function} func The function to partially apply arguments to. -   * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied. -   * @returns {Function} Returns the new partially applied function. -   * @example -   * -   * var greet = function(greeting, name) { return greeting + ': ' + name; }; -   * var hi = _.partial(greet, 'hi'); -   * hi('moe'); -   * // => 'hi: moe' -   */ -  function partial(func) { -    return createBound(func, slice(arguments, 1)); -  } - -  /** -   * Creates a function that, when executed, will only call the `func` -   * function at most once per every `wait` milliseconds. If the throttled -   * function is invoked more than once during the `wait` timeout, `func` will -   * also be called on the trailing edge of the timeout. Subsequent calls to the -   * throttled function will return the result of the last `func` call. -   * -   * @static -   * @memberOf _ -   * @category Functions -   * @param {Function} func The function to throttle. -   * @param {Number} wait The number of milliseconds to throttle executions to. -   * @returns {Function} Returns the new throttled function. -   * @example -   * -   * var throttled = _.throttle(updatePosition, 100); -   * jQuery(window).on('scroll', throttled); -   */ -  function throttle(func, wait) { -    var args, -        result, -        thisArg, -        timeoutId, -        lastCalled = 0; - -    function trailingCall() { -      lastCalled = new Date; -      timeoutId = null; -      result = func.apply(thisArg, args); -    } -    return function() { -      var now = new Date, -          remaining = wait - (now - lastCalled); - -      args = arguments; -      thisArg = this; - -      if (remaining <= 0) { -        clearTimeout(timeoutId); -        timeoutId = null; -        lastCalled = now; -        result = func.apply(thisArg, args); -      } -      else if (!timeoutId) { -        timeoutId = setTimeout(trailingCall, remaining); -      } -      return result; -    }; -  } - -  /** -   * Creates a function that passes `value` to the `wrapper` function as its -   * first argument. Additional arguments passed to the function are appended -   * to those passed to the `wrapper` function. The `wrapper` is executed with -   * the `this` binding of the created function. -   * -   * @static -   * @memberOf _ -   * @category Functions -   * @param {Mixed} value The value to wrap. -   * @param {Function} wrapper The wrapper function. -   * @returns {Function} Returns the new function. -   * @example -   * -   * var hello = function(name) { return 'hello ' + name; }; -   * hello = _.wrap(hello, function(func) { -   *   return 'before, ' + func('moe') + ', after'; -   * }); -   * hello(); -   * // => 'before, hello moe, after' -   */ -  function wrap(value, wrapper) { -    return function() { -      var args = [value]; -      push.apply(args, arguments); -      return wrapper.apply(this, args); -    }; -  } - -  /*--------------------------------------------------------------------------*/ - -  /** -   * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their -   * corresponding HTML entities. -   * -   * @static -   * @memberOf _ -   * @category Utilities -   * @param {String} string The string to escape. -   * @returns {String} Returns the escaped string. -   * @example -   * -   * _.escape('Moe, Larry & Curly'); -   * // => 'Moe, Larry & Curly' -   */ -  function escape(string) { -    return string == null ? '' : (string + '').replace(reUnescapedHtml, escapeHtmlChar); -  } - -  /** -   * This function returns the first argument passed to it. -   * -   * @static -   * @memberOf _ -   * @category Utilities -   * @param {Mixed} value Any value. -   * @returns {Mixed} Returns `value`. -   * @example -   * -   * var moe = { 'name': 'moe' }; -   * moe === _.identity(moe); -   * // => true -   */ -  function identity(value) { -    return value; -  } - -  /** -   * Adds functions properties of `object` to the `lodash` function and chainable -   * wrapper. -   * -   * @static -   * @memberOf _ -   * @category Utilities -   * @param {Object} object The object of function properties to add to `lodash`. -   * @example -   * -   * _.mixin({ -   *   'capitalize': function(string) { -   *     return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase(); -   *   } -   * }); -   * -   * _.capitalize('larry'); -   * // => 'Larry' -   * -   * _('curly').capitalize(); -   * // => 'Curly' -   */ -  function mixin(object) { -    forEach(functions(object), function(methodName) { -      var func = lodash[methodName] = object[methodName]; - -      lodash.prototype[methodName] = function() { -        var args = [this.__wrapped__]; -        push.apply(args, arguments); - -        var result = func.apply(lodash, args); -        return new lodash(result); -      }; -    }); -  } - -  /** -   * Reverts the '_' variable to its previous value and returns a reference to -   * the `lodash` function. -   * -   * @static -   * @memberOf _ -   * @category Utilities -   * @returns {Function} Returns the `lodash` function. -   * @example -   * -   * var lodash = _.noConflict(); -   */ -  function noConflict() { -    window._ = oldDash; -    return this; -  } - -  /** -   * Produces a random number between `min` and `max` (inclusive). If only one -   * argument is passed, a number between `0` and the given number will be returned. -   * -   * @static -   * @memberOf _ -   * @category Utilities -   * @param {Number} [min=0] The minimum possible value. -   * @param {Number} [max=1] The maximum possible value. -   * @returns {Number} Returns a random number. -   * @example -   * -   * _.random(0, 5); -   * // => a number between 1 and 5 -   * -   * _.random(5); -   * // => also a number between 1 and 5 -   */ -  function random(min, max) { -    if (min == null && max == null) { -      max = 1; -    } -    min = +min || 0; -    if (max == null) { -      max = min; -      min = 0; -    } -    return min + floor(nativeRandom() * ((+max || 0) - min + 1)); -  } - -  /** -   * Resolves the value of `property` on `object`. If `property` is a function -   * it will be invoked and its result returned, else the property value is -   * returned. If `object` is falsey, then `null` is returned. -   * -   * @static -   * @memberOf _ -   * @category Utilities -   * @param {Object} object The object to inspect. -   * @param {String} property The property to get the value of. -   * @returns {Mixed} Returns the resolved value. -   * @example -   * -   * var object = { -   *   'cheese': 'crumpets', -   *   'stuff': function() { -   *     return 'nonsense'; -   *   } -   * }; -   * -   * _.result(object, 'cheese'); -   * // => 'crumpets' -   * -   * _.result(object, 'stuff'); -   * // => 'nonsense' -   */ -  function result(object, property) { -    // based on Backbone's private `getValue` function -    // https://github.com/documentcloud/backbone/blob/0.9.2/backbone.js#L1419-1424 -    var value = object ? object[property] : null; -    return isFunction(value) ? object[property]() : value; -  } - -  /** -   * A micro-templating method that handles arbitrary delimiters, preserves -   * whitespace, and correctly escapes quotes within interpolated code. -   * -   * Note: In the development build `_.template` utilizes sourceURLs for easier -   * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl -   * -   * Note: Lo-Dash may be used in Chrome extensions by either creating a `lodash csp` -   * build and avoiding `_.template` use, or loading Lo-Dash in a sandboxed page. -   * See http://developer.chrome.com/trunk/extensions/sandboxingEval.html -   * -   * @static -   * @memberOf _ -   * @category Utilities -   * @param {String} text The template text. -   * @param {Obect} data The data object used to populate the text. -   * @param {Object} options The options object. -   *  escape - The "escape" delimiter regexp. -   *  evaluate - The "evaluate" delimiter regexp. -   *  interpolate - The "interpolate" delimiter regexp. -   *  sourceURL - The sourceURL of the template's compiled source. -   *  variable - The data object variable name. -   * -   * @returns {Function|String} Returns a compiled function when no `data` object -   *  is given, else it returns the interpolated text. -   * @example -   * -   * // using a compiled template -   * var compiled = _.template('hello <%= name %>'); -   * compiled({ 'name': 'moe' }); -   * // => 'hello moe' -   * -   * var list = '<% _.forEach(people, function(name) { %><li><%= name %></li><% }); %>'; -   * _.template(list, { 'people': ['moe', 'larry', 'curly'] }); -   * // => '<li>moe</li><li>larry</li><li>curly</li>' -   * -   * // using the "escape" delimiter to escape HTML in data property values -   * _.template('<b><%- value %></b>', { 'value': '<script>' }); -   * // => '<b><script></b>' -   * -   * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter -   * _.template('hello ${ name }', { 'name': 'curly' }); -   * // => 'hello curly' -   * -   * // using the internal `print` function in "evaluate" delimiters -   * _.template('<% print("hello " + epithet); %>!', { 'epithet': 'stooge' }); -   * // => 'hello stooge!' -   * -   * // using custom template delimiters -   * _.templateSettings = { -   *   'interpolate': /{{([\s\S]+?)}}/g -   * }; -   * -   * _.template('hello {{ name }}!', { 'name': 'mustache' }); -   * // => 'hello mustache!' -   * -   * // using the `sourceURL` option to specify a custom sourceURL for the template -   * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' }); -   * compiled(data); -   * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector -   * -   * // using the `variable` option to ensure a with-statement isn't used in the compiled template -   * var compiled = _.template('hello <%= data.name %>!', null, { 'variable': 'data' }); -   * compiled.source; -   * // => function(data) { -   *   var __t, __p = '', __e = _.escape; -   *   __p += 'hello ' + ((__t = ( data.name )) == null ? '' : __t) + '!'; -   *   return __p; -   * } -   * -   * // using the `source` property to inline compiled templates for meaningful -   * // line numbers in error messages and a stack trace -   * fs.writeFileSync(path.join(cwd, 'jst.js'), '\ -   *   var JST = {\ -   *     "main": ' + _.template(mainText).source + '\ -   *   };\ -   * '); -   */ -  function template(text, data, options) { -    // based on John Resig's `tmpl` implementation -    // http://ejohn.org/blog/javascript-micro-templating/ -    // and Laura Doktorova's doT.js -    // https://github.com/olado/doT -    text || (text = ''); -    options || (options = {}); - -    var isEvaluating, -        result, -        settings = lodash.templateSettings, -        index = 0, -        interpolate = options.interpolate || settings.interpolate || reNoMatch, -        source = "__p += '", -        variable = options.variable || settings.variable, -        hasVariable = variable; - -    // compile regexp to match each delimiter -    var reDelimiters = RegExp( -      (options.escape || settings.escape || reNoMatch).source + '|' + -      interpolate.source + '|' + -      (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' + -      (options.evaluate || settings.evaluate || reNoMatch).source + '|$' -    , 'g'); - -    text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) { -      interpolateValue || (interpolateValue = esTemplateValue); - -      // escape characters that cannot be included in string literals -      source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar); - -      // replace delimiters with snippets -      if (escapeValue) { -        source += "' +\n__e(" + escapeValue + ") +\n'"; -      } -      if (evaluateValue) { -        source += "';\n" + evaluateValue + ";\n__p += '"; -      } -      if (interpolateValue) { -        source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'"; -      } -      isEvaluating || (isEvaluating = evaluateValue || reComplexDelimiter.test(escapeValue || interpolateValue)); -      index = offset + match.length; - -      // the JS engine embedded in Adobe products requires returning the `match` -      // string in order to produce the correct `offset` value -      return match; -    }); - -    source += "';\n"; - -    // if `variable` is not specified and the template contains "evaluate" -    // delimiters, wrap a with-statement around the generated code to add the -    // data object to the top of the scope chain -    if (!hasVariable) { -      variable = 'obj'; -      if (isEvaluating) { -        source = 'with (' + variable + ') {\n' + source + '\n}\n'; -      } -      else { -        // avoid a with-statement by prepending data object references to property names -        var reDoubleVariable = RegExp('(\\(\\s*)' + variable + '\\.' + variable + '\\b', 'g'); -        source = source -          .replace(reInsertVariable, '$&' + variable + '.') -          .replace(reDoubleVariable, '$1__d'); -      } -    } - -    // cleanup code by stripping empty strings -    source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source) -      .replace(reEmptyStringMiddle, '$1') -      .replace(reEmptyStringTrailing, '$1;'); - -    // frame code as the function body -    source = 'function(' + variable + ') {\n' + -      (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') + -      "var __t, __p = '', __e = _.escape" + -      (isEvaluating -        ? ', __j = Array.prototype.join;\n' + -          "function print() { __p += __j.call(arguments, '') }\n" -        : (hasVariable ? '' : ', __d = ' + variable + '.' + variable + ' || ' + variable) + ';\n' -      ) + -      source + -      'return __p\n}'; - -    // use a sourceURL for easier debugging -    // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl -    var sourceURL = useSourceURL -      ? '\n//@ sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') -      : ''; - -    try { -      result = Function('_', 'return ' + source + sourceURL)(lodash); -    } catch(e) { -      e.source = source; -      throw e; -    } - -    if (data) { -      return result(data); -    } -    // provide the compiled function's source via its `toString` method, in -    // supported environments, or the `source` property as a convenience for -    // inlining compiled templates during the build process -    result.source = source; -    return result; -  } - -  /** -   * Executes the `callback` function `n` times, returning an array of the results -   * of each `callback` execution. The `callback` is bound to `thisArg` and invoked -   * with one argument; (index). -   * -   * @static -   * @memberOf _ -   * @category Utilities -   * @param {Number} n The number of times to execute the callback. -   * @param {Function} callback The function called per iteration. -   * @param {Mixed} [thisArg] The `this` binding of `callback`. -   * @returns {Array} Returns a new array of the results of each `callback` execution. -   * @example -   * -   * var diceRolls = _.times(3, _.partial(_.random, 1, 6)); -   * // => [3, 6, 4] -   * -   * _.times(3, function(n) { mage.castSpell(n); }); -   * // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively -   * -   * _.times(3, function(n) { this.cast(n); }, mage); -   * // => also calls `mage.castSpell(n)` three times -   */ -  function times(n, callback, thisArg) { -    n = +n || 0; -    var index = -1, -        result = Array(n); - -    while (++index < n) { -      result[index] = callback.call(thisArg, index); -    } -    return result; -  } - -  /** -   * The opposite of `_.escape`, this method converts the HTML entities -   * `&`, `<`, `>`, `"`, and `'` in `string` to their -   * corresponding characters. -   * -   * @static -   * @memberOf _ -   * @category Utilities -   * @param {String} string The string to unescape. -   * @returns {String} Returns the unescaped string. -   * @example -   * -   * _.unescape('Moe, Larry & Curly'); -   * // => 'Moe, Larry & Curly' -   */ -  function unescape(string) { -    return string == null ? '' : (string + '').replace(reEscapedHtml, unescapeHtmlChar); -  } - -  /** -   * Generates a unique ID. If `prefix` is passed, the ID will be appended to it. -   * -   * @static -   * @memberOf _ -   * @category Utilities -   * @param {String} [prefix] The value to prefix the ID with. -   * @returns {String} Returns the unique ID. -   * @example -   * -   * _.uniqueId('contact_'); -   * // => 'contact_104' -   * -   * _.uniqueId(); -   * // => '105' -   */ -  function uniqueId(prefix) { -    return (prefix == null ? '' : prefix + '') + (++idCounter); -  } - -  /*--------------------------------------------------------------------------*/ - -  /** -   * Invokes `interceptor` with the `value` as the first argument, and then -   * returns `value`. The purpose of this method is to "tap into" a method chain, -   * in order to perform operations on intermediate results within the chain. -   * -   * @static -   * @memberOf _ -   * @category Chaining -   * @param {Mixed} value The value to pass to `interceptor`. -   * @param {Function} interceptor The function to invoke. -   * @returns {Mixed} Returns `value`. -   * @example -   * -   * _.chain([1, 2, 3, 200]) -   *  .filter(function(num) { return num % 2 == 0; }) -   *  .tap(alert) -   *  .map(function(num) { return num * num; }) -   *  .value(); -   * // => // [2, 200] (alerted) -   * // => [4, 40000] -   */ -  function tap(value, interceptor) { -    interceptor(value); -    return value; -  } - -  /** -   * Produces the `toString` result of the wrapped value. -   * -   * @name toString -   * @memberOf _ -   * @category Chaining -   * @returns {String} Returns the string result. -   * @example -   * -   * _([1, 2, 3]).toString(); -   * // => '1,2,3' -   */ -  function wrapperToString() { -    return this.__wrapped__ + ''; -  } - -  /** -   * Extracts the wrapped value. -   * -   * @name valueOf -   * @memberOf _ -   * @alias value -   * @category Chaining -   * @returns {Mixed} Returns the wrapped value. -   * @example -   * -   * _([1, 2, 3]).valueOf(); -   * // => [1, 2, 3] -   */ -  function wrapperValueOf() { -    return this.__wrapped__; -  } - -  /*--------------------------------------------------------------------------*/ - -  // add functions that return wrapped values when chaining -  lodash.after = after; -  lodash.assign = assign; -  lodash.bind = bind; -  lodash.bindAll = bindAll; -  lodash.bindKey = bindKey; -  lodash.compact = compact; -  lodash.compose = compose; -  lodash.countBy = countBy; -  lodash.debounce = debounce; -  lodash.defaults = defaults; -  lodash.defer = defer; -  lodash.delay = delay; -  lodash.difference = difference; -  lodash.filter = filter; -  lodash.flatten = flatten; -  lodash.forEach = forEach; -  lodash.forIn = forIn; -  lodash.forOwn = forOwn; -  lodash.functions = functions; -  lodash.groupBy = groupBy; -  lodash.initial = initial; -  lodash.intersection = intersection; -  lodash.invert = invert; -  lodash.invoke = invoke; -  lodash.keys = keys; -  lodash.map = map; -  lodash.max = max; -  lodash.memoize = memoize; -  lodash.merge = merge; -  lodash.min = min; -  lodash.object = object; -  lodash.omit = omit; -  lodash.once = once; -  lodash.pairs = pairs; -  lodash.partial = partial; -  lodash.pick = pick; -  lodash.pluck = pluck; -  lodash.range = range; -  lodash.reject = reject; -  lodash.rest = rest; -  lodash.shuffle = shuffle; -  lodash.sortBy = sortBy; -  lodash.tap = tap; -  lodash.throttle = throttle; -  lodash.times = times; -  lodash.toArray = toArray; -  lodash.union = union; -  lodash.uniq = uniq; -  lodash.values = values; -  lodash.where = where; -  lodash.without = without; -  lodash.wrap = wrap; -  lodash.zip = zip; - -  // add aliases -  lodash.collect = map; -  lodash.drop = rest; -  lodash.each = forEach; -  lodash.extend = assign; -  lodash.methods = functions; -  lodash.select = filter; -  lodash.tail = rest; -  lodash.unique = uniq; - -  // add functions to `lodash.prototype` -  mixin(lodash); - -  /*--------------------------------------------------------------------------*/ - -  // add functions that return unwrapped values when chaining -  lodash.clone = clone; -  lodash.cloneDeep = cloneDeep; -  lodash.contains = contains; -  lodash.escape = escape; -  lodash.every = every; -  lodash.find = find; -  lodash.has = has; -  lodash.identity = identity; -  lodash.indexOf = indexOf; -  lodash.isArguments = isArguments; -  lodash.isArray = isArray; -  lodash.isBoolean = isBoolean; -  lodash.isDate = isDate; -  lodash.isElement = isElement; -  lodash.isEmpty = isEmpty; -  lodash.isEqual = isEqual; -  lodash.isFinite = isFinite; -  lodash.isFunction = isFunction; -  lodash.isNaN = isNaN; -  lodash.isNull = isNull; -  lodash.isNumber = isNumber; -  lodash.isObject = isObject; -  lodash.isPlainObject = isPlainObject; -  lodash.isRegExp = isRegExp; -  lodash.isString = isString; -  lodash.isUndefined = isUndefined; -  lodash.lastIndexOf = lastIndexOf; -  lodash.mixin = mixin; -  lodash.noConflict = noConflict; -  lodash.random = random; -  lodash.reduce = reduce; -  lodash.reduceRight = reduceRight; -  lodash.result = result; -  lodash.size = size; -  lodash.some = some; -  lodash.sortedIndex = sortedIndex; -  lodash.template = template; -  lodash.unescape = unescape; -  lodash.uniqueId = uniqueId; - -  // add aliases -  lodash.all = every; -  lodash.any = some; -  lodash.detect = find; -  lodash.foldl = reduce; -  lodash.foldr = reduceRight; -  lodash.include = contains; -  lodash.inject = reduce; - -  forOwn(lodash, function(func, methodName) { -    if (!lodash.prototype[methodName]) { -      lodash.prototype[methodName] = function() { -        var args = [this.__wrapped__]; -        push.apply(args, arguments); -        return func.apply(lodash, args); -      }; -    } -  }); - -  /*--------------------------------------------------------------------------*/ - -  // add functions capable of returning wrapped and unwrapped values when chaining -  lodash.first = first; -  lodash.last = last; - -  // add aliases -  lodash.take = first; -  lodash.head = first; - -  forOwn(lodash, function(func, methodName) { -    if (!lodash.prototype[methodName]) { -      lodash.prototype[methodName]= function(n, guard) { -        var result = func(this.__wrapped__, n, guard); -        return (n == null || guard) ? result : new lodash(result); -      }; -    } -  }); - -  /*--------------------------------------------------------------------------*/ - -  /** -   * The semantic version number. -   * -   * @static -   * @memberOf _ -   * @type String -   */ -  lodash.VERSION = '1.0.0-rc.3'; - -  // add "Chaining" functions to the wrapper -  lodash.prototype.toString = wrapperToString; -  lodash.prototype.value = wrapperValueOf; -  lodash.prototype.valueOf = wrapperValueOf; - -  // add `Array` functions that return unwrapped values -  each(['join', 'pop', 'shift'], function(methodName) { -    var func = arrayRef[methodName]; -    lodash.prototype[methodName] = function() { -      return func.apply(this.__wrapped__, arguments); -    }; -  }); - -  // add `Array` functions that return the wrapped value -  each(['push', 'reverse', 'sort', 'unshift'], function(methodName) { -    var func = arrayRef[methodName]; -    lodash.prototype[methodName] = function() { -      func.apply(this.__wrapped__, arguments); -      return this; -    }; -  }); - -  // add `Array` functions that return new wrapped values -  each(['concat', 'slice', 'splice'], function(methodName) { -    var func = arrayRef[methodName]; -    lodash.prototype[methodName] = function() { -      var result = func.apply(this.__wrapped__, arguments); -      return new lodash(result); -    }; -  }); - -  // avoid array-like object bugs with `Array#shift` and `Array#splice` -  // in Firefox < 10 and IE < 9 -  if (hasObjectSpliceBug) { -    each(['pop', 'shift', 'splice'], function(methodName) { -      var func = arrayRef[methodName], -          isSplice = methodName == 'splice'; - -      lodash.prototype[methodName] = function() { -        var value = this.__wrapped__, -            result = func.apply(value, arguments); - -        if (value.length === 0) { -          delete value[0]; -        } -        return isSplice ? new lodash(result) : result; -      }; -    }); -  } - -  // add pseudo private property to be used and removed during the build process -  lodash._each = each; -  lodash._iteratorTemplate = iteratorTemplate; - -  /*--------------------------------------------------------------------------*/ - -  // expose Lo-Dash -  // some AMD build optimizers, like r.js, check for specific condition patterns like the following: -  if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { -    // Expose Lo-Dash to the global object even when an AMD loader is present in -    // case Lo-Dash was injected by a third-party script and not intended to be -    // loaded as a module. The global assignment can be reverted in the Lo-Dash -    // module via its `noConflict()` method. -    window._ = lodash; - -    // define as an anonymous module so, through path mapping, it can be -    // referenced as the "underscore" module -    define(function() { -      return lodash; -    }); -  } -  // check for `exports` after `define` in case a build optimizer adds an `exports` object -  else if (freeExports) { -    // in Node.js or RingoJS v0.8.0+ -    if (typeof module == 'object' && module && module.exports == freeExports) { -      (module.exports = lodash)._ = lodash; -    } -    // in Narwhal or RingoJS v0.7.0- -    else { -      freeExports._ = lodash; -    } -  } -  else { -    // in a browser or Rhino -    window._ = lodash; -  } -}(this)); diff --git a/module/web/static/js/utils/apitypes.js b/module/web/static/js/utils/apitypes.js new file mode 100644 index 000000000..c9fca48d6 --- /dev/null +++ b/module/web/static/js/utils/apitypes.js @@ -0,0 +1,14 @@ +// Autogenerated, do not edit! +define([], function() { +	return { +		DownloadState: {'Failed': 3, 'All': 0, 'Unmanaged': 4, 'Finished': 1, 'Unfinished': 2}, +		DownloadStatus: {'Downloading': 10, 'NA': 0, 'Processing': 14, 'Waiting': 9, 'Decrypting': 13, 'Paused': 4, 'Failed': 7, 'Finished': 5, 'Skipped': 6, 'Unknown': 16, 'Aborted': 12, 'Online': 2, 'TempOffline': 11, 'Offline': 1, 'Custom': 15, 'Starting': 8, 'Queued': 3}, +		FileStatus: {'Remote': 2, 'Ok': 0, 'Missing': 1}, +		Input: {'Multiple': 10, 'Int': 2, 'NA': 0, 'List': 11, 'Bool': 7, 'File': 3, 'Text': 1, 'Table': 12, 'Folder': 4, 'Password': 6, 'Click': 8, 'Select': 9, 'Textbox': 5}, +		MediaType: {'All': 0, 'Audio': 2, 'Image': 4, 'Other': 1, 'Video': 8, 'Document': 16, 'Archive': 32}, +		Output: {'Captcha': 2, 'All': 0, 'Query': 4, 'Notification': 1}, +		PackageStatus: {'Paused': 1, 'Remote': 3, 'Folder': 2, 'Ok': 0}, +		Permission: {'All': 0, 'Interaction': 32, 'Modify': 4, 'Add': 1, 'Accounts': 16, 'Plugins': 64, 'Download': 8, 'Delete': 2}, +		Role: {'Admin': 0, 'User': 1}, +	}; +});
\ No newline at end of file diff --git a/module/web/static/js/views/actionbarView.js b/module/web/static/js/views/actionbarView.js deleted file mode 100644 index bdfb9ef7b..000000000 --- a/module/web/static/js/views/actionbarView.js +++ /dev/null @@ -1,28 +0,0 @@ -define(['jquery', 'backbone', 'underscore', 'app'], -    function($, Backbone, _, App) { - -        // Renders the actionbar for the dashboard -        return Backbone.View.extend({ -            el: 'ul.actionbar', - -            events: { -            }, - -            initialize: function() { - -                this.$('.search-query').typeahead({ -                    minLength: 2, -                    source: this.getAutocompletion -                }); - -            }, - -            render: function() { -            }, - -            getAutocompletion: function() { -                return ["static", "autocompletion", "demo", "with", "some", "keywords", -                    "a very long proposal for autocompletion"]; -            } -        }); -    });
\ No newline at end of file diff --git a/module/web/static/js/views/dashboardView.js b/module/web/static/js/views/dashboardView.js index 64f61eeaf..58ca8faf0 100644 --- a/module/web/static/js/views/dashboardView.js +++ b/module/web/static/js/views/dashboardView.js @@ -1,6 +1,6 @@  define(['jquery', 'backbone', 'underscore', 'app', 'models/TreeCollection', -    'views/packageView', 'views/fileView', 'views/selectionView', 'views/actionbarView'], -    function($, Backbone, _, App, TreeCollection, packageView, fileView, selectionView, actionbarView) { +    'views/packageView', 'views/fileView', 'views/selectionView', 'views/filterView'], +    function($, Backbone, _, App, TreeCollection, packageView, fileView, selectionView, filterView) {          // Renders whole dashboard          return Backbone.View.extend({ @@ -24,7 +24,7 @@ define(['jquery', 'backbone', 'underscore', 'app', 'models/TreeCollection',                  this.tree = new TreeCollection();                  var view = new selectionView(this.tree); -                view = new actionbarView(); +                view = new filterView();                  // When package is added we reload the data                  App.vent.on('package:added', function() { diff --git a/module/web/static/js/views/fileView.js b/module/web/static/js/views/fileView.js index 3a4183289..f4f228559 100644 --- a/module/web/static/js/views/fileView.js +++ b/module/web/static/js/views/fileView.js @@ -14,6 +14,7 @@ define(['jquery', 'backbone', 'underscore', 'app', 'views/abstract/itemView'],              initialize: function() {                  this.listenTo(this.model, 'change', this.render); +                this.listenTo(this.model, 'change:visible', this.visibility_changed);                  this.listenTo(this.model, 'remove', this.destroy);              }, @@ -45,7 +46,10 @@ define(['jquery', 'backbone', 'underscore', 'app', 'views/abstract/itemView'],                  else                      this.$el.removeClass('ui-selected'); -                this.$('.iconf-chevron-down').dropdown(); +                if (this.model.get('visible')) +                    this.$el.show(); +                else +                    this.$el.hide();                  return this;              }, @@ -57,6 +61,10 @@ define(['jquery', 'backbone', 'underscore', 'app', 'views/abstract/itemView'],                  this.model.set('selected', !checked, {silent: true});                  this.$el.toggleClass('ui-selected');                  App.vent.trigger('file:selection'); +            }, + +            visibility_changed: function() { +              }          }); diff --git a/module/web/static/js/views/filterView.js b/module/web/static/js/views/filterView.js new file mode 100644 index 000000000..eef5db92f --- /dev/null +++ b/module/web/static/js/views/filterView.js @@ -0,0 +1,93 @@ +define(['jquery', 'backbone', 'underscore', 'app', 'utils/apitypes'], +    function($, Backbone, _, App, Api) { + +        var Finished = [Api.DownloadStatus.Finished, Api.DownloadStatus.Skipped]; +        var Failed = [Api.DownloadStatus.Failed, Api.DownloadStatus.Aborted, Api.DownloadStatus.TempOffline, Api.DownloadStatus.Offline]; +        // Unfinished - Other + +        // Renders the actionbar for the dashboard, handles everything related to filtering displayed files +        return Backbone.View.extend({ +            el: 'ul.actionbar', + +            events: { +                'click .filter-type': 'filter_type', +                'click .filter-state': 'switch_filter' +            }, + +            state: null, +            stateMenu: null, + +            initialize: function() { +                this.$('.search-query').typeahead({ +                    minLength: 2, +                    source: this.getAutocompletion +                }); + +                this.stateMenu = this.$('.dropdown-toggle .state'); +                this.state = Api.DownloadState.All; +            }, + +            render: function() { +                return this; +            }, + +            getAutocompletion: function() { +                return ["static", "autocompletion", "demo", "with", "some", "keywords", +                    "a very long proposal for autocompletion"]; +            }, + +            switch_filter: function(e) { +                e.stopPropagation(); +                var element = $(e.target); +                var state = parseInt(element.data('state'), 10); +                var menu = this.stateMenu.parent().parent(); +                menu.removeClass('open'); + +                if (state === Api.DownloadState.Finished) { +                    menu.removeClass().addClass('dropdown finished'); +                } else if (state === Api.DownloadState.Unfinished) { +                    menu.removeClass().addClass('dropdown active'); +                } else if (state === Api.DownloadState.Failed) { +                    menu.removeClass().addClass('dropdown failed'); +                } else { +                    menu.removeClass().addClass('dropdown'); +                } + +                this.state = state; +                this.stateMenu.text(element.text()); +                this.apply_filter(); +            }, + +            // Applies the filtering to current open files +            apply_filter: function() { +                if (!App.dashboard.files) +                    return; + +                var self = this; +                App.dashboard.files.map(function(file) { +                    var visible = file.get('visible'); +                    if (visible !== self.is_visible(file)) +                        file.set('visible', !visible); +                }); + +            }, + +            // determine if a file should be visible +            // TODO: non download files +            is_visible: function(file) { +                if (this.state == Api.DownloadState.Finished) +                    return _.indexOf(Finished, file.get('download').status) > -1; +                else if (this.state == Api.DownloadState.Unfinished) +                    return _.indexOf(Finished, file.get('download').status) > -1 && _.indexOf(Failed, file.get('download').status) > -1; +                else if (this.state == Api.DownloadState.Failed) +                    return _.indexOf(Failed, file.get('download').status) > -1; + +                return true; +            }, + +            filter_type: function(e) { + +            } + +        }); +    });
\ No newline at end of file diff --git a/module/web/static/js/views/packageView.js b/module/web/static/js/views/packageView.js index 095121d87..9eb1ecf5f 100644 --- a/module/web/static/js/views/packageView.js +++ b/module/web/static/js/views/packageView.js @@ -24,7 +24,7 @@ define(['jquery', 'app', 'views/abstract/itemView', 'underscore'],                  this.listenTo(this.model, 'change', this.render);                  this.listenTo(this.model, 'remove', this.unrender); -//                // Clear drop down menu +                // Clear drop down menu                  var self = this;                  this.$el.on('mouseleave', function() {                      self.$('.dropdown-menu').parent().removeClass('open'); @@ -39,9 +39,6 @@ define(['jquery', 'app', 'views/abstract/itemView', 'underscore'],                  this.$el.html(this.template(this.model.toJSON()));                  this.$el.initTooltips(); -                // Init the dropdown-menu -                this.$('.iconf-chevron-down').dropdown(); -                  return this;              }, diff --git a/module/web/static/js/views/selectionView.js b/module/web/static/js/views/selectionView.js index 4c433e31c..eaed33d59 100644 --- a/module/web/static/js/views/selectionView.js +++ b/module/web/static/js/views/selectionView.js @@ -15,18 +15,15 @@ define(['jquery', 'backbone', 'underscore', 'app'],              // available packages              tree: null, -            // selected files -            files: null,              // Element of the action bar              actionBar: null, -            // needed to know when slide down +            // number of currently selected elements              current: 0,              initialize: function(tree) {                  this.tree = tree; -                this.files = tree.get('files'); -                App.vent.on('dashboard:show', _.bind(this.set_files, this)); +                App.vent.on('dashboard:show', _.bind(this.render, this));                  App.vent.on('package:selection', _.bind(this.render, this));                  App.vent.on('file:selection', _.bind(this.render, this)); @@ -37,10 +34,13 @@ define(['jquery', 'backbone', 'underscore', 'app'],  //                this.tree.get('packages').on('delete', _.bind(this.render, this));              }, -            get_files: function() { +            get_files: function(all) {                  var files = []; -                if (this.files) -                    files = this.files.where({selected: true}); +                if (App.dashboard.files) +                    if (all) +                        files = App.dashboard.files.where({visible: true}); +                    else +                        files = App.dashboard.files.where({selected: true, visible: true});                  return files;              }, @@ -71,11 +71,6 @@ define(['jquery', 'backbone', 'underscore', 'app'],                  this.current = files + packs;              }, -            set_files: function(files) { -                this.files = files; -                this.render(); -            }, -              // Deselects all items, optional only files              deselect: function(filesOnly) {                  this.get_files().map(function(file) { @@ -123,8 +118,7 @@ define(['jquery', 'backbone', 'underscore', 'app'],              select_toggle: function() {                  var files = this.get_files();                  if (files.length === 0) { -                    // TODO Select only visible files -                    this.files.map(function(file) { +                    this.get_files(true).map(function(file) {                          file.set('selected', true);                      }); diff --git a/module/web/templates/default/dashboard.html b/module/web/templates/default/dashboard.html index e80426dcc..4312a4bd8 100644 --- a/module/web/templates/default/dashboard.html +++ b/module/web/templates/default/dashboard.html @@ -37,13 +37,19 @@                  <%/if%>
                  <i class="iconf-chevron-down" data-toggle="dropdown">
                  </i>
 -                <ul class="dropdown-menu">
 +                <ul class="dropdown-menu" role="menu">
                      <li><a href="#"><i class="iconf-folder-open-alt"></i> Open</a></li>
 +                    <li><a href="#"><i class="iconf-plus-sign"></i> Add links</a></li>
                      <li><a href="#"><i class="iconf-edit"></i> Details</a></li>
                      <li><a href="#"><i class="iconf-trash"></i> Delete</a></li>
                      <li><a href="#"><i class="iconf-refresh"></i> Recheck</a></li>
                      <li class="divider"></li>
 -                    <li><a>Addons</a></li>
 +                    <li class="dropdown-submenu">
 +                        <a>Addons</a>
 +                        <ul class="dropdown-menu">
 +                            <li><a>Test</a></li>
 +                        </ul>
 +                    </li>
                  </ul>
              </div>
              <div class="progress">
 @@ -60,8 +66,7 @@      <script type="text/template" id="template-file">
          <div class="file-row first">
 -            <i class="checkbox"></i>
 -            <i class="iconf-file-alt"></i> 
 +            <i class="checkbox"></i> 
              <span class="name">
              <% name %>
              </span>
 @@ -84,13 +89,18 @@                      <img src="icons/<% download.plugin %>"/>
                      <% download.plugin %> 
                      <i class="iconf-chevron-down" data-toggle="dropdown"></i>
 -                    <ul class="dropdown-menu">
 +                    <ul class="dropdown-menu" role="menu">
                          <li><a href="#"><i class="iconf-trash"></i> Delete</a></li>
                          <li><a href="#"><i class="iconf-refresh"></i> Restart</a></li>
                          <li><a href="#"><i class="iconf-download"></i> Download</a></li>
                          <li><a href="#"><i class="iconf-share"></i> Share</a></li>
                          <li class="divider"></li>
 -                        <li><a>Addons</a></li>
 +                        <li class="dropdown-submenu pull-left">
 +                            <a>Addons</a>
 +                            <ul class="dropdown-menu">
 +                                <li><a>Test</a></li>
 +                            </ul>
 +                        </li>
                      </ul>
                  </div>
      </script>
 @@ -132,33 +142,35 @@              <a href="#"><i class="iconf-check-empty btn-check"></i></a>
          </li>
          <li class="dropdown" style="float: right;">
 -            <a class="dropdown-toggle"
 +            <a class="dropdown-toggle type"
                 data-toggle="dropdown"
                 href="#">
                  Type
                  <b class="caret"></b>
              </a>
              <ul class="dropdown-menu">
 -                <li><a><i class="icon-ok"></i> Audio</a></li>
 -                <li><a><i class="icon-ok"></i> Image</a></li>
 -                <li><a><i class="icon-ok"></i> Video</a></li>
 -                <li><a><i class="icon-ok"></i> Document</a></li>
 -                <li><a><i class="icon-remove"></i> Archive</a></li>
 -                <li><a><i class="icon-remove"></i> Other</a></li>
 +                <li><a class="filter-type" data-type="2" href="#"><i class="icon-ok"></i> Audio</a></li>
 +                <li><a class="filter-type" data-type="4" href="#"><i class="icon-ok"></i> Image</a></li>
 +                <li><a class="filter-type" data-type="8" href="#"><i class="icon-ok"></i> Video</a></li>
 +                <li><a class="filter-type" data-type="16" href="#"><i class="icon-ok"></i> Document</a></li>
 +                <li><a class="filter-type" data-type="32" href="#"><i class="icon-remove"></i> Archive</a></li>
 +                <li><a class="filter-type" data-type="1" href="#"><i class="icon-remove"></i> Other</a></li>
              </ul>
          </li>
          <li class="dropdown" style="float: right;">
              <a class="dropdown-toggle"
                 data-toggle="dropdown"
                 href="#">
 -                All
 +                <span class="state">
 +                    All
 +                </span>
                  <b class="caret"></b>
              </a>
              <ul class="dropdown-menu">
 -                <li><a>All</a></li>
 -                <li><a>Finished</a></li>
 -                <li><a>Unfinished</a></li>
 -                <li><a>Failed</a></li>
 +                <li><a class="filter-state" data-state="0" href="#">All</a></li>
 +                <li><a class="filter-state" data-state="1" href="#">Finished</a></li>
 +                <li><a class="filter-state" data-state="2" href="#">Unfinished</a></li>
 +                <li><a class="filter-state" data-state="3" href="#">Failed</a></li>
              </ul>
          </li>
      </ul>
  | 
