summaryrefslogtreecommitdiffstats
path: root/module/web/static/js/libs/lodash-0.4.2.js
diff options
context:
space:
mode:
Diffstat (limited to 'module/web/static/js/libs/lodash-0.4.2.js')
-rw-r--r--module/web/static/js/libs/lodash-0.4.2.js3803
1 files changed, 3803 insertions, 0 deletions
diff --git a/module/web/static/js/libs/lodash-0.4.2.js b/module/web/static/js/libs/lodash-0.4.2.js
new file mode 100644
index 000000000..67806db05
--- /dev/null
+++ b/module/web/static/js/libs/lodash-0.4.2.js
@@ -0,0 +1,3803 @@
+/*!
+ * Lo-Dash v0.4.2 <http://lodash.com>
+ * Copyright 2012 John-David Dalton <http://allyoucanleet.com/>
+ * Based on Underscore.js 1.3.3, copyright 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
+ * <http://documentcloud.github.com/underscore>
+ * Available under MIT license <http://lodash.com/license>
+ */
+;(function(window, undefined) {
+ 'use strict';
+
+ /**
+ * Used to cache the last `_.templateSettings.evaluate` delimiter to avoid
+ * unnecessarily assigning `reEvaluateDelimiter` a new generated regexp.
+ * Assigned in `_.template`.
+ */
+ var lastEvaluateDelimiter;
+
+ /**
+ * Used to cache the last template `options.variable` to avoid unnecessarily
+ * assigning `reDoubleVariable` a new generated regexp. Assigned in `_.template`.
+ */
+ var lastVariable;
+
+ /**
+ * Used to match potentially incorrect data object references, like `obj.obj`,
+ * in compiled templates. Assigned in `_.template`.
+ */
+ var reDoubleVariable;
+
+ /**
+ * Used to match "evaluate" delimiters, including internal delimiters,
+ * in template text. Assigned in `_.template`.
+ */
+ var reEvaluateDelimiter;
+
+ /** Detect free variable `exports` */
+ var freeExports = typeof exports == 'object' && exports &&
+ (typeof global == 'object' && global && global == global.global && (window = global), exports);
+
+ /** Native prototype shortcuts */
+ var ArrayProto = Array.prototype,
+ ObjectProto = Object.prototype;
+
+ /** Used to generate unique IDs */
+ var idCounter = 0;
+
+ /** Used to restore the original `_` reference in `noConflict` */
+ var oldDash = window._;
+
+ /** Used to detect delimiter values that should be processed by `tokenizeEvaluate` */
+ var reComplexDelimiter = /[-+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/;
+
+ /** 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 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('^' +
+ (ObjectProto.valueOf + '')
+ .replace(/[.*+?^=!:${}()|[\]\/\\]/g, '\\$&')
+ .replace(/valueOf|for [^\]]+/g, '.+?') + '$'
+ );
+
+ /** Used to match tokens in template text */
+ var reToken = /__token__(\d+)/g;
+
+ /** Used to match unescaped characters in strings for inclusion in HTML */
+ 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;
+
+ /** Used to replace template delimiters */
+ var token = '__token__';
+
+ /** Used to store tokenized template text snippets */
+ var tokenized = [];
+
+ /** Native method shortcuts */
+ var concat = ArrayProto.concat,
+ hasOwnProperty = ObjectProto.hasOwnProperty,
+ push = ArrayProto.push,
+ propertyIsEnumerable = ObjectProto.propertyIsEnumerable,
+ slice = ArrayProto.slice,
+ toString = ObjectProto.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,
+ nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys;
+
+ /** `Object#toString` result shortcuts */
+ var arrayClass = '[object Array]',
+ boolClass = '[object Boolean]',
+ dateClass = '[object Date]',
+ funcClass = '[object Function]',
+ numberClass = '[object Number]',
+ regexpClass = '[object RegExp]',
+ stringClass = '[object String]';
+
+ /** Timer shortcuts */
+ var clearTimeout = window.clearTimeout,
+ setTimeout = window.setTimeout;
+
+ /**
+ * Detect the JScript [[DontEnum]] bug:
+ * In IE < 9 an objects own properties, shadowing non-enumerable ones, are
+ * made non-enumerable as well.
+ */
+ var hasDontEnumBug = !propertyIsEnumerable.call({ 'valueOf': 0 }, 'valueOf');
+
+ /** Detect if `Array#slice` cannot be used to convert strings to arrays (Opera < 10.52) */
+ var noArraySliceOnStrings = slice.call('x')[0] != 'x';
+
+ /**
+ * 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 `Function#bind` exists and is inferred to be fast (all but V8) */
+ var isBindFast = nativeBind && /\n|Opera/.test(nativeBind + toString.call(window.opera));
+
+ /* Detect if `Object.keys` exists and is inferred to be fast (V8, Opera, IE) */
+ var isKeysFast = nativeKeys && /^.+$|true/.test(nativeKeys + !!window.attachEvent);
+
+ /** Detect if sourceURL syntax is usable without erroring */
+ try {
+ // Adobe's and Narwhal's JS engines will error
+ var useSourceURL = (Function('//@')(), true);
+ } catch(e){ }
+
+ /**
+ * Used to escape characters for inclusion in HTML.
+ * The `>` and `/` characters 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 (semi-related fun fact)
+ */
+ var htmlEscapes = {
+ '&': '&amp;',
+ '<': '&lt;',
+ '"': '&quot;',
+ "'": '&#x27;'
+ };
+
+ /** 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'
+ };
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * The `lodash` function.
+ *
+ * @name _
+ * @constructor
+ * @param {Mixed} value The value to wrap in a `LoDash` instance.
+ * @returns {Object} Returns a `LoDash` instance.
+ */
+ function lodash(value) {
+ // allow invoking `lodash` without the `new` operator
+ return new LoDash(value);
+ }
+
+ /**
+ * Creates a `LoDash` instance that wraps a value to allow chaining.
+ *
+ * @private
+ * @constructor
+ * @param {Mixed} value The value to wrap.
+ */
+ function LoDash(value) {
+ // exit early if already wrapped
+ if (value && value._wrapped) {
+ return value;
+ }
+ this._wrapped = value;
+ }
+
+ /**
+ * By default, Lo-Dash uses embedded Ruby (ERB) style template delimiters,
+ * 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': /<%=([\s\S]+?)%>/g,
+
+ /**
+ * Used to reference the data object in the template text.
+ *
+ * @static
+ * @memberOf _.templateSettings
+ * @type String
+ */
+ 'variable': 'obj'
+ };
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * 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 (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<% if (init) { %> = <%= init %><% } %>;\n' +
+ // add code to exit early or do so if the first argument is falsey
+ '<%= exit %>;\n' +
+ // add code after the exit snippet but before the iteration branches
+ '<%= top %>;\n' +
+
+ // the following branch is for iterating arrays and array-like objects
+ '<% if (arrayBranch) { %>' +
+ 'var length = iteratee.length; index = -1;' +
+ ' <% if (objectBranch) { %>\nif (length === length >>> 0) {<% } %>' +
+
+ // add support for accessing string characters by index if needed
+ ' <% if (noCharByIndex) { %>\n' +
+ ' if (toString.call(iteratee) == stringClass) {\n' +
+ ' iteratee = iteratee.split(\'\')\n' +
+ ' }' +
+ ' <% } %>\n' +
+
+ ' <%= arrayBranch.beforeLoop %>;\n' +
+ ' while (++index < length) {\n' +
+ ' <%= arrayBranch.inLoop %>\n' +
+ ' }' +
+ ' <% if (objectBranch) { %>\n}<% } %>' +
+ '<% } %>' +
+
+ // the following branch is for iterating an object's own/inherited properties
+ '<% if (objectBranch) { %>' +
+ ' <% if (arrayBranch) { %>\nelse {<% } %>' +
+ ' <% 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 props = nativeKeys(iteratee),\n' +
+ ' propIndex = -1,\n' +
+ ' length = props.length;\n\n' +
+ ' <%= objectBranch.beforeLoop %>;\n' +
+ ' while (++propIndex < length) {\n' +
+ ' index = props[propIndex];\n' +
+ ' if (!(skipProto && index == \'prototype\')) {\n' +
+ ' <%= objectBranch.inLoop %>\n' +
+ ' }\n' +
+ ' }' +
+
+ // else using a for-in loop
+ ' <% } else { %>\n' +
+ ' <%= objectBranch.beforeLoop %>;\n' +
+ ' for (index in iteratee) {' +
+ ' <% if (hasDontEnumBug) { %>\n' +
+ ' <% if (useHas) { %>if (hasOwnProperty.call(iteratee, index)) {\n <% } %>' +
+ ' <%= objectBranch.inLoop %>;\n' +
+ ' <% if (useHas) { %>}<% } %>' +
+ ' <% } else { %>\n' +
+
+ // 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 (!(skipProto && index == \'prototype\')<% if (useHas) { %> &&\n' +
+ ' hasOwnProperty.call(iteratee, index)<% } %>) {\n' +
+ ' <%= objectBranch.inLoop %>\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' +
+ ' <%= objectBranch.inLoop %>\n' +
+ ' }' +
+ ' <% } %>' +
+ ' <% } %>' +
+ ' <% if (arrayBranch) { %>\n}<% } %>' +
+ '<% } %>\n' +
+
+ // add code to the bottom of the iteration function
+ '<%= bottom %>;\n' +
+ // finally, return the `result`
+ 'return result'
+ );
+
+ /**
+ * Reusable iterator options shared by
+ * `every`, `filter`, `find`, `forEach`, `forIn`, `forOwn`, `groupBy`, `map`,
+ * `reject`, `some`, and `sortBy`.
+ */
+ var baseIteratorOptions = {
+ 'args': 'collection, callback, thisArg',
+ 'init': 'collection',
+ 'top':
+ 'if (!callback) {\n' +
+ ' callback = identity\n' +
+ '}\n' +
+ 'else if (thisArg) {\n' +
+ ' callback = iteratorBind(callback, thisArg)\n' +
+ '}',
+ 'inLoop': 'callback(iteratee[index], index, collection)'
+ };
+
+ /** Reusable iterator options for `every` and `some` */
+ var everyIteratorOptions = {
+ 'init': 'true',
+ 'inLoop': 'if (!callback(iteratee[index], index, collection)) return !result'
+ };
+
+ /** Reusable iterator options for `defaults` and `extend` */
+ var extendIteratorOptions = {
+ 'useHas': false,
+ 'useStrict': false,
+ 'args': 'object',
+ 'init': 'object',
+ 'top':
+ 'for (var iterateeIndex = 1, length = arguments.length; iterateeIndex < length; iterateeIndex++) {\n' +
+ ' iteratee = arguments[iterateeIndex];\n' +
+ (hasDontEnumBug ? ' if (iteratee) {' : ''),
+ 'inLoop': 'result[index] = iteratee[index]',
+ 'bottom': (hasDontEnumBug ? ' }\n' : '') + '}'
+ };
+
+ /** Reusable iterator options for `filter` and `reject` */
+ var filterIteratorOptions = {
+ 'init': '[]',
+ 'inLoop': 'callback(iteratee[index], index, collection) && result.push(iteratee[index])'
+ };
+
+ /** Reusable iterator options for `find`, `forEach`, `forIn`, and `forOwn` */
+ var forEachIteratorOptions = {
+ 'top': 'if (thisArg) callback = iteratorBind(callback, thisArg)'
+ };
+
+ /** Reusable iterator options for `forIn` and `forOwn` */
+ var forOwnIteratorOptions = {
+ 'inLoop': {
+ 'object': baseIteratorOptions.inLoop
+ }
+ };
+
+ /** Reusable iterator options for `invoke`, `map`, `pluck`, and `sortBy` */
+ var mapIteratorOptions = {
+ 'init': '',
+ 'exit': 'if (!collection) return []',
+ 'beforeLoop': {
+ 'array': 'result = Array(length)',
+ 'object': 'result = ' + (isKeysFast ? 'Array(length)' : '[]')
+ },
+ 'inLoop': {
+ 'array': 'result[index] = callback(iteratee[index], index, collection)',
+ 'object': 'result' + (isKeysFast ? '[propIndex] = ' : '.push') + '(callback(iteratee[index], index, collection))'
+ }
+ };
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Creates a new function optimized for searching 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 start searching 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 || 30),
+ cache = isLarge ? {} : array;
+
+ if (isLarge) {
+ // init value cache
+ var key,
+ index = fromIndex - 1;
+
+ while (++index < length) {
+ // manually coerce `value` to string because `hasOwnProperty`, in some
+ // older versions of Firefox, coerces objects incorrectly
+ 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(cache, value, fromIndex) > -1;
+ }
+ }
+
+ /**
+ * Creates compiled iteration functions. The iteration function will be created
+ * to iterate over only objects if the first argument of `options.args` is
+ * "object" or `options.inLoop.array` is falsey.
+ *
+ * @private
+ * @param {Object} [options1, options2, ...] The compile options objects.
+ *
+ * useHas - A boolean to specify whether or not to use `hasOwnProperty` checks
+ * in the object loop.
+ *
+ * useStrict - A boolean to specify whether or not to include the ES5
+ * "use strict" directive.
+ *
+ * args - A string of comma separated arguments the iteration function will
+ * accept.
+ *
+ * init - A string to specify the initial value of the `result` variable.
+ *
+ * exit - A string of code to use in place of the default exit-early check
+ * of `if (!arguments[0]) return result`.
+ *
+ * top - A string of code to execute after the exit-early check but before
+ * the iteration branches.
+ *
+ * beforeLoop - A string or object containing an "array" or "object" property
+ * of code to execute before the array or object loops.
+ *
+ * inLoop - A string or object containing an "array" or "object" property
+ * of code to execute in the array or object loops.
+ *
+ * bottom - A string of code to execute after the iteration branches but
+ * before the `result` is returned.
+ *
+ * @returns {Function} Returns the compiled function.
+ */
+ function createIterator() {
+ var object,
+ prop,
+ value,
+ index = -1,
+ length = arguments.length;
+
+ // merge options into a template data object
+ var data = {
+ 'bottom': '',
+ 'exit': '',
+ 'init': '',
+ 'top': '',
+ 'arrayBranch': { 'beforeLoop': '' },
+ 'objectBranch': { 'beforeLoop': '' }
+ };
+
+ while (++index < length) {
+ object = arguments[index];
+ for (prop in object) {
+ value = (value = object[prop]) == null ? '' : value;
+ // keep this regexp explicit for the build pre-process
+ if (/beforeLoop|inLoop/.test(prop)) {
+ if (typeof value == 'string') {
+ value = { 'array': value, 'object': value };
+ }
+ data.arrayBranch[prop] = value.array;
+ data.objectBranch[prop] = value.object;
+ } else {
+ data[prop] = value;
+ }
+ }
+ }
+ // set additional template `data` values
+ var args = data.args,
+ firstArg = /^[^,]+/.exec(args)[0];
+
+ data.firstArg = firstArg;
+ data.hasDontEnumBug = hasDontEnumBug;
+ data.isKeysFast = isKeysFast;
+ data.shadowed = shadowed;
+ data.useHas = data.useHas !== false;
+ data.useStrict = data.useStrict !== false;
+
+ if (!('noCharByIndex' in data)) {
+ data.noCharByIndex = noCharByIndex;
+ }
+ if (!data.exit) {
+ data.exit = 'if (!' + firstArg + ') return result';
+ }
+ if (firstArg != 'collection' || !data.arrayBranch.inLoop) {
+ data.arrayBranch = null;
+ }
+ // create the function factory
+ var factory = Function(
+ 'arrayClass, bind, compareAscending, funcClass, hasOwnProperty, identity, ' +
+ 'iteratorBind, objectTypes, nativeKeys, propertyIsEnumerable, slice, ' +
+ 'stringClass, toString',
+ 'return function(' + args + ') {\n' + iteratorTemplate(data) + '\n}'
+ );
+ // return the compiled function
+ return factory(
+ arrayClass, bind, compareAscending, funcClass, hasOwnProperty, identity,
+ iteratorBind, objectTypes, nativeKeys, propertyIsEnumerable, slice,
+ stringClass, toString
+ );
+ }
+
+ /**
+ * Used by `sortBy` to compare transformed values of `collection`, 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 `-1` if `a` < `b`, `0` if `a` == `b`, or `1` if `a` > `b`.
+ */
+ function compareAscending(a, b) {
+ a = a.criteria;
+ b = b.criteria;
+
+ if (a === undefined) {
+ return 1;
+ }
+ if (b === undefined) {
+ return -1;
+ }
+ return a < b ? -1 : a > b ? 1 : 0;
+ }
+
+ /**
+ * Used by `template` to replace tokens with their corresponding code snippets.
+ *
+ * @private
+ * @param {String} match The matched token.
+ * @param {String} index The `tokenized` index of the code snippet.
+ * @returns {String} Returns the code snippet.
+ */
+ function detokenize(match, index) {
+ return tokenized[index];
+ }
+
+ /**
+ * 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 escape characters for inclusion in HTML.
+ *
+ * @private
+ * @param {String} match The matched character to escape.
+ * @returns {String} Returns the escaped character.
+ */
+ function escapeHtmlChar(match) {
+ return htmlEscapes[match];
+ }
+
+ /**
+ * Creates a new function that, when called, invokes `func` with the `this`
+ * binding of `thisArg` and the arguments (value, index, object).
+ *
+ * @private
+ * @param {Function} func The function to bind.
+ * @param {Mixed} [thisArg] The `this` binding of `func`.
+ * @returns {Function} Returns the new bound function.
+ */
+ function iteratorBind(func, thisArg) {
+ return function(value, index, object) {
+ return func.call(thisArg, value, index, object);
+ };
+ }
+
+ /**
+ * A no-operation function.
+ *
+ * @private
+ */
+ function noop() {
+ // no operation performed
+ }
+
+ /**
+ * A shim 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.
+ */
+ var shimKeys = createIterator({
+ 'args': 'object',
+ 'exit': 'if (!(object && objectTypes[typeof object])) throw TypeError()',
+ 'init': '[]',
+ 'inLoop': 'result.push(index)'
+ });
+
+ /**
+ * Used by `template` to replace "escape" template delimiters with tokens.
+ *
+ * @private
+ * @param {String} match The matched template delimiter.
+ * @param {String} value The delimiter value.
+ * @returns {String} Returns a token.
+ */
+ function tokenizeEscape(match, value) {
+ if (reComplexDelimiter.test(value)) {
+ return '<e%-' + value + '%>';
+ }
+ var index = tokenized.length;
+ tokenized[index] = "' +\n__e(" + value + ") +\n'";
+ return token + index;
+ }
+
+ /**
+ * Used by `template` to replace "evaluate" template delimiters, or complex
+ * "escape" and "interpolate" delimiters, with tokens.
+ *
+ * @private
+ * @param {String} match The matched template delimiter.
+ * @param {String} value The delimiter value.
+ * @param {String} escapeValue The "escape" delimiter value.
+ * @param {String} interpolateValue The "interpolate" delimiter value.
+ * @returns {String} Returns a token.
+ */
+ function tokenizeEvaluate(match, value, escapeValue, interpolateValue) {
+ var index = tokenized.length;
+ if (value) {
+ tokenized[index] = "';\n" + value + ";\n__p += '"
+ } else if (escapeValue) {
+ tokenized[index] = "' +\n__e(" + escapeValue + ") +\n'";
+ } else if (interpolateValue) {
+ tokenized[index] = "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
+ }
+ return token + index;
+ }
+
+ /**
+ * Used by `template` to replace "interpolate" template delimiters with tokens.
+ *
+ * @private
+ * @param {String} match The matched template delimiter.
+ * @param {String} value The delimiter value.
+ * @returns {String} Returns a token.
+ */
+ function tokenizeInterpolate(match, value) {
+ if (reComplexDelimiter.test(value)) {
+ return '<e%=' + value + '%>';
+ }
+ var index = tokenized.length;
+ tokenized[index] = "' +\n((__t = (" + value + ")) == null ? '' : __t) +\n'";
+ return token + index;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Checks if a given `target` value is present in a `collection` using strict
+ * equality for comparisons, i.e. `===`.
+ *
+ * @static
+ * @memberOf _
+ * @alias include
+ * @category Collections
+ * @param {Array|Object|String} collection The collection to iterate over.
+ * @param {Mixed} target The value to check for.
+ * @returns {Boolean} Returns `true` if `target` value is found, else `false`.
+ * @example
+ *
+ * _.contains([1, 2, 3], 3);
+ * // => true
+ *
+ * _.contains({ 'name': 'moe', 'age': 40 }, 'moe');
+ * // => true
+ *
+ * _.contains('curly', 'ur');
+ * // => true
+ */
+ var contains = createIterator({
+ 'args': 'collection, target',
+ 'init': 'false',
+ 'noCharByIndex': false,
+ 'beforeLoop': {
+ 'array': 'if (toString.call(iteratee) == stringClass) return collection.indexOf(target) > -1'
+ },
+ 'inLoop': 'if (iteratee[index] === target) return true'
+ });
+
+ /**
+ * Checks if the `callback` returns a truthy value for **all** elements of a
+ * `collection`. The `callback` is bound to `thisArg` and invoked with 3
+ * 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 for the callback.
+ * @returns {Boolean} Returns `true` if all values pass the callback check, else `false`.
+ * @example
+ *
+ * _.every([true, 1, null, 'yes'], Boolean);
+ * // => false
+ */
+ var every = createIterator(baseIteratorOptions, everyIteratorOptions);
+
+ /**
+ * Examines each value in a `collection`, returning an array of all values the
+ * `callback` returns truthy for. The `callback` is bound to `thisArg` and
+ * invoked with 3 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 for the callback.
+ * @returns {Array} Returns a new array of values that passed callback check.
+ * @example
+ *
+ * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
+ * // => [2, 4, 6]
+ */
+ var filter = createIterator(baseIteratorOptions, filterIteratorOptions);
+
+ /**
+ * Examines each value in a `collection`, returning the first one the `callback`
+ * returns truthy for. The function returns as soon as it finds an acceptable
+ * value, and does not iterate over the entire `collection`. The `callback` is
+ * bound to `thisArg` and invoked with 3 arguments; (value, index|key, collection).
+ *
+ * @static
+ * @memberOf _
+ * @alias detect
+ * @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 for the callback.
+ * @returns {Mixed} Returns the value 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 find = createIterator(baseIteratorOptions, forEachIteratorOptions, {
+ 'init': '',
+ 'inLoop': 'if (callback(iteratee[index], index, collection)) return iteratee[index]'
+ });
+
+ /**
+ * Iterates over a `collection`, executing the `callback` for each value in the
+ * `collection`. The `callback` is bound to `thisArg` and invoked with 3
+ * arguments; (value, index|key, collection).
+ *
+ * @static
+ * @memberOf _
+ * @alias each
+ * @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 for the callback.
+ * @returns {Array|Object} Returns the `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 (order is not guaranteed)
+ */
+ var forEach = createIterator(baseIteratorOptions, forEachIteratorOptions);
+
+ /**
+ * Splits `collection` into sets, grouped by the result of running each value
+ * through `callback`. The `callback` is bound to `thisArg` and invoked with
+ * 3 arguments; (value, index|key, collection). The `callback` argument may
+ * also be the name of a property to group by.
+ *
+ * @static
+ * @memberOf _
+ * @category Collections
+ * @param {Array|Object|String} collection The collection to iterate over.
+ * @param {Function|String} callback The function called per iteration or
+ * property name to group by.
+ * @param {Mixed} [thisArg] The `this` binding for the callback.
+ * @returns {Object} Returns an object of grouped values.
+ * @example
+ *
+ * _.groupBy([1.3, 2.1, 2.4], function(num) { return Math.floor(num); });
+ * // => { '1': [1.3], '2': [2.1, 2.4] }
+ *
+ * _.groupBy([1.3, 2.1, 2.4], function(num) { return this.floor(num); }, Math);
+ * // => { '1': [1.3], '2': [2.1, 2.4] }
+ *
+ * _.groupBy(['one', 'two', 'three'], 'length');
+ * // => { '3': ['one', 'two'], '5': ['three'] }
+ */
+ var groupBy = createIterator(baseIteratorOptions, {
+ 'init': '{}',
+ 'top':
+ 'var prop, isFunc = typeof callback == \'function\';\n' +
+ 'if (isFunc && thisArg) callback = iteratorBind(callback, thisArg)',
+ 'inLoop':
+ 'prop = isFunc\n' +
+ ' ? callback(iteratee[index], index, collection)\n' +
+ ' : iteratee[index][callback];\n' +
+ '(hasOwnProperty.call(result, prop) ? result[prop] : result[prop] = []).push(iteratee[index])'
+ });
+
+ /**
+ * Invokes the method named by `methodName` on each element in the `collection`.
+ * 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 values returned from 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']]
+ */
+ var invoke = createIterator(mapIteratorOptions, {
+ 'args': 'collection, methodName',
+ 'top':
+ 'var args = slice.call(arguments, 2),\n' +
+ ' isFunc = typeof methodName == \'function\'',
+ 'inLoop': {
+ 'array':
+ 'result[index] = (isFunc ? methodName : iteratee[index][methodName])' +
+ '.apply(iteratee[index], args)',
+ 'object':
+ 'result' + (isKeysFast ? '[propIndex] = ' : '.push') +
+ '((isFunc ? methodName : iteratee[index][methodName]).apply(iteratee[index], args))'
+ }
+ });
+
+ /**
+ * Produces a new array of values by mapping each element in the `collection`
+ * through a transformation `callback`. The `callback` is bound to `thisArg`
+ * and invoked with 3 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 for the callback.
+ * @returns {Array} Returns a new array of values returned by the callback.
+ * @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 map = createIterator(baseIteratorOptions, mapIteratorOptions);
+
+ /**
+ * 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']
+ */
+ var pluck = createIterator(mapIteratorOptions, {
+ 'args': 'collection, property',
+ 'inLoop': {
+ 'array': 'result[index] = iteratee[index][property]',
+ 'object': 'result' + (isKeysFast ? '[propIndex] = ' : '.push') + '(iteratee[index][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 The function called per iteration.
+ * @param {Mixed} [accumulator] Initial value of the accumulator.
+ * @param {Mixed} [thisArg] The `this` binding for the callback.
+ * @returns {Mixed} Returns the accumulated value.
+ * @example
+ *
+ * var sum = _.reduce([1, 2, 3], function(memo, num) { return memo + num; });
+ * // => 6
+ */
+ var reduce = createIterator({
+ 'args': 'collection, callback, accumulator, thisArg',
+ 'init': 'accumulator',
+ 'top':
+ 'var noaccum = arguments.length < 3;\n' +
+ 'if (thisArg) callback = iteratorBind(callback, thisArg)',
+ 'beforeLoop': {
+ 'array': 'if (noaccum) result = collection[++index]'
+ },
+ 'inLoop': {
+ 'array':
+ 'result = callback(result, iteratee[index], index, collection)',
+ 'object':
+ 'result = noaccum\n' +
+ ' ? (noaccum = false, iteratee[index])\n' +
+ ' : callback(result, iteratee[index], index, collection)'
+ }
+ });
+
+ /**
+ * 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 The function called per iteration.
+ * @param {Mixed} [accumulator] Initial value of the accumulator.
+ * @param {Mixed} [thisArg] The `this` binding for the 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) {
+ if (!collection) {
+ return accumulator;
+ }
+
+ var length = collection.length,
+ noaccum = arguments.length < 3;
+
+ if(thisArg) {
+ callback = iteratorBind(callback, thisArg);
+ }
+ if (length === length >>> 0) {
+ var iteratee = noCharByIndex && toString.call(collection) == stringClass
+ ? collection.split('')
+ : collection;
+
+ if (length && noaccum) {
+ accumulator = iteratee[--length];
+ }
+ while (length--) {
+ accumulator = callback(accumulator, iteratee[length], length, collection);
+ }
+ return accumulator;
+ }
+
+ var prop,
+ props = keys(collection);
+
+ length = props.length;
+ if (length && noaccum) {
+ accumulator = collection[props[--length]];
+ }
+ while (length--) {
+ prop = props[length];
+ accumulator = callback(accumulator, collection[prop], prop, 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 for the callback.
+ * @returns {Array} Returns a new array of values 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 reject = createIterator(baseIteratorOptions, filterIteratorOptions, {
+ 'inLoop': '!' + filterIteratorOptions.inLoop
+ });
+
+ /**
+ * 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 3 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 for the callback.
+ * @returns {Boolean} Returns `true` if any value passes the callback check, else `false`.
+ * @example
+ *
+ * _.some([null, 0, 'yes', false]);
+ * // => true
+ */
+ var some = createIterator(baseIteratorOptions, everyIteratorOptions, {
+ 'init': 'false',
+ 'inLoop': everyIteratorOptions.inLoop.replace('!', '')
+ });
+
+
+ /**
+ * Produces a new sorted array, sorted in ascending order by the results of
+ * running each element of `collection` through a transformation `callback`.
+ * The `callback` is bound to `thisArg` and invoked with 3 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 The function called per iteration or
+ * property name to sort by.
+ * @param {Mixed} [thisArg] The `this` binding for the callback.
+ * @returns {Array} Returns a new array of sorted values.
+ * @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']
+ */
+ var sortBy = createIterator(baseIteratorOptions, mapIteratorOptions, {
+ 'top':
+ 'if (typeof callback == \'string\') {\n' +
+ ' var prop = callback;\n' +
+ ' callback = function(collection) { return collection[prop] }\n' +
+ '}\n' +
+ 'else if (thisArg) {\n' +
+ ' callback = iteratorBind(callback, thisArg)\n' +
+ '}',
+ 'inLoop': {
+ 'array':
+ 'result[index] = {\n' +
+ ' criteria: callback(iteratee[index], index, collection),\n' +
+ ' value: iteratee[index]\n' +
+ '}',
+ 'object':
+ 'result' + (isKeysFast ? '[propIndex] = ' : '.push') + '({\n' +
+ ' criteria: callback(iteratee[index], index, collection),\n' +
+ ' value: iteratee[index]\n' +
+ '})'
+ },
+ 'bottom':
+ 'result.sort(compareAscending);\n' +
+ 'length = result.length;\n' +
+ 'while (length--) {\n' +
+ ' result[length] = result[length].value\n' +
+ '}'
+ });
+
+ /**
+ * Converts the `collection`, into an array. Useful for converting the
+ * `arguments` object.
+ *
+ * @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) {
+ return [];
+ }
+ if (collection.toArray && toString.call(collection.toArray) == funcClass) {
+ return collection.toArray();
+ }
+ var length = collection.length;
+ if (length === length >>> 0) {
+ return (noArraySliceOnStrings ? toString.call(collection) == stringClass : typeof collection == 'string')
+ ? collection.split('')
+ : slice.call(collection);
+ }
+ return values(collection);
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Produces a new 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 result = [];
+ if (!array) {
+ return result;
+ }
+ var index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ if (array[index]) {
+ result.push(array[index]);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Produces a new array of `array` values 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` values not present in the
+ * other arrays.
+ * @example
+ *
+ * _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
+ * // => [1, 3, 4]
+ */
+ function difference(array) {
+ var result = [];
+ if (!array) {
+ return result;
+ }
+ var index = -1,
+ length = array.length,
+ flattened = concat.apply(result, arguments),
+ contains = cachedContains(flattened, length);
+
+ while (++index < length) {
+ if (!contains(array[index])) {
+ result.push(array[index]);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets the first value of the `array`. Pass `n` to return the first `n` values
+ * 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 value or an array of the first `n` values
+ * of `array`.
+ * @example
+ *
+ * _.first([5, 4, 3, 2, 1]);
+ * // => 5
+ */
+ function first(array, n, guard) {
+ if (array) {
+ return (n == null || guard) ? array[0] : slice.call(array, 0, n);
+ }
+ }
+
+ /**
+ * 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 result = [];
+ if (!array) {
+ return result;
+ }
+ var value,
+ index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ value = array[index];
+ 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 `isSorted` 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 start searching 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) {
+ if (!array) {
+ return -1;
+ }
+ var index = -1,
+ length = array.length;
+
+ if (fromIndex) {
+ if (typeof fromIndex == 'number') {
+ index = (fromIndex < 0 ? Math.max(0, length + fromIndex) : fromIndex) - 1;
+ } else {
+ 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 value of `array`. Pass `n` to exclude the last `n`
+ * values from the result.
+ *
+ * @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 {Array} Returns all but the last value or `n` values of `array`.
+ * @example
+ *
+ * _.initial([3, 2, 1]);
+ * // => [3, 2]
+ */
+ function initial(array, n, guard) {
+ if (!array) {
+ return [];
+ }
+ return slice.call(array, 0, -((n == null || guard) ? 1 : n));
+ }
+
+ /**
+ * Computes the intersection of all the passed-in arrays.
+ *
+ * @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 **all** of the arrays.
+ * @example
+ *
+ * _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
+ * // => [1, 2]
+ */
+ function intersection(array) {
+ var result = [];
+ if (!array) {
+ return result;
+ }
+ var value,
+ index = -1,
+ length = array.length,
+ others = slice.call(arguments, 1),
+ cache = [];
+
+ while (++index < length) {
+ value = array[index];
+ if (indexOf(result, value) < 0 &&
+ every(others, function(other, index) {
+ return (cache[index] || (cache[index] = cachedContains(other)))(value);
+ })) {
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets the last value of the `array`. Pass `n` to return the lasy `n` values
+ * 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 value or an array of the last `n` values
+ * 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.call(array, -n || length);
+ }
+ }
+
+ /**
+ * Gets the index at which the last occurrence of `value` is found using
+ * strict equality for comparisons, i.e. `===`.
+ *
+ * @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 start searching 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) {
+ if (!array) {
+ return -1;
+ }
+ var index = array.length;
+ if (fromIndex && typeof fromIndex == 'number') {
+ index = (fromIndex < 0 ? Math.max(0, index + fromIndex) : Math.min(fromIndex, index - 1)) + 1;
+ }
+ while (index--) {
+ if (array[index] === value) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * 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 3 arguments; (value, index, array).
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {Array} array The array to iterate over.
+ * @param {Function} [callback] The function called per iteration.
+ * @param {Mixed} [thisArg] The `this` binding for the 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(array, callback, thisArg) {
+ var computed = -Infinity,
+ result = computed;
+
+ if (!array) {
+ return result;
+ }
+ var current,
+ index = -1,
+ length = array.length;
+
+ if (!callback) {
+ while (++index < length) {
+ if (array[index] > result) {
+ result = array[index];
+ }
+ }
+ return result;
+ }
+ if (thisArg) {
+ callback = iteratorBind(callback, thisArg);
+ }
+ while (++index < length) {
+ current = callback(array[index], index, array);
+ if (current > computed) {
+ computed = current;
+ result = array[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 3 arguments; (value, index, array).
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {Array} array The array to iterate over.
+ * @param {Function} [callback] The function called per iteration.
+ * @param {Mixed} [thisArg] The `this` binding for the callback.
+ * @returns {Mixed} Returns the minimum value.
+ * @example
+ *
+ * _.min([10, 5, 100, 2, 1000]);
+ * // => 2
+ */
+ function min(array, callback, thisArg) {
+ var computed = Infinity,
+ result = computed;
+
+ if (!array) {
+ return result;
+ }
+ var current,
+ index = -1,
+ length = array.length;
+
+ if (!callback) {
+ while (++index < length) {
+ if (array[index] < result) {
+ result = array[index];
+ }
+ }
+ return result;
+ }
+ if (thisArg) {
+ callback = iteratorBind(callback, thisArg);
+ }
+ while (++index < length) {
+ current = callback(array[index], index, array);
+ if (current < computed) {
+ computed = current;
+ result = array[index];
+ }
+ }
+ 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) {
+ step || (step = 1);
+ if (end == null) {
+ end = start || 0;
+ start = 0;
+ }
+ // use `Array(length)` so V8 will avoid the slower "dictionary" mode
+ // http://www.youtube.com/watch?v=XAqIpGU8ZZk#t=16m27s
+ var index = -1,
+ length = Math.max(0, Math.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 tail
+ * @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 {Array} Returns all but the first value or `n` values of `array`.
+ * @example
+ *
+ * _.rest([3, 2, 1]);
+ * // => [2, 1]
+ */
+ function rest(array, n, guard) {
+ if (!array) {
+ return [];
+ }
+ return slice.call(array, (n == null || guard) ? 1 : n);
+ }
+
+ /**
+ * Produces a new 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 Arrays
+ * @param {Array} array The array to shuffle.
+ * @returns {Array} Returns a new shuffled array.
+ * @example
+ *
+ * _.shuffle([1, 2, 3, 4, 5, 6]);
+ * // => [4, 1, 6, 3, 5, 2]
+ */
+ function shuffle(array) {
+ if (!array) {
+ return [];
+ }
+ var rand,
+ index = -1,
+ length = array.length,
+ result = Array(length);
+
+ while (++index < length) {
+ rand = Math.floor(Math.random() * (index + 1));
+ result[index] = result[rand];
+ result[rand] = array[index];
+ }
+ return result;
+ }
+
+ /**
+ * 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 1 argument; (value).
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {Array} array The array to iterate over.
+ * @param {Mixed} value The value to evaluate.
+ * @param {Function} [callback=identity] The function called per iteration.
+ * @param {Mixed} [thisArg] The `this` binding for the callback.
+ * @returns {Number} Returns the index at which the value should be inserted
+ * into `array`.
+ * @example
+ *
+ * _.sortedIndex([20, 30, 40], 35);
+ * // => 2
+ *
+ * var dict = {
+ * 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'thirty-five': 35, 'fourty': 40 }
+ * };
+ *
+ * _.sortedIndex(['twenty', 'thirty', 'fourty'], 'thirty-five', function(word) {
+ * return dict.wordToNumber[word];
+ * });
+ * // => 2
+ *
+ * _.sortedIndex(['twenty', 'thirty', 'fourty'], 'thirty-five', function(word) {
+ * return this.wordToNumber[word];
+ * }, dict);
+ * // => 2
+ */
+ function sortedIndex(array, value, callback, thisArg) {
+ if (!array) {
+ return 0;
+ }
+ var mid,
+ low = 0,
+ high = array.length;
+
+ if (callback) {
+ if (thisArg) {
+ callback = bind(callback, thisArg);
+ }
+ value = callback(value);
+ while (low < high) {
+ mid = (low + high) >>> 1;
+ callback(array[mid]) < value ? low = mid + 1 : high = mid;
+ }
+ } else {
+ while (low < high) {
+ mid = (low + high) >>> 1;
+ array[mid] < value ? low = mid + 1 : high = mid;
+ }
+ }
+ return low;
+ }
+
+ /**
+ * Computes the union of the passed-in arrays.
+ *
+ * @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() {
+ var index = -1,
+ result = [],
+ flattened = concat.apply(result, arguments),
+ length = flattened.length;
+
+ while (++index < length) {
+ if (indexOf(result, flattened[index]) < 0) {
+ result.push(flattened[index]);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Produces 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 value of `array` is passed through a transformation `callback` before
+ * uniqueness is computed. The `callback` is bound to `thisArg` and invoked
+ * with 3 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 for the 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 result = [];
+ if (!array) {
+ return result;
+ }
+ var computed,
+ index = -1,
+ length = array.length,
+ seen = [];
+
+ // juggle arguments
+ if (typeof isSorted == 'function') {
+ thisArg = callback;
+ callback = isSorted;
+ isSorted = false;
+ }
+ if (!callback) {
+ callback = identity;
+ } else if (thisArg) {
+ callback = iteratorBind(callback, thisArg);
+ }
+ while (++index < length) {
+ computed = callback(array[index], index, array);
+ if (isSorted
+ ? !index || seen[seen.length - 1] !== computed
+ : indexOf(seen, computed) < 0
+ ) {
+ seen.push(computed);
+ result.push(array[index]);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Produces a new 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 result = [];
+ if (!array) {
+ return result;
+ }
+ var index = -1,
+ length = array.length,
+ contains = cachedContains(arguments, 1, 20);
+
+ while (++index < length) {
+ if (!contains(array[index])) {
+ result.push(array[index]);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Merges 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 merged arrays.
+ * @example
+ *
+ * _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
+ * // => [['moe', 30, true], ['larry', 40, false], ['curly', 50, false]]
+ */
+ function zip(array) {
+ if (!array) {
+ return [];
+ }
+ var index = -1,
+ length = max(pluck(arguments, 'length')),
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = pluck(arguments, index);
+ }
+ return result;
+ }
+
+ /**
+ * Merges an array of `keys` and an array of `values` into a single object.
+ *
+ * @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
+ *
+ * _.zipObject(['moe', 'larry', 'curly'], [30, 40, 50]);
+ * // => { 'moe': 30, 'larry': 40, 'curly': 50 }
+ */
+ function zipObject(keys, values) {
+ if (!keys) {
+ return {};
+ }
+ var index = -1,
+ length = keys.length,
+ result = {};
+
+ values || (values = []);
+ while (++index < length) {
+ result[keys[index]] = values[index];
+ }
+ return result;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Creates a new function that is restricted to executing only after it is
+ * called `n` times.
+ *
+ * @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 new 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. Lazy defined methods may be bound by passing
+ * the object they are bound to as `func` and the method name as `thisArg`.
+ *
+ * @static
+ * @memberOf _
+ * @category Functions
+ * @param {Function|Object} func The function to bind or the object the method belongs to.
+ * @param {Mixed} [thisArg] The `this` binding of `func` or the method name.
+ * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied.
+ * @returns {Function} Returns the new bound function.
+ * @example
+ *
+ * // basic bind
+ * var func = function(greeting) {
+ * return greeting + ' ' + this.name;
+ * };
+ *
+ * func = _.bind(func, { 'name': 'moe' }, 'hi');
+ * func();
+ * // => 'hi moe'
+ *
+ * // lazy bind
+ * var object = {
+ * 'name': 'moe',
+ * 'greet': function(greeting) {
+ * return greeting + ' ' + this.name;
+ * }
+ * };
+ *
+ * var func = _.bind(object, 'greet', 'hi');
+ * func();
+ * // => 'hi moe'
+ *
+ * object.greet = function(greeting) {
+ * return greeting + ', ' + this.name + '!';
+ * };
+ *
+ * func();
+ * // => 'hi, moe!'
+ */
+ function bind(func, thisArg) {
+ var methodName,
+ isFunc = toString.call(func) == funcClass;
+
+ // juggle arguments
+ if (!isFunc) {
+ methodName = thisArg;
+ thisArg = func;
+ }
+ // use `Function#bind` if it exists and is fast
+ // (in V8 `Function#bind` is slower except when partially applied)
+ else if (isBindFast || (nativeBind && arguments.length > 2)) {
+ return nativeBind.call.apply(nativeBind, arguments);
+ }
+
+ var partialArgs = slice.call(arguments, 2);
+
+ function bound() {
+ // `Function#bind` spec
+ // http://es5.github.com/#x15.3.4.5
+ var args = arguments,
+ thisBinding = thisArg;
+
+ if (!isFunc) {
+ func = thisArg[methodName];
+ }
+ if (partialArgs.length) {
+ args = args.length
+ ? concat.apply(partialArgs, args)
+ : partialArgs;
+ }
+ if (this instanceof bound) {
+ // get `func` instance if `bound` is invoked in a `new` expression
+ noop.prototype = func.prototype;
+ thisBinding = new noop;
+
+ // mimic the constructor's `return` behavior
+ // http://es5.github.com/#x13.2.2
+ var result = func.apply(thisBinding, args);
+ return result && objectTypes[typeof result]
+ ? result
+ : thisBinding
+ }
+ return func.apply(thisBinding, args);
+ }
+ return bound;
+ }
+
+ /**
+ * 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 the `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
+ */
+ var bindAll = createIterator({
+ 'useHas': false,
+ 'useStrict': false,
+ 'args': 'object',
+ 'init': 'object',
+ 'top':
+ 'var funcs = arguments,\n' +
+ ' length = funcs.length;\n' +
+ 'if (length > 1) {\n' +
+ ' for (var index = 1; index < length; index++)\n' +
+ ' result[funcs[index]] = bind(result[funcs[index]], result);\n' +
+ ' return result\n' +
+ '}',
+ 'inLoop':
+ 'if (toString.call(result[index]) == funcClass)' +
+ ' result[index] = bind(result[index], result)'
+ });
+
+ /**
+ * Creates a new 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()))`.
+ *
+ * @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 new 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) {
+ 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
+ * are 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.call(arguments, 2);
+ return setTimeout(function() { return func.apply(undefined, args); }, wait);
+ }
+
+ /**
+ * Defers executing the `func` function until the current call stack has cleared.
+ * Additional arguments are 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.call(arguments, 1);
+ return setTimeout(function() { return func.apply(undefined, args); }, 1);
+ }
+
+ /**
+ * Creates a new 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.
+ *
+ * @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 prop = resolver ? resolver.apply(this, arguments) : arguments[0];
+ return hasOwnProperty.call(cache, prop)
+ ? cache[prop]
+ : (cache[prop] = func.apply(this, arguments));
+ };
+ }
+
+ /**
+ * Creates a new function that is restricted to one execution. Repeat calls to
+ * the function will return the value of the first call.
+ *
+ * @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);
+ return result;
+ };
+ }
+
+ /**
+ * Creates a new function that, when called, invokes `func` with any additional
+ * `partial` arguments prepended to those passed to the partially applied
+ * function. This method is similar `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) {
+ var args = slice.call(arguments, 1),
+ argsLength = args.length;
+
+ return function() {
+ var result,
+ others = arguments;
+
+ if (others.length) {
+ args.length = argsLength;
+ push.apply(args, others);
+ }
+ result = args.length == 1 ? func.call(this, args[0]) : func.apply(this, args);
+ args.length = argsLength;
+ return result;
+ };
+ }
+
+ /**
+ * Creates a new 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;
+ func.apply(thisArg, args);
+ }
+
+ return function() {
+ var now = new Date,
+ remain = wait - (now - lastCalled);
+
+ args = arguments;
+ thisArg = this;
+
+ if (remain <= 0) {
+ lastCalled = now;
+ result = func.apply(thisArg, args);
+ }
+ else if (!timeoutId) {
+ timeoutId = setTimeout(trailingCall, remain);
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Create a new function that passes the `func` function to the `wrapper`
+ * function as its first argument. Additional arguments are appended to those
+ * passed to the `wrapper` function.
+ *
+ * @static
+ * @memberOf _
+ * @category Functions
+ * @param {Function} func The function to wrap.
+ * @param {Function} wrapper The wrapper function.
+ * @param {Mixed} [arg1, arg2, ...] Arguments to append to those passed to the wrapper.
+ * @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(func, wrapper) {
+ return function() {
+ var args = [func];
+ if (arguments.length) {
+ push.apply(args, arguments);
+ }
+ return wrapper.apply(this, args);
+ };
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Create a shallow clone of the `value`. Any nested objects or arrays will be
+ * assigned by reference and not cloned.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Mixed} value The value to clone.
+ * @returns {Mixed} Returns the cloned `value`.
+ * @example
+ *
+ * _.clone({ 'name': 'moe' });
+ * // => { 'name': 'moe' };
+ */
+ function clone(value) {
+ return value && objectTypes[typeof value]
+ ? (isArray(value) ? value.slice() : extend({}, value))
+ : value;
+ }
+
+ /**
+ * Assigns missing properties on `object` with default values from the defaults
+ * objects. Once a property is set, additional defaults of the same property
+ * will be ignored.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} object The object to populate.
+ * @param {Object} [defaults1, defaults2, ...] The defaults objects to apply to `object`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * var iceCream = { 'flavor': 'chocolate' };
+ * _.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'rainbow' });
+ * // => { 'flavor': 'chocolate', 'sprinkles': 'rainbow' }
+ */
+ var defaults = createIterator(extendIteratorOptions, {
+ 'inLoop': 'if (result[index] == null) ' + extendIteratorOptions.inLoop
+ });
+
+ /**
+ * Copies enumerable properties from the source objects to 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.
+ * @returns {Object} Returns the destination object.
+ * @example
+ *
+ * _.extend({ 'name': 'moe' }, { 'age': 40 });
+ * // => { 'name': 'moe', 'age': 40 }
+ */
+ var extend = createIterator(extendIteratorOptions);
+
+ /**
+ * Iterates over `object`'s own and inherited enumerable properties, executing
+ * the `callback` for each property. The `callback` is bound to `thisArg` and
+ * invoked with 3 arguments; (value, key, object).
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} object The object to iterate over.
+ * @param {Function} callback The function called per iteration.
+ * @param {Mixed} [thisArg] The `this` binding for the callback.
+ * @returns {Object} Returns the `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(baseIteratorOptions, forEachIteratorOptions, forOwnIteratorOptions, {
+ 'useHas': false
+ });
+
+ /**
+ * Iterates over `object`'s own enumerable properties, executing the `callback`
+ * for each property. The `callback` is bound to `thisArg` and invoked with 3
+ * arguments; (value, key, object).
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} object The object to iterate over.
+ * @param {Function} callback The function called per iteration.
+ * @param {Mixed} [thisArg] The `this` binding for the callback.
+ * @returns {Object} Returns the `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(baseIteratorOptions, forEachIteratorOptions, forOwnIteratorOptions);
+
+ /**
+ * Produces a sorted array of the 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', ...]
+ */
+ var functions = createIterator({
+ 'useHas': false,
+ 'args': 'object',
+ 'init': '[]',
+ 'inLoop': 'if (toString.call(iteratee[index]) == funcClass) result.push(index)',
+ 'bottom': '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 hasOwnProperty.call(object, property);
+ }
+
+ /**
+ * 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
+ */
+ var isArguments = function(value) {
+ return toString.call(value) == '[object Arguments]';
+ };
+ // fallback for browser like Firefox < 4 and IE < 9 which detect
+ // `arguments` as `[object Object]`
+ if (!isArguments(arguments)) {
+ isArguments = function(value) {
+ return !!(value && hasOwnProperty.call(value, 'callee'));
+ };
+ }
+
+ /**
+ * 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) {
+ return 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 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);
+ }
+
+ /**
+ * Checks if `value` is empty. Arrays or strings 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
+ */
+ var isEmpty = createIterator({
+ 'args': 'value',
+ 'init': 'true',
+ 'top':
+ 'var className = toString.call(value);\n' +
+ 'if (className == arrayClass || className == stringClass) return !value.length',
+ 'inLoop': {
+ 'object': 'return false'
+ }
+ });
+
+ /**
+ * 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 {Array} [stack] Internally used to keep track of "seen" objects to
+ * avoid circular references.
+ * @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, stack) {
+ stack || (stack = []);
+
+ // 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 `undefined == null`
+ if (a == null || b == null) {
+ return a === b;
+ }
+ // unwrap any wrapped objects
+ if (a._chain) {
+ a = a._wrapped;
+ }
+ if (b._chain) {
+ b = b._wrapped;
+ }
+ // invoke a custom `isEqual` method if one is provided
+ if (a.isEqual && toString.call(a.isEqual) == funcClass) {
+ return a.isEqual(b);
+ }
+ if (b.isEqual && toString.call(b.isEqual) == funcClass) {
+ return b.isEqual(a);
+ }
+ // compare [[Class]] names
+ var className = toString.call(a);
+ if (className != toString.call(b)) {
+ return false;
+ }
+ switch (className) {
+ // strings, numbers, dates, and booleans are compared by value
+ case stringClass:
+ // primitives and their corresponding object instances are equivalent;
+ // thus, `'5'` is quivalent to `new String('5')`
+ return a == String(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 boolClass:
+ case dateClass:
+ // coerce dates and booleans to numeric values, dates to milliseconds and
+ // booleans to 1 or 0; treat invalid dates coerced to `NaN` as not equal
+ return +a == +b;
+
+ // regexps are compared by their source and flags
+ case regexpClass:
+ return a.source == b.source &&
+ a.global == b.global &&
+ a.multiline == b.multiline &&
+ a.ignoreCase == b.ignoreCase;
+ }
+ if (typeof a != 'object' || typeof b != 'object') {
+ return false;
+ }
+ // Assume equality for cyclic structures. The algorithm for detecting cyclic
+ // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
+ var length = stack.length;
+ while (length--) {
+ // Linear search. Performance is inversely proportional to the number of
+ // unique nested structures.
+ if (stack[length] == a) {
+ return true;
+ }
+ }
+
+ var index = -1,
+ result = true,
+ size = 0;
+
+ // add the first collection to the stack of traversed objects
+ stack.push(a);
+
+ // recursively compare objects and arrays
+ if (className == arrayClass) {
+ // compare array 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], stack))) {
+ break;
+ }
+ }
+ }
+ }
+ else {
+ // objects with different constructors are not equivalent
+ if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) {
+ return false;
+ }
+ // deep compare objects.
+ for (var prop in a) {
+ if (hasOwnProperty.call(a, prop)) {
+ // count the number of properties.
+ size++;
+ // deep compare each property value.
+ if (!(result = hasOwnProperty.call(b, prop) && isEqual(a[prop], b[prop], stack))) {
+ break;
+ }
+ }
+ }
+ // ensure both objects have the same number of properties
+ if (result) {
+ for (prop in b) {
+ // Adobe's JS engine, embedded in applications like InDesign, has a
+ // bug that causes `!size--` to throw an error so it must be wrapped
+ // in parentheses.
+ // https://github.com/documentcloud/underscore/issues/355
+ if (hasOwnProperty.call(b, prop) && !(size--)) {
+ break;
+ }
+ }
+ result = !size;
+ }
+ // handle JScript [[DontEnum]] bug
+ if (result && hasDontEnumBug) {
+ while (++index < 7) {
+ prop = shadowed[index];
+ if (hasOwnProperty.call(a, prop)) {
+ if (!(result = hasOwnProperty.call(b, prop) && isEqual(a[prop], b[prop], stack))) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ // remove the first collection from the stack of traversed objects
+ stack.pop();
+ return result;
+ }
+
+ /**
+ * Checks if `value` is a finite number.
+ * Note: This is not the same as native `isFinite`, which will return true for
+ * booleans and other values. See http://es5.github.com/#x15.1.2.5.
+ *
+ * @deprecated
+ * @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');
+ * // => false
+ *
+ * _.isFinite(Infinity);
+ * // => false
+ */
+ function isFinite(value) {
+ return nativeIsFinite(value) && toString.call(value) == numberClass;
+ }
+
+ /**
+ * 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(''.concat);
+ * // => true
+ */
+ function isFunction(value) {
+ return toString.call(value) == funcClass;
+ }
+
+ /**
+ * Checks if `value` is the language type of Object.
+ * (e.g. arrays, functions, objects, regexps, `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);
+ * // => false
+ */
+ function isObject(value) {
+ // check if the value is the ECMAScript language type of Object
+ // http://es5.github.com/#x8
+ return value && objectTypes[typeof value];
+ }
+
+ /**
+ * 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.
+ *
+ * @deprecated
+ * @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 toString.call(value) == numberClass && value != +value
+ }
+
+ /**
+ * Checks if `value` is `null`.
+ *
+ * @deprecated
+ * @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 toString.call(value) == numberClass;
+ }
+
+ /**
+ * 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 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 toString.call(value) == stringClass;
+ }
+
+ /**
+ * Checks if `value` is `undefined`.
+ *
+ * @deprecated
+ * @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 value === undefined;
+ }
+
+ /**
+ * Produces an array of object`'s own enumerable property names.
+ *
+ * @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)
+ : nativeKeys(object);
+ };
+
+ /**
+ * Creates an object composed of the specified properties. Property names may
+ * be specified as individual arguments or as arrays of property names.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} object The object to pluck.
+ * @param {Object} [prop1, prop2, ...] The properties to pick.
+ * @returns {Object} Returns an object composed of the picked properties.
+ * @example
+ *
+ * _.pick({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'name', 'age');
+ * // => { 'name': 'moe', 'age': 40 }
+ */
+ function pick(object) {
+ var prop,
+ index = 0,
+ props = concat.apply(ArrayProto, arguments),
+ length = props.length,
+ result = {};
+
+ // start `index` at `1` to skip `object`
+ while (++index < length) {
+ prop = props[index];
+ if (prop in object) {
+ result[prop] = object[prop];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets the size of `value` by returning `value.length` if `value` is a string
+ * or array, or the number of own enumerable properties if `value` is an object.
+ *
+ * @deprecated
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Array|Object|String} value The value to inspect.
+ * @returns {Number} Returns `value.length` if `value` is a string or array,
+ * or the number of own enumerable properties if `value` is an object.
+ * @example
+ *
+ * _.size([1, 2]);
+ * // => 2
+ *
+ * _.size({ 'one': 1, 'two': 2, 'three': 3 });
+ * // => 3
+ *
+ * _.size('curly');
+ * // => 5
+ */
+ function size(value) {
+ if (!value) {
+ return 0;
+ }
+ var length = value.length;
+ return length === length >>> 0 ? value.length : keys(value).length;
+ }
+
+ /**
+ * Produces an array of `object`'s own enumerable property values.
+ *
+ * @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]
+ */
+ var values = createIterator({
+ 'args': 'object',
+ 'init': '[]',
+ 'inLoop': 'result.push(iteratee[index])'
+ });
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Escapes a string for inclusion in HTML, replacing `&`, `<`, `"`, and `'`
+ * characters.
+ *
+ * @static
+ * @memberOf _
+ * @category Utilities
+ * @param {String} string The string to escape.
+ * @returns {String} Returns the escaped string.
+ * @example
+ *
+ * _.escape('Curly, Larry & Moe');
+ * // => "Curly, Larry &amp; Moe"
+ */
+ function escape(string) {
+ return string == null ? '' : (string + '').replace(reUnescapedHtml, escapeHtmlChar);
+ }
+
+ /**
+ * This function returns the first argument passed to it.
+ * Note: It is used throughout Lo-Dash as a default callback.
+ *
+ * @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('curly');
+ * // => 'Curly'
+ *
+ * _('larry').capitalize();
+ * // => 'Larry'
+ */
+ function mixin(object) {
+ forEach(functions(object), function(methodName) {
+ var func = lodash[methodName] = object[methodName];
+
+ LoDash.prototype[methodName] = function() {
+ var args = [this._wrapped];
+ if (arguments.length) {
+ push.apply(args, arguments);
+ }
+ var result = func.apply(lodash, args);
+ if (this._chain) {
+ result = new LoDash(result);
+ result._chain = true;
+ }
+ return 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;
+ }
+
+ /**
+ * 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.
+ *
+ * @deprecated
+ * @static
+ * @memberOf _
+ * @category Utilities
+ * @param {Object} object The object to inspect.
+ * @param {String} property The property to get the result 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
+ if (!object) {
+ return null;
+ }
+ var value = object[property];
+ return toString.call(value) == funcClass ? object[property]() : value;
+ }
+
+ /**
+ * A micro-templating method that handles arbitrary delimiters, preserves
+ * whitespace, and correctly escapes quotes within interpolated code.
+ *
+ * @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.
+ * @returns {Function|String} Returns a compiled function when no `data` object
+ * is given, else it returns the interpolated text.
+ * @example
+ *
+ * // using 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', 'curly', 'larry'] });
+ * // => '<li>moe</li><li>curly</li><li>larry</li>'
+ *
+ * var template = _.template('<b><%- value %></b>');
+ * template({ 'value': '<script>' });
+ * // => '<b>&lt;script></b>'
+ *
+ * // using `print`
+ * var compiled = _.template('<% print("Hello " + epithet); %>');
+ * compiled({ 'epithet': 'stooge' });
+ * // => 'Hello stooge.'
+ *
+ * // using custom template settings
+ * _.templateSettings = {
+ * 'interpolate': /\{\{(.+?)\}\}/g
+ * };
+ *
+ * var template = _.template('Hello {{ name }}!');
+ * template({ 'name': 'Mustache' });
+ * // => 'Hello Mustache!'
+ *
+ * // using the `variable` option
+ * _.template('<%= data.hasWith %>', { 'hasWith': 'no' }, { 'variable': 'data' });
+ * // => 'no'
+ *
+ * // using the `source` property
+ * <script>
+ * JST.project = <%= _.template(jstText).source %>;
+ * </script>
+ */
+ 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
+ options || (options = {});
+
+ var isEvaluating,
+ result,
+ escapeDelimiter = options.escape,
+ evaluateDelimiter = options.evaluate,
+ interpolateDelimiter = options.interpolate,
+ settings = lodash.templateSettings,
+ variable = options.variable;
+
+ // use default settings if no options object is provided
+ if (escapeDelimiter == null) {
+ escapeDelimiter = settings.escape;
+ }
+ if (evaluateDelimiter == null) {
+ evaluateDelimiter = settings.evaluate;
+ }
+ if (interpolateDelimiter == null) {
+ interpolateDelimiter = settings.interpolate;
+ }
+
+ // tokenize delimiters to avoid escaping them
+ if (escapeDelimiter) {
+ text = text.replace(escapeDelimiter, tokenizeEscape);
+ }
+ if (interpolateDelimiter) {
+ text = text.replace(interpolateDelimiter, tokenizeInterpolate);
+ }
+ if (evaluateDelimiter != lastEvaluateDelimiter) {
+ // generate `reEvaluateDelimiter` to match `_.templateSettings.evaluate`
+ // and internal `<e%- %>`, `<e%= %>` delimiters
+ lastEvaluateDelimiter = evaluateDelimiter;
+ reEvaluateDelimiter = RegExp(
+ (evaluateDelimiter ? evaluateDelimiter.source : '($^)') +
+ '|<e%-([\\s\\S]+?)%>|<e%=([\\s\\S]+?)%>'
+ , 'g');
+ }
+ isEvaluating = tokenized.length;
+ text = text.replace(reEvaluateDelimiter, tokenizeEvaluate);
+ isEvaluating = isEvaluating != tokenized.length;
+
+ // escape characters that cannot be included in string literals and
+ // detokenize delimiter code snippets
+ text = "__p += '" + text
+ .replace(reUnescapedString, escapeStringChar)
+ .replace(reToken, detokenize) + "';\n";
+
+ // clear stored code snippets
+ tokenized.length = 0;
+
+ // if `options.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 (!variable) {
+ variable = settings.variable || lastVariable || 'obj';
+
+ if (isEvaluating) {
+ text = 'with (' + variable + ') {\n' + text + '\n}\n';
+ }
+ else {
+ if (variable != lastVariable) {
+ // generate `reDoubleVariable` to match references like `obj.obj` inside
+ // transformed "escape" and "interpolate" delimiters
+ lastVariable = variable;
+ reDoubleVariable = RegExp('(\\(\\s*)' + variable + '\\.' + variable + '\\b', 'g');
+ }
+ // avoid a with-statement by prepending data object references to property names
+ text = text
+ .replace(reInsertVariable, '$&' + variable + '.')
+ .replace(reDoubleVariable, '$1__d');
+ }
+ }
+
+ // cleanup code by stripping empty strings
+ text = ( isEvaluating ? text.replace(reEmptyStringLeading, '') : text)
+ .replace(reEmptyStringMiddle, '$1')
+ .replace(reEmptyStringTrailing, '$1;');
+
+ // frame code as the function body
+ text = 'function(' + variable + ') {\n' +
+ variable + ' || (' + variable + ' = {});\n' +
+ 'var __t, __p = \'\', __e = _.escape' +
+ (isEvaluating
+ ? ', __j = Array.prototype.join;\n' +
+ 'function print() { __p += __j.call(arguments, \'\') }\n'
+ : ', __d = ' + variable + '.' + variable + ' || ' + variable + ';\n'
+ ) +
+ text +
+ 'return __p\n}';
+
+ // add a sourceURL for easier debugging
+ // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
+ if (useSourceURL) {
+ text += '\n//@ sourceURL=/lodash/template/source[' + (templateCounter++) + ']';
+ }
+
+ try {
+ result = Function('_', 'return ' + text)(lodash);
+ } catch(e) {
+ result = function() { 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
+ // build time precompilation
+ result.source = text;
+ return result;
+ }
+
+ /**
+ * Executes the `callback` function `n` times. The `callback` is bound to
+ * `thisArg` and invoked with 1 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 for the callback.
+ * @example
+ *
+ * _.times(3, function() { genie.grantWish(); });
+ * // => calls `genie.grantWish()` 3 times
+ *
+ * _.times(3, function() { this.grantWish(); }, genie);
+ * // => also calls `genie.grantWish()` 3 times
+ */
+ function times(n, callback, thisArg) {
+ var index = -1;
+ if (thisArg) {
+ while (++index < n) {
+ callback.call(thisArg, index);
+ }
+ } else {
+ while (++index < n) {
+ callback(index);
+ }
+ }
+ }
+
+ /**
+ * 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 {Number|String} Returns a numeric id if no prefix is passed, else
+ * a string id may be returned.
+ * @example
+ *
+ * _.uniqueId('contact_');
+ * // => 'contact_104'
+ */
+ function uniqueId(prefix) {
+ var id = idCounter++;
+ return prefix ? prefix + id : id;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Wraps the value in a `lodash` wrapper object.
+ *
+ * @static
+ * @memberOf _
+ * @category Chaining
+ * @param {Mixed} value The value to wrap.
+ * @returns {Object} Returns the wrapper object.
+ * @example
+ *
+ * var stooges = [
+ * { 'name': 'moe', 'age': 40 },
+ * { 'name': 'larry', 'age': 50 },
+ * { 'name': 'curly', 'age': 60 }
+ * ];
+ *
+ * var youngest = _.chain(stooges)
+ * .sortBy(function(stooge) { return stooge.age; })
+ * .map(function(stooge) { return stooge.name + ' is ' + stooge.age; })
+ * .first()
+ * .value();
+ * // => 'moe is 40'
+ */
+ function chain(value) {
+ value = new LoDash(value);
+ value._chain = true;
+ return value;
+ }
+
+ /**
+ * 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 `callback`.
+ * @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;
+ }
+
+ /**
+ * Enables method chaining on the wrapper object.
+ *
+ * @name chain
+ * @deprecated
+ * @memberOf _
+ * @category Chaining
+ * @returns {Mixed} Returns the wrapper object.
+ * @example
+ *
+ * _([1, 2, 3]).value();
+ * // => [1, 2, 3]
+ */
+ function wrapperChain() {
+ this._chain = true;
+ return this;
+ }
+
+ /**
+ * Extracts the wrapped value.
+ *
+ * @name value
+ * @memberOf _
+ * @category Chaining
+ * @returns {Mixed} Returns the wrapped value.
+ * @example
+ *
+ * _([1, 2, 3]).value();
+ * // => [1, 2, 3]
+ */
+ function wrapperValue() {
+ return this._wrapped;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * The semantic version number.
+ *
+ * @static
+ * @memberOf _
+ * @type String
+ */
+ lodash.VERSION = '0.4.2';
+
+ // assign static methods
+ lodash.after = after;
+ lodash.bind = bind;
+ lodash.bindAll = bindAll;
+ lodash.chain = chain;
+ lodash.clone = clone;
+ lodash.compact = compact;
+ lodash.compose = compose;
+ lodash.contains = contains;
+ lodash.debounce = debounce;
+ lodash.defaults = defaults;
+ lodash.defer = defer;
+ lodash.delay = delay;
+ lodash.difference = difference;
+ lodash.escape = escape;
+ lodash.every = every;
+ lodash.extend = extend;
+ lodash.filter = filter;
+ lodash.find = find;
+ lodash.first = first;
+ lodash.flatten = flatten;
+ lodash.forEach = forEach;
+ lodash.forIn = forIn;
+ lodash.forOwn = forOwn;
+ lodash.functions = functions;
+ lodash.groupBy = groupBy;
+ lodash.has = has;
+ lodash.identity = identity;
+ lodash.indexOf = indexOf;
+ lodash.initial = initial;
+ lodash.intersection = intersection;
+ lodash.invoke = invoke;
+ 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.isRegExp = isRegExp;
+ lodash.isString = isString;
+ lodash.isUndefined = isUndefined;
+ lodash.keys = keys;
+ lodash.last = last;
+ lodash.lastIndexOf = lastIndexOf;
+ lodash.map = map;
+ lodash.max = max;
+ lodash.memoize = memoize;
+ lodash.min = min;
+ lodash.mixin = mixin;
+ lodash.noConflict = noConflict;
+ lodash.once = once;
+ lodash.partial = partial;
+ lodash.pick = pick;
+ lodash.pluck = pluck;
+ lodash.range = range;
+ lodash.reduce = reduce;
+ lodash.reduceRight = reduceRight;
+ lodash.reject = reject;
+ lodash.rest = rest;
+ lodash.result = result;
+ lodash.shuffle = shuffle;
+ lodash.size = size;
+ lodash.some = some;
+ lodash.sortBy = sortBy;
+ lodash.sortedIndex = sortedIndex;
+ lodash.tap = tap;
+ lodash.template = template;
+ lodash.throttle = throttle;
+ lodash.times = times;
+ lodash.toArray = toArray;
+ lodash.union = union;
+ lodash.uniq = uniq;
+ lodash.uniqueId = uniqueId;
+ lodash.values = values;
+ lodash.without = without;
+ lodash.wrap = wrap;
+ lodash.zip = zip;
+ lodash.zipObject = zipObject;
+
+ // assign aliases
+ lodash.all = every;
+ lodash.any = some;
+ lodash.collect = map;
+ lodash.detect = find;
+ lodash.each = forEach;
+ lodash.foldl = reduce;
+ lodash.foldr = reduceRight;
+ lodash.head = first;
+ lodash.include = contains;
+ lodash.inject = reduce;
+ lodash.methods = functions;
+ lodash.select = filter;
+ lodash.tail = rest;
+ lodash.take = first;
+ lodash.unique = uniq;
+
+ // add pseudo private properties used and removed during the build process
+ lodash._iteratorTemplate = iteratorTemplate;
+ lodash._shimKeys = shimKeys;
+
+ /*--------------------------------------------------------------------------*/
+
+ // assign private `LoDash` constructor's prototype
+ LoDash.prototype = lodash.prototype;
+
+ // add all static functions to `LoDash.prototype`
+ mixin(lodash);
+
+ // add `LoDash.prototype.chain` after calling `mixin()` to avoid overwriting
+ // it with the wrapped `lodash.chain`
+ LoDash.prototype.chain = wrapperChain;
+ LoDash.prototype.value = wrapperValue;
+
+ // add all mutator Array functions to the wrapper.
+ forEach(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
+ var func = ArrayProto[methodName];
+
+ LoDash.prototype[methodName] = function() {
+ var value = this._wrapped;
+ func.apply(value, arguments);
+
+ // 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.
+ if (value.length === 0) {
+ delete value[0];
+ }
+ if (this._chain) {
+ value = new LoDash(value);
+ value._chain = true;
+ }
+ return value;
+ };
+ });
+
+ // add all accessor Array functions to the wrapper.
+ forEach(['concat', 'join', 'slice'], function(methodName) {
+ var func = ArrayProto[methodName];
+
+ LoDash.prototype[methodName] = function() {
+ var value = this._wrapped,
+ result = func.apply(value, arguments);
+
+ if (this._chain) {
+ result = new LoDash(result);
+ result._chain = true;
+ }
+ return result;
+ };
+ });
+
+ /*--------------------------------------------------------------------------*/
+
+ // 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)); \ No newline at end of file