/*! * Lo-Dash v0.9.2 * (c) 2012 John-David Dalton * Based on Underscore.js 1.4.2 * (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. * Available under MIT license */ ;(function(window, undefined) { /** Detect free variable `exports` */ var freeExports = typeof exports == 'object' && exports; /** Detect free variable `global` and use it as `window` */ var freeGlobal = typeof global == 'object' && global; if (freeGlobal.global === freeGlobal) { window = freeGlobal; } /** Used for array and object method references */ var arrayRef = [], // avoid a Closure Compiler bug by creatively creating an object objectRef = new function(){}; /** Used to generate unique IDs */ var idCounter = 0; /** Used internally to indicate various things */ var indicatorObject = objectRef; /** Used by `cachedContains` as the default size when optimizations are enabled for large arrays */ var largeArraySize = 30; /** Used to restore the original `_` reference in `noConflict` */ var oldDash = window._; /** Used to detect template delimiter values that require a with-statement */ var reComplexDelimiter = /[-?+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/; /** Used to match HTML entities */ var reEscapedHtml = /&(?:amp|lt|gt|quot|#x27);/g; /** Used to match empty string literals in compiled template source */ var reEmptyStringLeading = /\b__p \+= '';/g, reEmptyStringMiddle = /\b(__p \+=) '' \+/g, reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; /** Used to match regexp flags from their coerced string values */ var reFlags = /\w*$/; /** Used to insert the data object variable into compiled template source */ var reInsertVariable = /(?:__e|__t = )\(\s*(?![\d\s"']|this\.)/g; /** Used to detect if a method is native */ var reNative = RegExp('^' + (objectRef.valueOf + '') .replace(/[.*+?^=!:${}()|[\]\/\\]/g, '\\$&') .replace(/valueOf|for [^\]]+/g, '.+?') + '$' ); /** * Used to match ES6 template delimiters * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-7.8.6 */ var reEsTemplate = /\$\{((?:(?=\\?)\\?[\s\S])*?)}/g; /** Used to match "interpolate" template delimiters */ var reInterpolate = /<%=([\s\S]+?)%>/g; /** Used to ensure capturing order of template delimiters */ var reNoMatch = /($^)/; /** Used to match HTML characters */ var reUnescapedHtml = /[&<>"']/g; /** Used to match unescaped characters in compiled string literals */ var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g; /** Used to fix the JScript [[DontEnum]] bug */ var shadowed = [ 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf' ]; /** Used to make template sourceURLs easier to identify */ var templateCounter = 0; /** Native method shortcuts */ var ceil = Math.ceil, concat = arrayRef.concat, floor = Math.floor, getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf, hasOwnProperty = objectRef.hasOwnProperty, push = arrayRef.push, propertyIsEnumerable = objectRef.propertyIsEnumerable, slice = arrayRef.slice, toString = objectRef.toString; /* Native method shortcuts for methods with the same name as other `lodash` methods */ var nativeBind = reNative.test(nativeBind = slice.bind) && nativeBind, nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray, nativeIsFinite = window.isFinite, nativeIsNaN = window.isNaN, nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys, nativeMax = Math.max, nativeMin = Math.min, nativeRandom = Math.random; /** `Object#toString` result shortcuts */ var argsClass = '[object Arguments]', arrayClass = '[object Array]', boolClass = '[object Boolean]', dateClass = '[object Date]', funcClass = '[object Function]', numberClass = '[object Number]', objectClass = '[object Object]', regexpClass = '[object RegExp]', stringClass = '[object String]'; /** * Detect the JScript [[DontEnum]] bug: * * In IE < 9 an objects own properties, shadowing non-enumerable ones, are * made non-enumerable as well. */ var hasDontEnumBug; /** Detect if own properties are iterated after inherited properties (IE < 9) */ var iteratesOwnLast; /** * Detect if `Array#shift` and `Array#splice` augment array-like objects * incorrectly: * * Firefox < 10, IE compatibility mode, and IE < 9 have buggy Array `shift()` * and `splice()` functions that fail to remove the last element, `value[0]`, * of array-like objects even though the `length` property is set to `0`. * The `shift()` method is buggy in IE 8 compatibility mode, while `splice()` * is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9. */ var hasObjectSpliceBug = (hasObjectSpliceBug = { '0': 1, 'length': 1 }, arrayRef.splice.call(hasObjectSpliceBug, 0, 1), hasObjectSpliceBug[0]); /** Detect if an `arguments` object's indexes are non-enumerable (IE < 9) */ var noArgsEnum = true; (function() { var props = []; function ctor() { this.x = 1; } ctor.prototype = { 'valueOf': 1, 'y': 1 }; for (var prop in new ctor) { props.push(prop); } for (prop in arguments) { noArgsEnum = !prop; } hasDontEnumBug = !/valueOf/.test(props); iteratesOwnLast = props[0] != 'x'; }(1)); /** Detect if an `arguments` object's [[Class]] is unresolvable (Firefox < 4, IE < 9) */ var noArgsClass = !isArguments(arguments); /** 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 a node's [[Class]] is unresolvable (IE < 9) * and that the JS engine won't error when attempting to coerce an object to * a string without a `toString` property value of `typeof` "function". */ try { var noNodeClass = ({ 'toString': 0 } + '', toString.call(window.document || 0) == objectClass); } catch(e) { } /* 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 (IE, Opera, V8) */ var isKeysFast = nativeKeys && /^.+$|true/.test(nativeKeys + !!window.attachEvent); /** * Detect if sourceURL syntax is usable without erroring: * * The JS engine in Adobe products, like InDesign, will throw a syntax error * when it encounters a single line comment beginning with the `@` symbol. * * The JS engine in Narwhal will generate the function `function anonymous(){//}` * and throw a syntax error. * * Avoid comments beginning `@` symbols in IE because they are part of its * non-standard conditional compilation support. * http://msdn.microsoft.com/en-us/library/121hztk3(v=vs.94).aspx */ try { var useSourceURL = (Function('//@')(), !window.attachEvent); } catch(e) { } /** Used to identify object classifications that `_.clone` supports */ var cloneableClasses = {}; cloneableClasses[argsClass] = cloneableClasses[funcClass] = false; cloneableClasses[arrayClass] = cloneableClasses[boolClass] = cloneableClasses[dateClass] = cloneableClasses[numberClass] = cloneableClasses[objectClass] = cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true; /** Used to determine if values are of the language type Object */ var objectTypes = { 'boolean': false, 'function': true, 'object': true, 'number': false, 'string': false, 'undefined': false }; /** Used to escape characters for inclusion in compiled string literals */ var stringEscapes = { '\\': '\\', "'": "'", '\n': 'n', '\r': 'r', '\t': 't', '\u2028': 'u2028', '\u2029': 'u2029' }; /*--------------------------------------------------------------------------*/ /** * The `lodash` function. * * @name _ * @constructor * @category Chaining * @param {Mixed} value The value to wrap in a `lodash` instance. * @returns {Object} Returns a `lodash` instance. */ function lodash(value) { // exit early if already wrapped if (value && value.__wrapped__) { return value; } // allow invoking `lodash` without the `new` operator if (!(this instanceof lodash)) { return new lodash(value); } this.__wrapped__ = value; } /** * By default, the template delimiters used by Lo-Dash are similar to those in * embedded Ruby (ERB). Change the following template settings to use alternative * delimiters. * * @static * @memberOf _ * @type Object */ lodash.templateSettings = { /** * Used to detect `data` property values to be HTML-escaped. * * @static * @memberOf _.templateSettings * @type RegExp */ 'escape': /<%-([\s\S]+?)%>/g, /** * Used to detect code to be evaluated. * * @static * @memberOf _.templateSettings * @type RegExp */ 'evaluate': /<%([\s\S]+?)%>/g, /** * Used to detect `data` property values to inject. * * @static * @memberOf _.templateSettings * @type RegExp */ 'interpolate': reInterpolate, /** * Used to reference the data object in the template text. * * @static * @memberOf _.templateSettings * @type String */ 'variable': '' }; /*--------------------------------------------------------------------------*/ /** * The template used to create iterator functions. * * @private * @param {Obect} data The data object used to populate the text. * @returns {String} Returns the interpolated text. */ var iteratorTemplate = template( // conditional strict mode '<% if (obj.useStrict) { %>\'use strict\';\n<% } %>' + // the `iteratee` may be reassigned by the `top` snippet 'var index, value, iteratee = <%= firstArg %>, ' + // assign the `result` variable an initial value 'result = <%= firstArg %>;\n' + // exit early if the first argument is falsey 'if (!<%= firstArg %>) return result;\n' + // add code before the iteration branches '<%= top %>;\n' + // array-like iteration: '<% if (arrayLoop) { %>' + 'var length = iteratee.length; index = -1;\n' + 'if (typeof length == \'number\') {' + // add support for accessing string characters by index if needed ' <% if (noCharByIndex) { %>\n' + ' if (isString(iteratee)) {\n' + ' iteratee = iteratee.split(\'\')\n' + ' }' + ' <% } %>\n' + // iterate over the array-like value ' while (++index < length) {\n' + ' value = iteratee[index];\n' + ' <%= arrayLoop %>\n' + ' }\n' + '}\n' + 'else {' + // object iteration: // add support for iterating over `arguments` objects if needed ' <% } else if (noArgsEnum) { %>\n' + ' var length = iteratee.length; index = -1;\n' + ' if (length && isArguments(iteratee)) {\n' + ' while (++index < length) {\n' + ' value = iteratee[index += \'\'];\n' + ' <%= objectLoop %>\n' + ' }\n' + ' } else {' + ' <% } %>' + // Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1 // (if the prototype or a property on the prototype has been set) // incorrectly sets a function's `prototype` property [[Enumerable]] // value to `true`. Because of this Lo-Dash standardizes on skipping // the the `prototype` property of functions regardless of its // [[Enumerable]] value. ' <% if (!hasDontEnumBug) { %>\n' + ' var skipProto = typeof iteratee == \'function\' && \n' + ' propertyIsEnumerable.call(iteratee, \'prototype\');\n' + ' <% } %>' + // iterate own properties using `Object.keys` if it's fast ' <% if (isKeysFast && useHas) { %>\n' + ' var ownIndex = -1,\n' + ' ownProps = objectTypes[typeof iteratee] ? nativeKeys(iteratee) : [],\n' + ' length = ownProps.length;\n\n' + ' while (++ownIndex < length) {\n' + ' index = ownProps[ownIndex];\n' + ' <% if (!hasDontEnumBug) { %>if (!(skipProto && index == \'prototype\')) {\n <% } %>' + ' value = iteratee[index];\n' + ' <%= objectLoop %>\n' + ' <% if (!hasDontEnumBug) { %>}\n<% } %>' + ' }' + // else using a for-in loop ' <% } else { %>\n' + ' for (index in iteratee) {<%' + ' if (!hasDontEnumBug || useHas) { %>\n if (<%' + ' if (!hasDontEnumBug) { %>!(skipProto && index == \'prototype\')<% }' + ' if (!hasDontEnumBug && useHas) { %> && <% }' + ' if (useHas) { %>hasOwnProperty.call(iteratee, index)<% }' + ' %>) {' + ' <% } %>\n' + ' value = iteratee[index];\n' + ' <%= objectLoop %>;' + ' <% if (!hasDontEnumBug || useHas) { %>\n }<% } %>\n' + ' }' + ' <% } %>' + // Because IE < 9 can't set the `[[Enumerable]]` attribute of an // existing property and the `constructor` property of a prototype // defaults to non-enumerable, Lo-Dash skips the `constructor` // property when it infers it's iterating over a `prototype` object. ' <% if (hasDontEnumBug) { %>\n\n' + ' var ctor = iteratee.constructor;\n' + ' <% for (var k = 0; k < 7; k++) { %>\n' + ' index = \'<%= shadowed[k] %>\';\n' + ' if (<%' + ' if (shadowed[k] == \'constructor\') {' + ' %>!(ctor && ctor.prototype === iteratee) && <%' + ' } %>hasOwnProperty.call(iteratee, index)) {\n' + ' value = iteratee[index];\n' + ' <%= objectLoop %>\n' + ' }' + ' <% } %>' + ' <% } %>' + ' <% if (arrayLoop || noArgsEnum) { %>\n}<% } %>\n' + // add code to the bottom of the iteration function '<%= bottom %>;\n' + // finally, return the `result` 'return result' ); /** * Reusable iterator options shared by `forEach`, `forIn`, and `forOwn`. */ var forEachIteratorOptions = { 'args': 'collection, callback, thisArg', 'top': 'callback = createCallback(callback, thisArg)', 'arrayLoop': 'if (callback(value, index, collection) === false) return result', 'objectLoop': 'if (callback(value, index, collection) === false) return result' }; /** Reusable iterator options for `defaults`, and `extend` */ var extendIteratorOptions = { 'useHas': false, 'args': 'object', 'top': 'for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {\n' + ' if (iteratee = arguments[argsIndex]) {', 'objectLoop': 'result[index] = value', 'bottom': ' }\n}' }; /** Reusable iterator options for `forIn` and `forOwn` */ var forOwnIteratorOptions = { 'arrayLoop': null }; /*--------------------------------------------------------------------------*/ /** * Creates a function optimized to search large arrays for a given `value`, * starting at `fromIndex`, using strict equality for comparisons, i.e. `===`. * * @private * @param {Array} array The array to search. * @param {Mixed} value The value to search for. * @param {Number} [fromIndex=0] The index to search from. * @param {Number} [largeSize=30] The length at which an array is considered large. * @returns {Boolean} Returns `true` if `value` is found, else `false`. */ function cachedContains(array, fromIndex, largeSize) { fromIndex || (fromIndex = 0); var length = array.length, isLarge = (length - fromIndex) >= (largeSize || largeArraySize); if (isLarge) { var cache = {}, index = fromIndex - 1; while (++index < length) { // manually coerce `value` to a string because `hasOwnProperty`, in some // older versions of Firefox, coerces objects incorrectly var key = array[index] + ''; (hasOwnProperty.call(cache, key) ? cache[key] : (cache[key] = [])).push(array[index]); } } return function(value) { if (isLarge) { var key = value + ''; return hasOwnProperty.call(cache, key) && indexOf(cache[key], value) > -1; } return indexOf(array, value, fromIndex) > -1; } } /** * Used by `_.max` and `_.min` as the default `callback` when a given * `collection` is a string value. * * @private * @param {String} value The character to inspect. * @returns {Number} Returns the code unit of given character. */ function charAtCallback(value) { return value.charCodeAt(0); } /** * Used by `sortBy` to compare transformed `collection` values, stable sorting * them in ascending order. * * @private * @param {Object} a The object to compare to `b`. * @param {Object} b The object to compare to `a`. * @returns {Number} Returns the sort order indicator of `1` or `-1`. */ function compareAscending(a, b) { var ai = a.index, bi = b.index; a = a.criteria; b = b.criteria; // ensure a stable sort in V8 and other engines // http://code.google.com/p/v8/issues/detail?id=90 if (a !== b) { if (a > b || a === undefined) { return 1; } if (a < b || b === undefined) { return -1; } } return ai < bi ? -1 : 1; } /** * Creates a function that, when called, invokes `func` with the `this` * binding of `thisArg` and prepends any `partailArgs` to the arguments passed * to the bound function. * * @private * @param {Function|String} func The function to bind or the method name. * @param {Mixed} [thisArg] The `this` binding of `func`. * @param {Array} partialArgs An array of arguments to be partially applied. * @returns {Function} Returns the new bound function. */ function createBound(func, thisArg, partialArgs) { var isFunc = isFunction(func), isPartial = !partialArgs, methodName = func; // juggle arguments if (isPartial) { partialArgs = thisArg; } function bound() { // `Function#bind` spec // http://es5.github.com/#x15.3.4.5 var args = arguments, thisBinding = isPartial ? this : thisArg; if (!isFunc) { func = thisArg[methodName]; } if (partialArgs.length) { args = args.length ? partialArgs.concat(slice.call(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 isObject(result) ? result : thisBinding } return func.apply(thisBinding, args); } return bound; } /** * Produces an iteration callback bound to an optional `thisArg`. If `func` is * a property name, the callback will return the property value for a given element. * * @private * @param {Function|String} [func=identity|property] The function called per * iteration or property name to query. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Function} Returns a callback function. */ function createCallback(func, thisArg) { if (!func) { return identity; } if (typeof func != 'function') { return function(object) { return object[func]; }; } if (thisArg !== undefined) { return function(value, index, object) { return func.call(thisArg, value, index, object); }; } return func; } /** * Creates compiled iteration functions. * * @private * @param {Object} [options1, options2, ...] The compile options object(s). * useHas - A boolean to specify using `hasOwnProperty` checks in the object loop. * args - A string of comma separated arguments the iteration function will accept. * top - A string of code to execute before the iteration branches. * arrayLoop - A string of code to execute in the array loop. * objectLoop - A string of code to execute in the object loop. * bottom - A string of code to execute after the iteration branches. * * @returns {Function} Returns the compiled function. */ function createIterator() { var data = { 'arrayLoop': '', 'bottom': '', 'hasDontEnumBug': hasDontEnumBug, 'isKeysFast': isKeysFast, 'objectLoop': '', 'noArgsEnum': noArgsEnum, 'noCharByIndex': noCharByIndex, 'shadowed': shadowed, 'top': '', 'useHas': true }; // merge options into a template data object for (var object, index = 0; object = arguments[index]; index++) { for (var key in object) { data[key] = object[key]; } } var args = data.args; data.firstArg = /^[^,]+/.exec(args)[0]; // create the function factory var factory = Function( 'createCallback, hasOwnProperty, isArguments, isString, objectTypes, ' + 'nativeKeys, propertyIsEnumerable', 'return function(' + args + ') {\n' + iteratorTemplate(data) + '\n}' ); // return the compiled function return factory( createCallback, hasOwnProperty, isArguments, isString, objectTypes, nativeKeys, propertyIsEnumerable ); } /** * Used by `template` to escape characters for inclusion in compiled * string literals. * * @private * @param {String} match The matched character to escape. * @returns {String} Returns the escaped character. */ function escapeStringChar(match) { return '\\' + stringEscapes[match]; } /** * Used by `escape` to convert characters to HTML entities. * * @private * @param {String} match The matched character to escape. * @returns {String} Returns the escaped character. */ function escapeHtmlChar(match) { return htmlEscapes[match]; } /** * A no-operation function. * * @private */ function noop() { // no operation performed } /** * Used by `unescape` to convert HTML entities to characters. * * @private * @param {String} match The matched character to unescape. * @returns {String} Returns the unescaped character. */ function unescapeHtmlChar(match) { return htmlUnescapes[match]; } /*--------------------------------------------------------------------------*/ /** * Checks if `value` is an `arguments` object. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is an `arguments` object, else `false`. * @example * * (function() { return _.isArguments(arguments); })(1, 2, 3); * // => true * * _.isArguments([1, 2, 3]); * // => false */ function isArguments(value) { return toString.call(value) == argsClass; } // fallback for browsers that can't detect `arguments` objects by [[Class]] if (noArgsClass) { isArguments = function(value) { return value ? hasOwnProperty.call(value, 'callee') : false; }; } /** * Iterates over `object`'s own and inherited enumerable properties, executing * the `callback` for each property. The `callback` is bound to `thisArg` and * invoked with three arguments; (value, key, object). Callbacks may exit iteration * early by explicitly returning `false`. * * @static * @memberOf _ * @category Objects * @param {Object} object The object to iterate over. * @param {Function} callback The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns `object`. * @example * * function Dog(name) { * this.name = name; * } * * Dog.prototype.bark = function() { * alert('Woof, woof!'); * }; * * _.forIn(new Dog('Dagny'), function(value, key) { * alert(key); * }); * // => alerts 'name' and 'bark' (order is not guaranteed) */ var forIn = createIterator(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 three * arguments; (value, key, object). Callbacks may exit iteration early by explicitly * returning `false`. * * @static * @memberOf _ * @category Objects * @param {Object} object The object to iterate over. * @param {Function} callback The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns `object`. * @example * * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) { * alert(key); * }); * // => alerts '0', '1', and 'length' (order is not guaranteed) */ var forOwn = createIterator(forEachIteratorOptions, forOwnIteratorOptions); /** * A fallback implementation of `isPlainObject` that checks if a given `value` * is an object created by the `Object` constructor, assuming objects created * by the `Object` constructor have no inherited enumerable properties and that * there are no `Object.prototype` extensions. * * @private * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if `value` is a plain object, else `false`. */ function shimIsPlainObject(value) { // avoid non-objects and false positives for `arguments` objects var result = false; if (!(value && typeof value == 'object') || isArguments(value)) { return result; } // IE < 9 presents DOM nodes as `Object` objects except they have `toString` // methods that are `typeof` "string" and still can coerce nodes to strings. // Also check that the constructor is `Object` (i.e. `Object instanceof Object`) var ctor = value.constructor; if ((!noNodeClass || !(typeof value.toString != 'function' && typeof (value + '') == 'string')) && (!isFunction(ctor) || ctor instanceof ctor)) { // IE < 9 iterates inherited properties before own properties. If the first // iterated property is an object's own property then there are no inherited // enumerable properties. if (iteratesOwnLast) { forIn(value, function(value, key, object) { result = !hasOwnProperty.call(object, key); return false; }); return result === false; } // In most environments an object's own properties are iterated before // its inherited properties. If the last iterated property is an object's // own property then there are no inherited enumerable properties. forIn(value, function(value, key) { result = key; }); return result === false || hasOwnProperty.call(value, result); } return result; } /** * A fallback implementation of `Object.keys` that produces an array of the * given object's own enumerable property names. * * @private * @param {Object} object The object to inspect. * @returns {Array} Returns a new array of property names. */ function shimKeys(object) { var result = []; forOwn(object, function(value, key) { result.push(key); }); return result; } /** * Used to convert characters to HTML entities: * * Though the `>` character is escaped for symmetry, characters like `>` and `/` * don't require escaping in HTML and have no special meaning unless they're part * of a tag or an unquoted attribute value. * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact") */ var htmlEscapes = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; /** Used to convert HTML entities to characters */ var htmlUnescapes = invert(htmlEscapes); /*--------------------------------------------------------------------------*/ /** * Creates a clone of `value`. If `deep` is `true`, all nested objects will * also be cloned otherwise they will be assigned by reference. Functions, DOM * nodes, `arguments` objects, and objects created by constructors other than * `Object` are **not** cloned. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to clone. * @param {Boolean} deep A flag to indicate a deep clone. * @param- {Object} [guard] Internally used to allow this method to work with * others like `_.map` without using their callback `index` argument for `deep`. * @param- {Array} [stackA=[]] Internally used to track traversed source objects. * @param- {Array} [stackB=[]] Internally used to associate clones with their * source counterparts. * @returns {Mixed} Returns the cloned `value`. * @example * * var stooges = [ * { 'name': 'moe', 'age': 40 }, * { 'name': 'larry', 'age': 50 }, * { 'name': 'curly', 'age': 60 } * ]; * * _.clone({ 'name': 'moe' }); * // => { 'name': 'moe' } * * var shallow = _.clone(stooges); * shallow[0] === stooges[0]; * // => true * * var deep = _.clone(stooges, true); * shallow[0] === stooges[0]; * // => false */ function clone(value, deep, guard, stackA, stackB) { if (value == null) { return value; } if (guard) { deep = false; } // inspect [[Class]] var isObj = isObject(value); if (isObj) { // don't clone `arguments` objects, functions, or non-object Objects var className = toString.call(value); if (!cloneableClasses[className] || (noArgsClass && isArguments(value))) { return value; } var isArr = className == arrayClass; isObj = isArr || (className == objectClass ? isPlainObject(value) : isObj); } // shallow clone if (!isObj || !deep) { // don't clone functions return isObj ? (isArr ? slice.call(value) : extend({}, value)) : value; } var ctor = value.constructor; switch (className) { case boolClass: case dateClass: return new ctor(+value); case numberClass: case stringClass: return new ctor(value); case regexpClass: return ctor(value.source, reFlags.exec(value)); } // check for circular references and return corresponding clone stackA || (stackA = []); stackB || (stackB = []); var length = stackA.length; while (length--) { if (stackA[length] == value) { return stackB[length]; } } // init cloned object var result = isArr ? ctor(value.length) : {}; // add the source value to the stack of traversed objects // and associate it with its clone stackA.push(value); stackB.push(result); // recursively populate clone (susceptible to call stack limits) (isArr ? forEach : forOwn)(value, function(objValue, key) { result[key] = clone(objValue, deep, null, stackA, stackB); }); return result; } /** * Assigns enumerable properties of the default object(s) to the `destination` * object for all `destination` properties that resolve to `null`/`undefined`. * Once a property is set, additional defaults of the same property will be * ignored. * * @static * @memberOf _ * @category Objects * @param {Object} object The destination object. * @param {Object} [default1, default2, ...] The default objects. * @returns {Object} Returns the destination object. * @example * * var iceCream = { 'flavor': 'chocolate' }; * _.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'rainbow' }); * // => { 'flavor': 'chocolate', 'sprinkles': 'rainbow' } */ var defaults = createIterator(extendIteratorOptions, { 'objectLoop': 'if (result[index] == null) ' + extendIteratorOptions.objectLoop }); /** * Assigns enumerable properties of the source object(s) 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); /** * Creates a sorted array of all enumerable properties, own and inherited, * of `object` that have function values. * * @static * @memberOf _ * @alias methods * @category Objects * @param {Object} object The object to inspect. * @returns {Array} Returns a new array of property names that have function values. * @example * * _.functions(_); * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...] */ function functions(object) { var result = []; forIn(object, function(value, key) { if (isFunction(value)) { result.push(key); } }); return result.sort(); } /** * Checks if the specified object `property` exists and is a direct property, * instead of an inherited property. * * @static * @memberOf _ * @category Objects * @param {Object} object The object to check. * @param {String} property The property to check for. * @returns {Boolean} Returns `true` if key is a direct property, else `false`. * @example * * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b'); * // => true */ function has(object, property) { return object ? hasOwnProperty.call(object, property) : false; } /** * Creates an object composed of the inverted keys and values of the given `object`. * * @static * @memberOf _ * @category Objects * @param {Object} object The object to invert. * @returns {Object} Returns the created inverted object. * @example * * _.invert({ 'first': 'Moe', 'second': 'Larry', 'third': 'Curly' }); * // => { 'Moe': 'first', 'Larry': 'second', 'Curly': 'third' } (order is not guaranteed) */ function invert(object) { var result = {}; forOwn(object, function(value, key) { result[value] = key; }); return result; } /** * Checks if `value` is an array. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is an array, else `false`. * @example * * (function() { return _.isArray(arguments); })(); * // => false * * _.isArray([1, 2, 3]); * // => true */ var isArray = nativeIsArray || function(value) { 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 : false; } /** * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a * length of `0` and objects with no own enumerable properties are considered * "empty". * * @static * @memberOf _ * @category Objects * @param {Array|Object|String} value The value to inspect. * @returns {Boolean} Returns `true` if the `value` is empty, else `false`. * @example * * _.isEmpty([1, 2, 3]); * // => false * * _.isEmpty({}); * // => true * * _.isEmpty(''); * // => true */ function isEmpty(value) { var result = true; if (!value) { return result; } var className = toString.call(value), length = value.length; if ((className == arrayClass || className == stringClass || className == argsClass || (noArgsClass && isArguments(value))) || (className == objectClass && typeof length == 'number' && isFunction(value.splice))) { return !length; } forOwn(value, function() { return (result = false); }); return result; } /** * Performs a deep comparison between two values to determine if they are * equivalent to each other. * * @static * @memberOf _ * @category Objects * @param {Mixed} a The value to compare. * @param {Mixed} b The other value to compare. * @param- {Object} [stackA=[]] Internally used track traversed `a` objects. * @param- {Object} [stackB=[]] Internally used track traversed `b` objects. * @returns {Boolean} Returns `true` if the values are equvalent, else `false`. * @example * * var moe = { 'name': 'moe', 'luckyNumbers': [13, 27, 34] }; * var clone = { 'name': 'moe', 'luckyNumbers': [13, 27, 34] }; * * moe == clone; * // => false * * _.isEqual(moe, clone); * // => true */ function isEqual(a, b, stackA, stackB) { // exit early for identical values if (a === b) { // treat `+0` vs. `-0` as not equal return a !== 0 || (1 / a == 1 / b); } // a strict comparison is necessary because `null == undefined` if (a == null || b == null) { return a === b; } // compare [[Class]] names var className = toString.call(a); if (className != toString.call(b)) { return false; } switch (className) { case boolClass: case dateClass: // coerce dates and booleans to numbers, dates to milliseconds and booleans // to `1` or `0`, treating invalid dates coerced to `NaN` as not equal return +a == +b; case numberClass: // treat `NaN` vs. `NaN` as equal return a != +a ? b != +b // but treat `+0` vs. `-0` as not equal : (a == 0 ? (1 / a == 1 / b) : a == +b); case regexpClass: case stringClass: // coerce regexes to strings (http://es5.github.com/#x15.10.6.4) // treat string primitives and their corresponding object instances as equal return a == b + ''; } // exit early, in older browsers, if `a` is array-like but not `b` var isArr = className == arrayClass || className == argsClass; if (noArgsClass && !isArr && (isArr = isArguments(a)) && !isArguments(b)) { return false; } if (!isArr) { // unwrap any `lodash` wrapped values if (a.__wrapped__ || b.__wrapped__) { return isEqual(a.__wrapped__ || a, b.__wrapped__ || b); } // exit for functions and DOM nodes if (className != objectClass || (noNodeClass && ( (typeof a.toString != 'function' && typeof (a + '') == 'string') || (typeof b.toString != 'function' && typeof (b + '') == 'string')))) { return false; } var ctorA = a.constructor, ctorB = b.constructor; // non `Object` object instances with different constructors are not equal if (ctorA != ctorB && !( isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB )) { return false; } } // assume cyclic structures are equal // the algorithm for detecting cyclic structures is adapted from ES 5.1 // section 15.12.3, abstract operation `JO` (http://es5.github.com/#x15.12.3) stackA || (stackA = []); stackB || (stackB = []); var length = stackA.length; while (length--) { if (stackA[length] == a) { return stackB[length] == b; } } var index = -1, result = true, size = 0; // add `a` and `b` to the stack of traversed objects stackA.push(a); stackB.push(b); // recursively compare objects and arrays (susceptible to call stack limits) if (isArr) { // compare lengths to determine if a deep comparison is necessary size = a.length; result = size == b.length; if (result) { // deep compare the contents, ignoring non-numeric properties while (size--) { if (!(result = isEqual(a[size], b[size], stackA, stackB))) { break; } } } return result; } // deep compare objects for (var key in a) { if (hasOwnProperty.call(a, key)) { // count the number of properties. size++; // deep compare each property value. if (!(hasOwnProperty.call(b, key) && isEqual(a[key], b[key], stackA, stackB))) { return false; } } } // ensure both objects have the same number of properties for (key in b) { // The JS engine in Adobe products, 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, key) && !(size--)) { // `size` will be `-1` if `b` has more properties than `a` return false; } } // handle JScript [[DontEnum]] bug if (hasDontEnumBug) { while (++index < 7) { key = shadowed[index]; if (hasOwnProperty.call(a, key) && !(hasOwnProperty.call(b, key) && isEqual(a[key], b[key], stackA, stackB))) { return false; } } } return true; } /** * Checks if `value` is, or can be coerced to, a finite number. * * Note: This is not the same as native `isFinite`, which will return true for * booleans and empty strings. See http://es5.github.com/#x15.1.2.5. * * @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'); * // => true * * _.isFinite(true); * // => false * * _.isFinite(''); * // => false * * _.isFinite(Infinity); * // => false */ function isFinite(value) { return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value)); } /** * Checks if `value` is a function. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is a function, else `false`. * @example * * _.isFunction(_); * // => true */ function isFunction(value) { return typeof value == 'function'; } // fallback for older versions of Chrome and Safari if (isFunction(/x/)) { isFunction = function(value) { return toString.call(value) == funcClass; }; } /** * Checks if `value` is the language type of Object. * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is an object, else `false`. * @example * * _.isObject({}); * // => true * * _.isObject([1, 2, 3]); * // => true * * _.isObject(1); * // => false */ function isObject(value) { // check if the value is the ECMAScript language type of Object // http://es5.github.com/#x8 // and avoid a V8 bug // http://code.google.com/p/v8/issues/detail?id=2291 return value ? objectTypes[typeof value] : false; } /** * Checks if `value` is `NaN`. * * Note: This is not the same as native `isNaN`, which will return true for * `undefined` and other values. See http://es5.github.com/#x15.1.2.4. * * @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 a given `value` is an object created by the `Object` constructor. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if `value` is a plain object, else `false`. * @example * * function Stooge(name, age) { * this.name = name; * this.age = age; * } * * _.isPlainObject(new Stooge('moe', 40)); * // => false * * _.isPlainObject([1, 2, 3]); * // => false * * _.isPlainObject({ 'name': 'moe', 'age': 40 }); * // => true */ var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) { if (!(value && typeof value == 'object')) { return false; } var valueOf = value.valueOf, objProto = typeof valueOf == 'function' && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto); return objProto ? value == objProto || (getPrototypeOf(value) == objProto && !isArguments(value)) : shimIsPlainObject(value); }; /** * Checks if `value` is a regular expression. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is a regular expression, else `false`. * @example * * _.isRegExp(/moe/); * // => true */ function isRegExp(value) { return 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; } /** * Creates an array composed of the own enumerable property names of `object`. * * @static * @memberOf _ * @category Objects * @param {Object} object The object to inspect. * @returns {Array} Returns a new array of property names. * @example * * _.keys({ 'one': 1, 'two': 2, 'three': 3 }); * // => ['one', 'two', 'three'] (order is not guaranteed) */ var keys = !nativeKeys ? shimKeys : function(object) { // avoid iterating over the `prototype` property return typeof object == 'function' && propertyIsEnumerable.call(object, 'prototype') ? shimKeys(object) : (isObject(object) ? nativeKeys(object) : []); }; /** * Merges enumerable properties of the source object(s) into the `destination` * object. Subsequent sources will overwrite propery assignments of previous * sources. * * @static * @memberOf _ * @category Objects * @param {Object} object The destination object. * @param {Object} [source1, source2, ...] The source objects. * @param- {Object} [indicator] Internally used to indicate that the `stack` * argument is an array of traversed objects instead of another source object. * @param- {Array} [stackA=[]] Internally used to track traversed source objects. * @param- {Array} [stackB=[]] Internally used to associate values with their * source counterparts. * @returns {Object} Returns the destination object. * @example * * var stooges = [ * { 'name': 'moe' }, * { 'name': 'larry' } * ]; * * var ages = [ * { 'age': 40 }, * { 'age': 50 } * ]; * * _.merge(stooges, ages); * // => [{ 'name': 'moe', 'age': 40 }, { 'name': 'larry', 'age': 50 }] */ function merge(object, source, indicator) { var args = arguments, index = 0, length = 2, stackA = args[3], stackB = args[4]; if (indicator !== objectRef) { stackA = []; stackB = []; length = args.length; } while (++index < length) { forOwn(args[index], function(source, key) { var found, isArr, value; if (source && ((isArr = isArray(source)) || isPlainObject(source))) { // avoid merging previously merged cyclic sources var stackLength = stackA.length; while (stackLength--) { found = stackA[stackLength] == source; if (found) { break; } } if (found) { object[key] = stackB[stackLength]; } else { // add `source` and associated `value` to the stack of traversed objects stackA.push(source); stackB.push(value = (value = object[key], isArr) ? (isArray(value) ? value : []) : (isPlainObject(value) ? value : {}) ); // recursively merge objects and arrays (susceptible to call stack limits) object[key] = merge(value, source, objectRef, stackA, stackB); } } else if (source != null) { object[key] = source; } }); } return object; } /** * Creates a shallow clone of `object` excluding the specified properties. * Property names may be specified as individual arguments or as arrays of * property names. If `callback` is passed, it will be executed for each property * in the `object`, omitting the properties `callback` returns truthy for. The * `callback` is bound to `thisArg` and invoked with three arguments; (value, key, object). * * @static * @memberOf _ * @category Objects * @param {Object} object The source object. * @param {Function|String} callback|[prop1, prop2, ...] The properties to omit * or the function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns an object without the omitted properties. * @example * * _.omit({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'userid'); * // => { 'name': 'moe', 'age': 40 } * * _.omit({ 'name': 'moe', '_hint': 'knucklehead', '_seed': '96c4eb' }, function(value, key) { * return key.charAt(0) == '_'; * }); * // => { 'name': 'moe' } */ function omit(object, callback, thisArg) { var isFunc = typeof callback == 'function', result = {}; if (isFunc) { callback = createCallback(callback, thisArg); } else { var props = concat.apply(arrayRef, arguments); } forIn(object, function(value, key, object) { if (isFunc ? !callback(value, key, object) : indexOf(props, key, 1) < 0 ) { result[key] = value; } }); return result; } /** * Creates a two dimensional array of the given object's key-value pairs, * i.e. `[[key1, value1], [key2, value2]]`. * * @static * @memberOf _ * @category Objects * @param {Object} object The object to inspect. * @returns {Array} Returns new array of key-value pairs. * @example * * _.pairs({ 'moe': 30, 'larry': 40, 'curly': 50 }); * // => [['moe', 30], ['larry', 40], ['curly', 50]] (order is not guaranteed) */ function pairs(object) { var result = []; forOwn(object, function(value, key) { result.push([key, value]); }); return result; } /** * Creates a shallow clone of `object` composed of the specified properties. * Property names may be specified as individual arguments or as arrays of * property names. If `callback` is passed, it will be executed for each property * in the `object`, picking the properties `callback` returns truthy for. The * `callback` is bound to `thisArg` and invoked with three arguments; (value, key, object). * * @static * @memberOf _ * @category Objects * @param {Object} object The source object. * @param {Function|String} callback|[prop1, prop2, ...] The properties to pick * or the function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns an object composed of the picked properties. * @example * * _.pick({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'name', 'age'); * // => { 'name': 'moe', 'age': 40 } * * _.pick({ 'name': 'moe', '_hint': 'knucklehead', '_seed': '96c4eb' }, function(value, key) { * return key.charAt(0) != '_'; * }); * // => { 'name': 'moe' } */ function pick(object, callback, thisArg) { var result = {}; if (typeof callback != 'function') { var index = 0, props = concat.apply(arrayRef, arguments), length = props.length; while (++index < length) { var key = props[index]; if (key in object) { result[key] = object[key]; } } } else { callback = createCallback(callback, thisArg); forIn(object, function(value, key, object) { if (callback(value, key, object)) { result[key] = value; } }); } return result; } /** * Creates an array composed of the own enumerable property values of `object`. * * @static * @memberOf _ * @category Objects * @param {Object} object The object to inspect. * @returns {Array} Returns a new array of property values. * @example * * _.values({ 'one': 1, 'two': 2, 'three': 3 }); * // => [1, 2, 3] */ function values(object) { var result = []; forOwn(object, function(value) { result.push(value); }); return result; } /*--------------------------------------------------------------------------*/ /** * Checks if a given `target` element is present in a `collection` using strict * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used * as the offset from the end of the collection. * * @static * @memberOf _ * @alias include * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Mixed} target The value to check for. * @param {Number} [fromIndex=0] The index to search from. * @returns {Boolean} Returns `true` if the `target` element is found, else `false`. * @example * * _.contains([1, 2, 3], 1); * // => true * * _.contains([1, 2, 3], 1, 2); * // => false * * _.contains({ 'name': 'moe', 'age': 40 }, 'moe'); * // => true * * _.contains('curly', 'ur'); * // => true */ function contains(collection, target, fromIndex) { var index = -1, length = collection ? collection.length : 0; fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0; if (typeof length == 'number') { return (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex) ) > -1; } return some(collection, function(value) { return ++index >= fromIndex && value === target; }); } /** * Creates an object composed of keys returned from running each element of * `collection` through a `callback`. The corresponding value of each key is * the number of times the key was returned by `callback`. The `callback` is * bound to `thisArg` and invoked with three arguments; (value, index|key, collection). * The `callback` argument may also be the name of a property to count by (e.g. 'length'). * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|String} callback|property The function called per iteration * or property name to count by. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns the composed aggregate object. * @example * * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); }); * // => { '4': 1, '6': 2 } * * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math); * // => { '4': 1, '6': 2 } * * _.countBy(['one', 'two', 'three'], 'length'); * // => { '3': 2, '5': 1 } */ function countBy(collection, callback, thisArg) { var result = {}; callback = createCallback(callback, thisArg); forEach(collection, function(value, key, collection) { key = callback(value, key, collection); (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1); }); return result; } /** * Checks if the `callback` returns a truthy value for **all** elements of a * `collection`. The `callback` is bound to `thisArg` and invoked with three * arguments; (value, index|key, collection). * * @static * @memberOf _ * @alias all * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Boolean} Returns `true` if all elements pass the callback check, * else `false`. * @example * * _.every([true, 1, null, 'yes'], Boolean); * // => false */ function every(collection, callback, thisArg) { var result = true; callback = createCallback(callback, thisArg); if (isArray(collection)) { var index = -1, length = collection.length; while (++index < length) { if (!(result = !!callback(collection[index], index, collection))) { break; } } } else { forEach(collection, function(value, index, collection) { return (result = !!callback(value, index, collection)); }); } return result; } /** * Examines each element in a `collection`, returning an array of all elements * the `callback` returns truthy for. The `callback` is bound to `thisArg` and * invoked with three arguments; (value, index|key, collection). * * @static * @memberOf _ * @alias select * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array} Returns a new array of elements that passed the callback check. * @example * * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); * // => [2, 4, 6] */ function filter(collection, callback, thisArg) { var result = []; callback = createCallback(callback, thisArg); forEach(collection, function(value, index, collection) { if (callback(value, index, collection)) { result.push(value); } }); return result; } /** * Examines each element in a `collection`, returning the first one the `callback` * returns truthy for. The function returns as soon as it finds an acceptable * element, and does not iterate over the entire `collection`. The `callback` is * bound to `thisArg` and invoked with three arguments; (value, index|key, collection). * * @static * @memberOf _ * @alias detect * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} callback The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the element that passed the callback check, * else `undefined`. * @example * * var even = _.find([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); * // => 2 */ function find(collection, callback, thisArg) { var result; callback = createCallback(callback, thisArg); forEach(collection, function(value, index, collection) { if (callback(value, index, collection)) { result = value; return false; } }); return result; } /** * Iterates over a `collection`, executing the `callback` for each element in * the `collection`. The `callback` is bound to `thisArg` and invoked with three * arguments; (value, index|key, collection). Callbacks may exit iteration early * by explicitly returning `false`. * * @static * @memberOf _ * @alias each * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} callback The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array|Object|String} Returns `collection`. * @example * * _([1, 2, 3]).forEach(alert).join(','); * // => alerts each number and returns '1,2,3' * * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, alert); * // => alerts each number (order is not guaranteed) */ var forEach = createIterator(forEachIteratorOptions); /** * Creates an object composed of keys returned from running each element of * `collection` through a `callback`. The corresponding value of each key is an * array of elements passed to `callback` that returned the key. The `callback` * is bound to `thisArg` and invoked with three arguments; (value, index|key, collection). * The `callback` argument may also be the name of a property to group by (e.g. 'length'). * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|String} callback|property The function called per iteration * or property name to group by. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns the composed aggregate object. * @example * * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); }); * // => { '4': [4.2], '6': [6.1, 6.4] } * * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math); * // => { '4': [4.2], '6': [6.1, 6.4] } * * _.groupBy(['one', 'two', 'three'], 'length'); * // => { '3': ['one', 'two'], '5': ['three'] } */ function groupBy(collection, callback, thisArg) { var result = {}; callback = createCallback(callback, thisArg); forEach(collection, function(value, key, collection) { key = callback(value, key, collection); (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value); }); return result; } /** * Invokes the method named by `methodName` on each element in the `collection`, * returning an array of the results of each invoked method. Additional arguments * will be passed to each invoked method. If `methodName` is a function it will * be invoked for, and `this` bound to, each element in the `collection`. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|String} methodName The name of the method to invoke or * the function invoked per iteration. * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with. * @returns {Array} Returns a new array of the results of each invoked method. * @example * * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); * // => [[1, 5, 7], [1, 2, 3]] * * _.invoke([123, 456], String.prototype.split, ''); * // => [['1', '2', '3'], ['4', '5', '6']] */ function invoke(collection, methodName) { var args = slice.call(arguments, 2), isFunc = typeof methodName == 'function', result = []; forEach(collection, function(value) { result.push((isFunc ? methodName : value[methodName]).apply(value, args)); }); return result; } /** * Creates an array of values by running each element in the `collection` * through a `callback`. The `callback` is bound to `thisArg` and invoked with * three arguments; (value, index|key, collection). * * @static * @memberOf _ * @alias collect * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array} Returns a new array of the results of each `callback` execution. * @example * * _.map([1, 2, 3], function(num) { return num * 3; }); * // => [3, 6, 9] * * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; }); * // => [3, 6, 9] (order is not guaranteed) */ function map(collection, callback, thisArg) { var index = -1, length = collection ? collection.length : 0, result = Array(typeof length == 'number' ? length : 0); callback = createCallback(callback, thisArg); if (isArray(collection)) { while (++index < length) { result[index] = callback(collection[index], index, collection); } } else { forEach(collection, function(value, key, collection) { result[++index] = callback(value, key, collection); }); } return result; } /** * Retrieves the maximum value of an `array`. If `callback` is passed, * it will be executed for each value in the `array` to generate the * criterion by which the value is ranked. The `callback` is bound to * `thisArg` and invoked with three arguments; (value, index, collection). * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the maximum value. * @example * * var stooges = [ * { 'name': 'moe', 'age': 40 }, * { 'name': 'larry', 'age': 50 }, * { 'name': 'curly', 'age': 60 } * ]; * * _.max(stooges, function(stooge) { return stooge.age; }); * // => { 'name': 'curly', 'age': 60 }; */ function max(collection, callback, thisArg) { var computed = -Infinity, index = -1, length = collection ? collection.length : 0, result = computed; if (callback || !isArray(collection)) { callback = !callback && isString(collection) ? charAtCallback : createCallback(callback, thisArg); forEach(collection, function(value, index, collection) { var current = callback(value, index, collection); if (current > computed) { computed = current; result = value; } }); } else { while (++index < length) { if (collection[index] > result) { result = collection[index]; } } } return result; } /** * Retrieves the minimum value of an `array`. If `callback` is passed, * it will be executed for each value in the `array` to generate the * criterion by which the value is ranked. The `callback` is bound to `thisArg` * and invoked with three arguments; (value, index, collection). * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the minimum value. * @example * * _.min([10, 5, 100, 2, 1000]); * // => 2 */ function min(collection, callback, thisArg) { var computed = Infinity, index = -1, length = collection ? collection.length : 0, result = computed; if (callback || !isArray(collection)) { callback = !callback && isString(collection) ? charAtCallback : createCallback(callback, thisArg); forEach(collection, function(value, index, collection) { var current = callback(value, index, collection); if (current < computed) { computed = current; result = value; } }); } else { while (++index < length) { if (collection[index] < result) { result = collection[index]; } } } return result; } /** * Retrieves the value of a specified property from all elements in * the `collection`. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {String} property The property to pluck. * @returns {Array} Returns a new array of property values. * @example * * var stooges = [ * { 'name': 'moe', 'age': 40 }, * { 'name': 'larry', 'age': 50 }, * { 'name': 'curly', 'age': 60 } * ]; * * _.pluck(stooges, 'name'); * // => ['moe', 'larry', 'curly'] */ function pluck(collection, property) { var result = []; forEach(collection, function(value) { result.push(value[property]); }); return result; } /** * 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 of `callback`. * @returns {Mixed} Returns the accumulated value. * @example * * var sum = _.reduce([1, 2, 3], function(memo, num) { return memo + num; }); * // => 6 */ function reduce(collection, callback, accumulator, thisArg) { var noaccum = arguments.length < 3; callback = createCallback(callback, thisArg); forEach(collection, function(value, index, collection) { accumulator = noaccum ? (noaccum = false, value) : callback(accumulator, value, index, collection) }); return accumulator; } /** * The right-associative version of `_.reduce`. * * @static * @memberOf _ * @alias foldr * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} callback The function called per iteration. * @param {Mixed} [accumulator] Initial value of the accumulator. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the accumulated value. * @example * * var list = [[0, 1], [2, 3], [4, 5]]; * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []); * // => [4, 5, 2, 3, 0, 1] */ function reduceRight(collection, callback, accumulator, thisArg) { var iteratee = collection, length = collection ? collection.length : 0, noaccum = arguments.length < 3; if (typeof length != 'number') { var props = keys(collection); length = props.length; } else if (noCharByIndex && isString(collection)) { iteratee = collection.split(''); } forEach(collection, function(value, index, collection) { index = props ? props[--length] : --length; accumulator = noaccum ? (noaccum = false, iteratee[index]) : callback.call(thisArg, accumulator, iteratee[index], index, collection); }); return accumulator; } /** * The opposite of `_.filter`, this method returns the values of a * `collection` that `callback` does **not** return truthy for. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array} Returns a new array of elements that did **not** pass the * callback check. * @example * * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); * // => [1, 3, 5] */ function reject(collection, callback, thisArg) { callback = createCallback(callback, thisArg); return filter(collection, function(value, index, collection) { return !callback(value, index, collection); }); } /** * Creates an array of shuffled `array` values, using a version of the * Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to shuffle. * @returns {Array} Returns a new shuffled collection. * @example * * _.shuffle([1, 2, 3, 4, 5, 6]); * // => [4, 1, 6, 3, 5, 2] */ function shuffle(collection) { var index = -1, result = Array(collection ? collection.length : 0); forEach(collection, function(value) { var rand = floor(nativeRandom() * (++index + 1)); result[index] = result[rand]; result[rand] = value; }); return result; } /** * Gets the size of the `collection` by returning `collection.length` for arrays * and array-like objects or the number of own enumerable properties for objects. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to inspect. * @returns {Number} Returns `collection.length` or number of own enumerable properties. * @example * * _.size([1, 2]); * // => 2 * * _.size({ 'one': 1, 'two': 2, 'three': 3 }); * // => 3 * * _.size('curly'); * // => 5 */ function size(collection) { var length = collection ? collection.length : 0; return typeof length == 'number' ? length : keys(collection).length; } /** * Checks if the `callback` returns a truthy value for **any** element of a * `collection`. The function returns as soon as it finds passing value, and * does not iterate over the entire `collection`. The `callback` is bound to * `thisArg` and invoked with three arguments; (value, index|key, collection). * * @static * @memberOf _ * @alias any * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Boolean} Returns `true` if any element passes the callback check, * else `false`. * @example * * _.some([null, 0, 'yes', false]); * // => true */ function some(collection, callback, thisArg) { var result; callback = createCallback(callback, thisArg); if (isArray(collection)) { var index = -1, length = collection.length; while (++index < length) { if (result = callback(collection[index], index, collection)) { break; } } } else { forEach(collection, function(value, index, collection) { return !(result = callback(value, index, collection)); }); } return !!result; } /** * Creates an array, stable sorted in ascending order by the results of * running each element of `collection` through a `callback`. The `callback` * is bound to `thisArg` and invoked with three arguments; (value, index|key, collection). * The `callback` argument may also be the name of a property to sort by (e.g. 'length'). * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|String} callback|property The function called per iteration * or property name to sort by. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array} Returns a new array of sorted elements. * @example * * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); }); * // => [3, 1, 2] * * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math); * // => [3, 1, 2] * * _.sortBy(['larry', 'brendan', 'moe'], 'length'); * // => ['moe', 'larry', 'brendan'] */ function sortBy(collection, callback, thisArg) { var result = []; callback = createCallback(callback, thisArg); forEach(collection, function(value, index, collection) { result.push({ 'criteria': callback(value, index, collection), 'index': index, 'value': value }); }); var length = result.length; result.sort(compareAscending); while (length--) { result[length] = result[length].value; } return result; } /** * Converts the `collection`, to an array. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to convert. * @returns {Array} Returns the new converted array. * @example * * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4); * // => [2, 3, 4] */ function toArray(collection) { if (collection && typeof collection.length == 'number') { return (noArraySliceOnStrings ? isString(collection) : typeof collection == 'string') ? collection.split('') : slice.call(collection); } return values(collection); } /** * Examines each element in a `collection`, returning an array of all elements * that contain the given `properties`. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Object} properties The object of property values to filter by. * @returns {Array} Returns a new array of elements that contain the given `properties`. * @example * * var stooges = [ * { 'name': 'moe', 'age': 40 }, * { 'name': 'larry', 'age': 50 }, * { 'name': 'curly', 'age': 60 } * ]; * * _.where(stooges, { 'age': 40 }); * // => [{ 'name': 'moe', 'age': 40 }] */ function where(collection, properties) { var props = []; forIn(properties, function(value, prop) { props.push(prop); }); return filter(collection, function(object) { var length = props.length; while (length--) { var result = object[props[length]] === properties[props[length]]; if (!result) { break; } } return !!result; }); } /*--------------------------------------------------------------------------*/ /** * Creates an array with all falsey values of `array` removed. The values * `false`, `null`, `0`, `""`, `undefined` and `NaN` are all falsey. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to compact. * @returns {Array} Returns a new filtered array. * @example * * _.compact([0, 1, false, 2, '', 3]); * // => [1, 2, 3] */ function compact(array) { var index = -1, length = array ? array.length : 0, result = []; while (++index < length) { var value = array[index]; if (value) { result.push(value); } } return result; } /** * Creates an array of `array` elements not present in the other arrays * using strict equality for comparisons, i.e. `===`. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to process. * @param {Array} [array1, array2, ...] Arrays to check. * @returns {Array} Returns a new array of `array` elements not present in the * other arrays. * @example * * _.difference([1, 2, 3, 4, 5], [5, 2, 10]); * // => [1, 3, 4] */ function difference(array) { var index = -1, length = array ? array.length : 0, flattened = concat.apply(arrayRef, arguments), contains = cachedContains(flattened, length), result = []; while (++index < length) { var value = array[index]; if (!contains(value)) { result.push(value); } } return result; } /** * Gets the first element of the `array`. Pass `n` to return the first `n` * elements of the `array`. * * @static * @memberOf _ * @alias head, take * @category Arrays * @param {Array} array The array to query. * @param {Number} [n] The number of elements to return. * @param- {Object} [guard] Internally used to allow this method to work with * others like `_.map` without using their callback `index` argument for `n`. * @returns {Mixed} Returns the first element or an array of the first `n` * elements of `array`. * @example * * _.first([5, 4, 3, 2, 1]); * // => 5 */ function first(array, n, guard) { if (array) { 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 index = -1, length = array ? array.length : 0, result = []; while (++index < length) { var value = array[index]; // recursively flatten arrays (susceptible to call stack limits) if (isArray(value)) { push.apply(result, shallow ? value : flatten(value)); } else { result.push(value); } } return result; } /** * Gets the index at which the first occurrence of `value` is found using * strict equality for comparisons, i.e. `===`. If the `array` is already * sorted, passing `true` for `fromIndex` will run a faster binary search. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to search. * @param {Mixed} value The value to search for. * @param {Boolean|Number} [fromIndex=0] The index to search from or `true` to * perform a binary search on a sorted `array`. * @returns {Number} Returns the index of the matched value or `-1`. * @example * * _.indexOf([1, 2, 3, 1, 2, 3], 2); * // => 1 * * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3); * // => 4 * * _.indexOf([1, 1, 2, 2, 3, 3], 2, true); * // => 2 */ function indexOf(array, value, fromIndex) { var index = -1, length = array ? array.length : 0; if (typeof fromIndex == 'number') { index = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0) - 1; } else if (fromIndex) { index = sortedIndex(array, value); return array[index] === value ? index : -1; } while (++index < length) { if (array[index] === value) { return index; } } return -1; } /** * Gets all but the last element of `array`. Pass `n` to exclude the last `n` * elements from the result. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to query. * @param {Number} [n=1] The number of elements to exclude. * @param- {Object} [guard] Internally used to allow this method to work with * others like `_.map` without using their callback `index` argument for `n`. * @returns {Array} Returns all but the last element or `n` elements of `array`. * @example * * _.initial([3, 2, 1]); * // => [3, 2] */ function initial(array, n, guard) { return array ? slice.call(array, 0, -((n == null || guard) ? 1 : n)) : []; } /** * Computes the intersection of all the passed-in arrays using strict equality * for comparisons, i.e. `===`. * * @static * @memberOf _ * @category Arrays * @param {Array} [array1, array2, ...] Arrays to process. * @returns {Array} Returns a new array of unique elements, 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 args = arguments, argsLength = args.length, cache = {}, result = []; forEach(array, function(value) { if (indexOf(result, value) < 0) { var length = argsLength; while (--length) { if (!(cache[length] || (cache[length] = cachedContains(args[length])))(value)) { return; } } result.push(value); } }); return result; } /** * Gets the last element of the `array`. Pass `n` to return the last `n` * elements of the `array`. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to query. * @param {Number} [n] The number of elements to return. * @param- {Object} [guard] Internally used to allow this method to work with * others like `_.map` without using their callback `index` argument for `n`. * @returns {Mixed} Returns the last element or an array of the last `n` * elements of `array`. * @example * * _.last([3, 2, 1]); * // => 1 */ function last(array, n, guard) { if (array) { var length = array.length; return (n == null || guard) ? array[length - 1] : slice.call(array, -n || length); } } /** * Gets the index at which the last occurrence of `value` is found using strict * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used * as the offset from the end of the collection. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to search. * @param {Mixed} value The value to search for. * @param {Number} [fromIndex=array.length-1] The index to search from. * @returns {Number} Returns the index of the matched value or `-1`. * @example * * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2); * // => 4 * * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3); * // => 1 */ function lastIndexOf(array, value, fromIndex) { var index = array ? array.length : 0; if (typeof fromIndex == 'number') { index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1; } while (index--) { if (array[index] === value) { return index; } } return -1; } /** * Creates an object composed from arrays of `keys` and `values`. Pass either * a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`, or * two arrays, one of `keys` and one of corresponding `values`. * * @static * @memberOf _ * @category Arrays * @param {Array} keys The array of keys. * @param {Array} [values=[]] The array of values. * @returns {Object} Returns an object composed of the given keys and * corresponding values. * @example * * _.object(['moe', 'larry', 'curly'], [30, 40, 50]); * // => { 'moe': 30, 'larry': 40, 'curly': 50 } */ function object(keys, values) { var index = -1, length = keys ? keys.length : 0, result = {}; while (++index < length) { var key = keys[index]; if (values) { result[key] = values[index]; } else { result[key[0]] = key[1]; } } return result; } /** * Creates an array of numbers (positive and/or negative) progressing from * `start` up to but not including `stop`. This method is a port of Python's * `range()` function. See http://docs.python.org/library/functions.html#range. * * @static * @memberOf _ * @category Arrays * @param {Number} [start=0] The start of the range. * @param {Number} end The end of the range. * @param {Number} [step=1] The value to increment or descrement by. * @returns {Array} Returns a new range array. * @example * * _.range(10); * // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] * * _.range(1, 11); * // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] * * _.range(0, 30, 5); * // => [0, 5, 10, 15, 20, 25] * * _.range(0, -10, -1); * // => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] * * _.range(0); * // => [] */ function range(start, end, step) { start = +start || 0; step = +step || 1; if (end == null) { end = start; start = 0; } // use `Array(length)` so V8 will avoid the slower "dictionary" mode // http://www.youtube.com/watch?v=XAqIpGU8ZZk#t=16m27s var index = -1, length = nativeMax(0, ceil((end - start) / step)), result = Array(length); while (++index < length) { result[index] = start; start += step; } return result; } /** * The opposite of `_.initial`, this method gets all but the first value of * `array`. Pass `n` to exclude the first `n` values from the result. * * @static * @memberOf _ * @alias drop, tail * @category Arrays * @param {Array} array The array to query. * @param {Number} [n=1] The number of elements to exclude. * @param- {Object} [guard] Internally used to allow this method to work with * others like `_.map` without using their callback `index` argument for `n`. * @returns {Array} Returns all but the first value or `n` values of `array`. * @example * * _.rest([3, 2, 1]); * // => [2, 1] */ function rest(array, n, guard) { return array ? slice.call(array, (n == null || guard) ? 1 : n) : []; } /** * Uses a binary search to determine the smallest index at which the `value` * should be inserted into `array` in order to maintain the sort order of the * sorted `array`. If `callback` is passed, it will be executed for `value` and * each element in `array` to compute their sort ranking. The `callback` is * bound to `thisArg` and invoked with one argument; (value). The `callback` * argument may also be the name of a property to order by. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to iterate over. * @param {Mixed} value The value to evaluate. * @param {Function|String} [callback=identity|property] The function called * per iteration or property name to order by. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Number} Returns the index at which the value should be inserted * into `array`. * @example * * _.sortedIndex([20, 30, 50], 40); * // => 2 * * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x'); * // => 2 * * var dict = { * 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 } * }; * * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) { * return dict.wordToNumber[word]; * }); * // => 2 * * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) { * return this.wordToNumber[word]; * }, dict); * // => 2 */ function sortedIndex(array, value, callback, thisArg) { var low = 0, high = array ? array.length : low; // explicitly reference `identity` for better engine inlining callback = callback ? createCallback(callback, thisArg) : identity; value = callback(value); while (low < high) { var mid = (low + high) >>> 1; callback(array[mid]) < value ? low = mid + 1 : high = mid; } return low; } /** * Computes the union of the passed-in arrays using strict equality for * comparisons, i.e. `===`. * * @static * @memberOf _ * @category Arrays * @param {Array} [array1, array2, ...] Arrays to process. * @returns {Array} Returns a new array of unique values, in order, that are * present in one or more of the arrays. * @example * * _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]); * // => [1, 2, 3, 101, 10] */ function union() { return uniq(concat.apply(arrayRef, arguments)); } /** * Creates a duplicate-value-free version of the `array` using strict equality * for comparisons, i.e. `===`. If the `array` is already sorted, passing `true` * for `isSorted` will run a faster algorithm. If `callback` is passed, each * element of `array` is passed through a callback` before uniqueness is computed. * The `callback` is bound to `thisArg` and invoked with three arguments; (value, index, array). * * @static * @memberOf _ * @alias unique * @category Arrays * @param {Array} array The array to process. * @param {Boolean} [isSorted=false] A flag to indicate that the `array` is already sorted. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array} Returns a duplicate-value-free array. * @example * * _.uniq([1, 2, 1, 3, 1]); * // => [1, 2, 3] * * _.uniq([1, 1, 2, 2, 3], true); * // => [1, 2, 3] * * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return Math.floor(num); }); * // => [1, 2, 3] * * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return this.floor(num); }, Math); * // => [1, 2, 3] */ function uniq(array, isSorted, callback, thisArg) { var index = -1, length = array ? array.length : 0, result = [], seen = result; // juggle arguments if (typeof isSorted == 'function') { thisArg = callback; callback = isSorted; isSorted = false; } // init value cache for large arrays var isLarge = !isSorted && length > 74; if (isLarge) { var cache = {}; } if (callback) { seen = []; callback = createCallback(callback, thisArg); } while (++index < length) { var value = array[index], computed = callback ? callback(value, index, array) : value; if (isLarge) { // manually coerce `computed` to a string because `hasOwnProperty`, in // some older versions of Firefox, coerces objects incorrectly seen = hasOwnProperty.call(cache, computed + '') ? cache[computed] : (cache[computed] = []); } if (isSorted ? !index || seen[seen.length - 1] !== computed : indexOf(seen, computed) < 0 ) { if (callback || isLarge) { seen.push(computed); } result.push(value); } } return result; } /** * Creates an array with all occurrences of the passed values removed using * strict equality for comparisons, i.e. `===`. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to filter. * @param {Mixed} [value1, value2, ...] Values to remove. * @returns {Array} Returns a new filtered array. * @example * * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1); * // => [2, 3, 4] */ function without(array) { var index = -1, length = array ? array.length : 0, contains = cachedContains(arguments, 1, 20), result = []; while (++index < length) { var value = array[index]; if (!contains(value)) { result.push(value); } } return result; } /** * Groups the elements of each array at their corresponding indexes. Useful for * separate data sources that are coordinated through matching array indexes. * For a matrix of nested arrays, `_.zip.apply(...)` can transpose the matrix * in a similar fashion. * * @static * @memberOf _ * @category Arrays * @param {Array} [array1, array2, ...] Arrays to process. * @returns {Array} Returns a new array of grouped elements. * @example * * _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]); * // => [['moe', 30, true], ['larry', 40, false], ['curly', 50, false]] */ function zip(array) { var index = -1, length = array ? max(pluck(arguments, 'length')) : 0, result = Array(length); while (++index < length) { result[index] = pluck(arguments, index); } return result; } /*--------------------------------------------------------------------------*/ /** * Creates a function that is restricted to executing `func` only after it is * called `n` times. The `func` is executed with the `this` binding of the * created function. * * @static * @memberOf _ * @category Functions * @param {Number} n The number of times the function must be called before * it is executed. * @param {Function} func The function to restrict. * @returns {Function} Returns the new restricted function. * @example * * var renderNotes = _.after(notes.length, render); * _.forEach(notes, function(note) { * note.asyncSave({ 'success': renderNotes }); * }); * // `renderNotes` is run once, after all notes have saved */ function after(n, func) { if (n < 1) { return func(); } return function() { if (--n < 1) { return func.apply(this, arguments); } }; } /** * Creates a function that, when called, invokes `func` with the `this` * binding of `thisArg` and prepends any additional `bind` arguments to those * passed to the bound function. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to bind. * @param {Mixed} [thisArg] The `this` binding of `func`. * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied. * @returns {Function} Returns the new bound function. * @example * * var func = function(greeting) { * return greeting + ' ' + this.name; * }; * * func = _.bind(func, { 'name': 'moe' }, 'hi'); * func(); * // => 'hi moe' */ function bind(func, thisArg) { // use `Function#bind` if it exists and is fast // (in V8 `Function#bind` is slower except when partially applied) return isBindFast || (nativeBind && arguments.length > 2) ? nativeBind.call.apply(nativeBind, arguments) : createBound(func, thisArg, slice.call(arguments, 2)); } /** * Binds methods on `object` to `object`, overwriting the existing method. * If no method names are provided, all the function properties of `object` * will be bound. * * @static * @memberOf _ * @category Functions * @param {Object} object The object to bind and assign the bound methods to. * @param {String} [methodName1, methodName2, ...] Method names on the object to bind. * @returns {Object} Returns `object`. * @example * * var buttonView = { * 'label': 'lodash', * 'onClick': function() { alert('clicked: ' + this.label); } * }; * * _.bindAll(buttonView); * jQuery('#lodash_button').on('click', buttonView.onClick); * // => When the button is clicked, `this.label` will have the correct value */ function bindAll(object) { var funcs = arguments, index = funcs.length > 1 ? 0 : (funcs = functions(object), -1), length = funcs.length; while (++index < length) { var key = funcs[index]; object[key] = bind(object[key], object); } return object; } /** * Creates a function that is the composition of the passed functions, * where each function consumes the return value of the function that follows. * In math terms, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`. * Each function is executed with the `this` binding of the composed function. * * @static * @memberOf _ * @category Functions * @param {Function} [func1, func2, ...] Functions to compose. * @returns {Function} Returns the new composed function. * @example * * var greet = function(name) { return 'hi: ' + name; }; * var exclaim = function(statement) { return statement + '!'; }; * var welcome = _.compose(exclaim, greet); * welcome('moe'); * // => 'hi: moe!' */ function compose() { var funcs = arguments; return function() { var args = arguments, length = funcs.length; while (length--) { args = [funcs[length].apply(this, args)]; } return args[0]; }; } /** * Creates a function that will delay the execution of `func` until after * `wait` milliseconds have elapsed since the last time it was invoked. Pass * `true` for `immediate` to cause debounce to invoke `func` on the leading, * instead of the trailing, edge of the `wait` timeout. Subsequent calls to * the debounced function will return the result of the last `func` call. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to debounce. * @param {Number} wait The number of milliseconds to delay. * @param {Boolean} immediate A flag to indicate execution is on the leading * edge of the timeout. * @returns {Function} Returns the new debounced function. * @example * * var lazyLayout = _.debounce(calculateLayout, 300); * jQuery(window).on('resize', lazyLayout); */ function debounce(func, wait, immediate) { var args, result, thisArg, timeoutId; function delayed() { timeoutId = null; if (!immediate) { result = func.apply(thisArg, args); } } return function() { var isImmediate = immediate && !timeoutId; args = arguments; thisArg = this; clearTimeout(timeoutId); timeoutId = setTimeout(delayed, wait); if (isImmediate) { result = func.apply(thisArg, args); } return result; }; } /** * Executes the `func` function after `wait` milliseconds. Additional arguments * will be passed to `func` when it is invoked. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to delay. * @param {Number} wait The number of milliseconds to delay execution. * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with. * @returns {Number} Returns the `setTimeout` timeout id. * @example * * var log = _.bind(console.log, console); * _.delay(log, 1000, 'logged later'); * // => 'logged later' (Appears after one second.) */ function delay(func, wait) { var args = slice.call(arguments, 2); return setTimeout(function() { func.apply(undefined, args); }, wait); } /** * Defers executing the `func` function until the current call stack has cleared. * Additional arguments will be passed to `func` when it is invoked. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to defer. * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with. * @returns {Number} Returns the `setTimeout` timeout id. * @example * * _.defer(function() { alert('deferred'); }); * // returns from the function before `alert` is called */ function defer(func) { var args = slice.call(arguments, 1); return setTimeout(function() { func.apply(undefined, args); }, 1); } /** * Creates a function that, when called, invokes `object[methodName]` and * prepends any additional `lateBind` arguments to those passed to the bound * function. This method differs from `_.bind` by allowing bound functions to * reference methods that will be redefined or don't yet exist. * * @static * @memberOf _ * @category Functions * @param {Object} object The object the method belongs to. * @param {String} methodName The method name. * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied. * @returns {Function} Returns the new bound function. * @example * * var object = { * 'name': 'moe', * 'greet': function(greeting) { * return greeting + ' ' + this.name; * } * }; * * var func = _.lateBind(object, 'greet', 'hi'); * func(); * // => 'hi moe' * * object.greet = function(greeting) { * return greeting + ', ' + this.name + '!'; * }; * * func(); * // => 'hi, moe!' */ function lateBind(object, methodName) { return createBound(methodName, object, slice.call(arguments, 2)); } /** * Creates a function that memoizes the result of `func`. If `resolver` is * passed, it will be used to determine the cache key for storing the result * based on the arguments passed to the memoized function. By default, the first * argument passed to the memoized function is used as the cache key. The `func` * is executed with the `this` binding of the memoized function. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to have its output memoized. * @param {Function} [resolver] A function used to resolve the cache key. * @returns {Function} Returns the new memoizing function. * @example * * var fibonacci = _.memoize(function(n) { * return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); * }); */ function memoize(func, resolver) { var cache = {}; return function() { var key = resolver ? resolver.apply(this, arguments) : arguments[0]; return hasOwnProperty.call(cache, key) ? cache[key] : (cache[key] = func.apply(this, arguments)); }; } /** * Creates a function that is restricted to execute `func` once. Repeat calls to * the function will return the value of the first call. The `func` is executed * with the `this` binding of the created function. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to restrict. * @returns {Function} Returns the new restricted function. * @example * * var initialize = _.once(createApplication); * initialize(); * initialize(); * // Application is only created once. */ function once(func) { var result, ran = false; return function() { if (ran) { return result; } ran = true; result = func.apply(this, arguments); // clear the `func` variable so the function may be garbage collected func = null; return result; }; } /** * Creates a function that, when called, invokes `func` with any additional * `partial` arguments prepended to those passed to the new function. This * method is similar to `bind`, except it does **not** alter the `this` binding. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to partially apply arguments to. * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied. * @returns {Function} Returns the new partially applied function. * @example * * var greet = function(greeting, name) { return greeting + ': ' + name; }; * var hi = _.partial(greet, 'hi'); * hi('moe'); * // => 'hi: moe' */ function partial(func) { return createBound(func, slice.call(arguments, 1)); } /** * Creates a function that, when executed, will only call the `func` * function at most once per every `wait` milliseconds. If the throttled * function is invoked more than once during the `wait` timeout, `func` will * also be called on the trailing edge of the timeout. Subsequent calls to the * throttled function will return the result of the last `func` call. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to throttle. * @param {Number} wait The number of milliseconds to throttle executions to. * @returns {Function} Returns the new throttled function. * @example * * var throttled = _.throttle(updatePosition, 100); * jQuery(window).on('scroll', throttled); */ function throttle(func, wait) { var args, result, thisArg, timeoutId, lastCalled = 0; function trailingCall() { lastCalled = new Date; timeoutId = null; result = func.apply(thisArg, args); } return function() { var now = new Date, remaining = wait - (now - lastCalled); args = arguments; thisArg = this; if (remaining <= 0) { clearTimeout(timeoutId); lastCalled = now; result = func.apply(thisArg, args); } else if (!timeoutId) { timeoutId = setTimeout(trailingCall, remaining); } return result; }; } /** * Creates a function that passes `value` to the `wrapper` function as its * first argument. Additional arguments passed to the function are appended * to those passed to the `wrapper` function. The `wrapper` is executed with * the `this` binding of the created function. * * @static * @memberOf _ * @category Functions * @param {Mixed} value The value to wrap. * @param {Function} wrapper The wrapper function. * @returns {Function} Returns the new function. * @example * * var hello = function(name) { return 'hello ' + name; }; * hello = _.wrap(hello, function(func) { * return 'before, ' + func('moe') + ', after'; * }); * hello(); * // => 'before, hello moe, after' */ function wrap(value, wrapper) { return function() { var args = [value]; push.apply(args, arguments); return wrapper.apply(this, args); }; } /*--------------------------------------------------------------------------*/ /** * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their * corresponding HTML entities. * * @static * @memberOf _ * @category Utilities * @param {String} string The string to escape. * @returns {String} Returns the escaped string. * @example * * _.escape('Moe, Larry & Curly'); * // => "Moe, Larry & Curly" */ function escape(string) { return string == null ? '' : (string + '').replace(reUnescapedHtml, escapeHtmlChar); } /** * This function returns the first argument passed to it. * * 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('larry'); * // => 'Larry' * * _('curly').capitalize(); * // => 'Curly' */ function mixin(object) { forEach(functions(object), function(methodName) { var func = lodash[methodName] = object[methodName]; lodash.prototype[methodName] = function() { var args = [this.__wrapped__]; push.apply(args, arguments); var result = func.apply(lodash, args); 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; } /** * Produces a random number between `min` and `max` (inclusive). If only one * argument is passed, a number between `0` and the given number will be returned. * * @static * @memberOf _ * @category Utilities * @param {Number} [min=0] The minimum possible value. * @param {Number} [max=1] The maximum possible value. * @returns {Number} Returns a random number. * @example * * _.random(0, 5); * // => a number between 1 and 5 * * _.random(5); * // => also a number between 1 and 5 */ function random(min, max) { if (min == null && max == null) { max = 1; } min = +min || 0; if (max == null) { max = min; min = 0; } return min + floor(nativeRandom() * ((+max || 0) - min + 1)); } /** * Resolves the value of `property` on `object`. If `property` is a function * it will be invoked and its result returned, else the property value is * returned. If `object` is falsey, then `null` is returned. * * @deprecated * @static * @memberOf _ * @category Utilities * @param {Object} object The object to inspect. * @param {String} property The property to get the value of. * @returns {Mixed} Returns the resolved value. * @example * * var object = { * 'cheese': 'crumpets', * 'stuff': function() { * return 'nonsense'; * } * }; * * _.result(object, 'cheese'); * // => 'crumpets' * * _.result(object, 'stuff'); * // => 'nonsense' */ function result(object, property) { // based on Backbone's private `getValue` function // https://github.com/documentcloud/backbone/blob/0.9.2/backbone.js#L1419-1424 var value = object ? object[property] : null; return isFunction(value) ? object[property]() : value; } /** * A micro-templating method that handles arbitrary delimiters, preserves * whitespace, and correctly escapes quotes within interpolated code. * * Note: In the development build `_.template` utilizes sourceURLs for easier * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl * * Note: Lo-Dash may be used in Chrome extensions by either creating a `lodash csp` * build and avoiding `_.template` use, or loading Lo-Dash in a sandboxed page. * See http://developer.chrome.com/trunk/extensions/sandboxingEval.html * * @static * @memberOf _ * @category Utilities * @param {String} text The template text. * @param {Obect} data The data object used to populate the text. * @param {Object} options The options object. * escape - The "escape" delimiter regexp. * evaluate - The "evaluate" delimiter regexp. * interpolate - The "interpolate" delimiter regexp. * sourceURL - The sourceURL of the template's compiled source. * variable - The data object variable name. * * @returns {Function|String} Returns a compiled function when no `data` object * is given, else it returns the interpolated text. * @example * * // using a compiled template * var compiled = _.template('hello <%= name %>'); * compiled({ 'name': 'moe' }); * // => 'hello moe' * * var list = '<% _.forEach(people, function(name) { %>
  • <%= name %>
  • <% }); %>'; * _.template(list, { 'people': ['moe', 'larry', 'curly'] }); * // => '
  • moe
  • larry
  • curly
  • ' * * // using the "escape" delimiter to escape HTML in data property values * _.template('<%- value %>', { 'value': '