| /*! |
| * Lo-Dash 0.10.0 <http://lodash.com> |
| * (c) 2012 John-David Dalton <http://allyoucanleet.com/> |
| * Based on Underscore.js 1.4.2 <http://underscorejs.org> |
| * (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. |
| * Available under MIT license <http://lodash.com/license> |
| */ |
| ;(function(window, undefined) { |
| |
| /** Detect free variable `exports` */ |
| var freeExports = typeof exports == 'object' && exports; |
| |
| /** Detect free variable `global` and use it as `window` */ |
| var freeGlobal = typeof global == 'object' && global; |
| if (freeGlobal.global === freeGlobal) { |
| window = freeGlobal; |
| } |
| |
| /** Used for array and object method references */ |
| var arrayRef = [], |
| // avoid a Closure Compiler bug by creatively creating an object |
| objectRef = new function(){}; |
| |
| /** Used to generate unique IDs */ |
| var idCounter = 0; |
| |
| /** Used internally to indicate various things */ |
| var indicatorObject = objectRef; |
| |
| /** Used by `cachedContains` as the default size when optimizations are enabled for large arrays */ |
| var largeArraySize = 30; |
| |
| /** Used to restore the original `_` reference in `noConflict` */ |
| var oldDash = window._; |
| |
| /** Used to detect template delimiter values that require a with-statement */ |
| var reComplexDelimiter = /[-?+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/; |
| |
| /** Used to match HTML entities */ |
| var reEscapedHtml = /&(?:amp|lt|gt|quot|#x27);/g; |
| |
| /** Used to match empty string literals in compiled template source */ |
| var reEmptyStringLeading = /\b__p \+= '';/g, |
| reEmptyStringMiddle = /\b(__p \+=) '' \+/g, |
| reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; |
| |
| /** Used to match regexp flags from their coerced string values */ |
| var reFlags = /\w*$/; |
| |
| /** Used to insert the data object variable into compiled template source */ |
| var reInsertVariable = /(?:__e|__t = )\(\s*(?![\d\s"']|this\.)/g; |
| |
| /** Used to detect if a method is native */ |
| var reNative = RegExp('^' + |
| (objectRef.valueOf + '') |
| .replace(/[.*+?^=!:${}()|[\]\/\\]/g, '\\$&') |
| .replace(/valueOf|for [^\]]+/g, '.+?') + '$' |
| ); |
| |
| /** |
| * Used to match ES6 template delimiters |
| * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-7.8.6 |
| */ |
| var reEsTemplate = /\$\{((?:(?=\\?)\\?[\s\S])*?)}/g; |
| |
| /** Used to match "interpolate" template delimiters */ |
| var reInterpolate = /<%=([\s\S]+?)%>/g; |
| |
| /** Used to ensure capturing order of template delimiters */ |
| var reNoMatch = /($^)/; |
| |
| /** Used to match HTML characters */ |
| var reUnescapedHtml = /[&<>"']/g; |
| |
| /** Used to match unescaped characters in compiled string literals */ |
| var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g; |
| |
| /** Used to fix the JScript [[DontEnum]] bug */ |
| var shadowed = [ |
| 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', |
| 'toLocaleString', 'toString', 'valueOf' |
| ]; |
| |
| /** Used to make template sourceURLs easier to identify */ |
| var templateCounter = 0; |
| |
| /** Native method shortcuts */ |
| var ceil = Math.ceil, |
| concat = arrayRef.concat, |
| floor = Math.floor, |
| getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf, |
| hasOwnProperty = objectRef.hasOwnProperty, |
| push = arrayRef.push, |
| propertyIsEnumerable = objectRef.propertyIsEnumerable, |
| 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 for `assign` and `defaults` */ |
| var assignIteratorOptions = { |
| 'args': 'object, source, guard', |
| 'top': |
| 'for (var argsIndex = 1, argsLength = typeof guard == \'number\' ? 2 : arguments.length; argsIndex < argsLength; argsIndex++) {\n' + |
| ' if ((iteratee = arguments[argsIndex])) {', |
| 'objectLoop': 'result[index] = value', |
| 'bottom': ' }\n}' |
| }; |
| |
| /** |
| * 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 `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, |
| key = thisArg; |
| |
| // juggle arguments |
| if (isPartial) { |
| partialArgs = thisArg; |
| } |
| if (!isFunc) { |
| thisArg = func; |
| } |
| |
| function bound() { |
| // `Function#bind` spec |
| // http://es5.github.com/#x15.3.4.5 |
| var args = arguments, |
| thisBinding = isPartial ? this : thisArg; |
| |
| if (!isFunc) { |
| func = thisArg[key]; |
| } |
| if (partialArgs.length) { |
| args = args.length |
| ? partialArgs.concat(slice.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]; |
| } |
| |
| /*--------------------------------------------------------------------------*/ |
| |
| /** |
| * Assigns own enumerable properties of source object(s) to the `destination` |
| * object. Subsequent sources will overwrite propery assignments of previous |
| * sources. |
| * |
| * @static |
| * @memberOf _ |
| * @alias extend |
| * @category Objects |
| * @param {Object} object The destination object. |
| * @param {Object} [source1, source2, ...] The source objects. |
| * @returns {Object} Returns the destination object. |
| * @example |
| * |
| * _.assign({ 'name': 'moe' }, { 'age': 40 }); |
| * // => { 'name': 'moe', 'age': 40 } |
| */ |
| var assign = createIterator(assignIteratorOptions); |
| |
| /** |
| * Checks if `value` is an `arguments` object. |
| * |
| * @static |
| * @memberOf _ |
| * @category Objects |
| * @param {Mixed} value The value to check. |
| * @returns {Boolean} Returns `true` if the `value` is an `arguments` object, else `false`. |
| * @example |
| * |
| * (function() { return _.isArguments(arguments); })(1, 2, 3); |
| * // => true |
| * |
| * _.isArguments([1, 2, 3]); |
| * // => false |
| */ |
| function isArguments(value) { |
| return toString.call(value) == argsClass; |
| } |
| // fallback for browsers that can't detect `arguments` objects by [[Class]] |
| if (noArgsClass) { |
| isArguments = function(value) { |
| return value ? hasOwnProperty.call(value, 'callee') : false; |
| }; |
| } |
| |
| /** |
| * Iterates over `object`'s own and inherited enumerable properties, executing |
| * the `callback` for each property. The `callback` is bound to `thisArg` and |
| * invoked with three arguments; (value, key, object). Callbacks may exit iteration |
| * early by explicitly returning `false`. |
| * |
| * @static |
| * @memberOf _ |
| * @category Objects |
| * @param {Object} object The object to iterate over. |
| * @param {Function} callback 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 an object's own enumerable properties, executing the `callback` |
| * for each property. The `callback` is bound to `thisArg` and invoked with three |
| * arguments; (value, key, object). Callbacks may exit iteration early by explicitly |
| * returning `false`. |
| * |
| * @static |
| * @memberOf _ |
| * @category Objects |
| * @param {Object} object The object to iterate over. |
| * @param {Function} callback 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) : assign({}, 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 own enumerable properties of source object(s) to the `destination` |
| * object for all `destination` properties that resolve to `null`/`undefined`. |
| * Once a property is set, additional defaults of the same property will be |
| * ignored. |
| * |
| * @static |
| * @memberOf _ |
| * @category Objects |
| * @param {Object} object The destination object. |
| * @param {Object} [default1, default2, ...] The default objects. |
| * @returns {Object} Returns the destination object. |
| * @example |
| * |
| * var iceCream = { 'flavor': 'chocolate' }; |
| * _.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'rainbow' }); |
| * // => { 'flavor': 'chocolate', 'sprinkles': 'rainbow' } |
| */ |
| var defaults = createIterator(assignIteratorOptions, { |
| 'objectLoop': 'if (result[index] == null) ' + assignIteratorOptions.objectLoop |
| }); |
| |
| /** |
| * Creates a sorted array of all enumerable properties, own and inherited, |
| * of `object` that have function values. |
| * |
| * @static |
| * @memberOf _ |
| * @alias methods |
| * @category Objects |
| * @param {Object} object The object to inspect. |
| * @returns {Array} Returns a new array of property names that have function values. |
| * @example |
| * |
| * _.functions(_); |
| * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...] |
| */ |
| function functions(object) { |
| var result = []; |
| forIn(object, function(value, key) { |
| if (isFunction(value)) { |
| result.push(key); |
| } |
| }); |
| return result.sort(); |
| } |
| |
| /** |
| * Checks if the specified object `property` exists and is a direct property, |
| * instead of an inherited property. |
| * |
| * @static |
| * @memberOf _ |
| * @category Objects |
| * @param {Object} object The object to check. |
| * @param {String} property The property to check for. |
| * @returns {Boolean} Returns `true` if key is a direct property, else `false`. |
| * @example |
| * |
| * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b'); |
| * // => true |
| */ |
| function has(object, property) { |
| return object ? hasOwnProperty.call(object, property) : false; |
| } |
| |
| /** |
| * Creates an object composed of the inverted keys and values of the given `object`. |
| * |
| * @static |
| * @memberOf _ |
| * @category Objects |
| * @param {Object} object The object to invert. |
| * @returns {Object} Returns the created inverted object. |
| * @example |
| * |
| * _.invert({ 'first': 'Moe', 'second': 'Larry', 'third': 'Curly' }); |
| * // => { 'Moe': 'first', 'Larry': 'second', 'Curly': 'third' } (order is not guaranteed) |
| */ |
| function invert(object) { |
| var result = {}; |
| forOwn(object, function(value, key) { |
| result[value] = key; |
| }); |
| return result; |
| } |
| |
| /** |
| * Checks if `value` is an array. |
| * |
| * @static |
| * @memberOf _ |
| * @category Objects |
| * @param {Mixed} value The value to check. |
| * @returns {Boolean} Returns `true` if the `value` is an array, else `false`. |
| * @example |
| * |
| * (function() { return _.isArray(arguments); })(); |
| * // => false |
| * |
| * _.isArray([1, 2, 3]); |
| * // => true |
| */ |
| var isArray = nativeIsArray || function(value) { |
| 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 !== indicatorObject) { |
| stackA = []; |
| stackB = []; |
| |
| // work with `_.reduce` by only using its callback `accumulator` and `value` arguments |
| if (typeof indicator != 'number') { |
| length = args.length; |
| } |
| } |
| while (++index < length) { |
| forOwn(args[index], function(source, key) { |
| var found, isArr, value; |
| if (source && ((isArr = isArray(source)) || isPlainObject(source))) { |
| // avoid merging previously merged cyclic sources |
| var stackLength = stackA.length; |
| while (stackLength--) { |
| found = stackA[stackLength] == source; |
| if (found) { |
| break; |
| } |
| } |
| if (found) { |
| object[key] = stackB[stackLength]; |
| } |
| else { |
| // add `source` and associated `value` to the stack of traversed objects |
| stackA.push(source); |
| stackB.push(value = (value = object[key], isArr) |
| ? (isArray(value) ? value : []) |
| : (isPlainObject(value) ? value : {}) |
| ); |
| // recursively merge objects and arrays (susceptible to call stack limits) |
| object[key] = merge(value, source, indicatorObject, stackA, stackB); |
| } |
| } else if (source != null) { |
| object[key] = source; |
| } |
| }); |
| } |
| return object; |
| } |
| |
| /** |
| * Creates a shallow clone of `object` excluding the specified properties. |
| * Property names may be specified as individual arguments or as arrays of |
| * property names. If `callback` is passed, it will be executed for each property |
| * in the `object`, omitting the properties `callback` returns truthy for. The |
| * `callback` is bound to `thisArg` and invoked with three arguments; (value, key, object). |
| * |
| * @static |
| * @memberOf _ |
| * @category Objects |
| * @param {Object} object The source object. |
| * @param {Function|String} callback|[prop1, prop2, ...] The properties to omit |
| * or the function called per iteration. |
| * @param {Mixed} [thisArg] The `this` binding of `callback`. |
| * @returns {Object} Returns an object without the omitted properties. |
| * @example |
| * |
| * _.omit({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'userid'); |
| * // => { 'name': 'moe', 'age': 40 } |
| * |
| * _.omit({ 'name': 'moe', '_hint': 'knucklehead', '_seed': '96c4eb' }, function(value, key) { |
| * return key.charAt(0) == '_'; |
| * }); |
| * // => { 'name': 'moe' } |
| */ |
| function omit(object, callback, thisArg) { |
| var isFunc = typeof callback == 'function', |
| result = {}; |
| |
| if (isFunc) { |
| callback = createCallback(callback, thisArg); |
| } else { |
| var props = concat.apply(arrayRef, arguments); |
| } |
| forIn(object, function(value, key, object) { |
| if (isFunc |
| ? !callback(value, key, object) |
| : indexOf(props, key, 1) < 0 |
| ) { |
| result[key] = value; |
| } |
| }); |
| return result; |
| } |
| |
| /** |
| * Creates a two dimensional array of the given object's key-value pairs, |
| * i.e. `[[key1, value1], [key2, value2]]`. |
| * |
| * @static |
| * @memberOf _ |
| * @category Objects |
| * @param {Object} object The object to inspect. |
| * @returns {Array} Returns new array of key-value pairs. |
| * @example |
| * |
| * _.pairs({ 'moe': 30, 'larry': 40, 'curly': 50 }); |
| * // => [['moe', 30], ['larry', 40], ['curly', 50]] (order is not guaranteed) |
| */ |
| function pairs(object) { |
| var result = []; |
| forOwn(object, function(value, key) { |
| result.push([key, value]); |
| }); |
| return result; |
| } |
| |
| /** |
| * Creates a shallow clone of `object` composed of the specified properties. |
| * Property names may be specified as individual arguments or as arrays of |
| * property names. If `callback` is passed, it will be executed for each property |
| * in the `object`, picking the properties `callback` returns truthy for. The |
| * `callback` is bound to `thisArg` and invoked with three arguments; (value, key, object). |
| * |
| * @static |
| * @memberOf _ |
| * @category Objects |
| * @param {Object} object The source object. |
| * @param {Function|String} callback|[prop1, prop2, ...] The properties to pick |
| * or the function called per iteration. |
| * @param {Mixed} [thisArg] The `this` binding of `callback`. |
| * @returns {Object} Returns an object composed of the picked properties. |
| * @example |
| * |
| * _.pick({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'name', 'age'); |
| * // => { 'name': 'moe', 'age': 40 } |
| * |
| * _.pick({ 'name': 'moe', '_hint': 'knucklehead', '_seed': '96c4eb' }, function(value, key) { |
| * return key.charAt(0) != '_'; |
| * }); |
| * // => { 'name': 'moe' } |
| */ |
| function pick(object, callback, thisArg) { |
| var result = {}; |
| if (typeof callback != 'function') { |
| var index = 0, |
| props = concat.apply(arrayRef, arguments), |
| length = props.length; |
| |
| while (++index < length) { |
| var key = props[index]; |
| if (key in object) { |
| result[key] = object[key]; |
| } |
| } |
| } else { |
| callback = createCallback(callback, thisArg); |
| forIn(object, function(value, key, object) { |
| if (callback(value, key, object)) { |
| result[key] = value; |
| } |
| }); |
| } |
| return result; |
| } |
| |
| /** |
| * Creates an array composed of the own enumerable property values of `object`. |
| * |
| * @static |
| * @memberOf _ |
| * @category Objects |
| * @param {Object} object The object to inspect. |
| * @returns {Array} Returns a new array of property values. |
| * @example |
| * |
| * _.values({ 'one': 1, 'two': 2, 'three': 3 }); |
| * // => [1, 2, 3] |
| */ |
| function values(object) { |
| var result = []; |
| forOwn(object, function(value) { |
| result.push(value); |
| }); |
| return result; |
| } |
| |
| /*--------------------------------------------------------------------------*/ |
| |
| /** |
| * Checks if a given `target` element is present in a `collection` using strict |
| * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used |
| * as the offset from the end of the collection. |
| * |
| * @static |
| * @memberOf _ |
| * @alias include |
| * @category Collections |
| * @param {Array|Object|String} collection The collection to iterate over. |
| * @param {Mixed} target The value to check for. |
| * @param {Number} [fromIndex=0] The index to search from. |
| * @returns {Boolean} Returns `true` if the `target` element is found, else `false`. |
| * @example |
| * |
| * _.contains([1, 2, 3], 1); |
| * // => true |
| * |
| * _.contains([1, 2, 3], 1, 2); |
| * // => false |
| * |
| * _.contains({ 'name': 'moe', 'age': 40 }, 'moe'); |
| * // => true |
| * |
| * _.contains('curly', 'ur'); |
| * // => true |
| */ |
| function contains(collection, target, fromIndex) { |
| var index = -1, |
| length = collection ? collection.length : 0, |
| result = false; |
| |
| fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0; |
| if (typeof length == 'number') { |
| result = (isString(collection) |
| ? collection.indexOf(target, fromIndex) |
| : indexOf(collection, target, fromIndex) |
| ) > -1; |
| } else { |
| forEach(collection, function(value) { |
| if (++index >= fromIndex) { |
| return !(result = value === target); |
| } |
| }); |
| } |
| return result; |
| } |
| |
| /** |
| * Creates an object composed of keys returned from running each element of |
| * `collection` through a `callback`. The corresponding value of each key is |
| * the number of times the key was returned by `callback`. The `callback` is |
| * bound to `thisArg` and invoked with three arguments; (value, index|key, collection). |
| * The `callback` argument may also be the name of a property to count by (e.g. 'length'). |
| * |
| * @static |
| * @memberOf _ |
| * @category Collections |
| * @param {Array|Object|String} collection The collection to iterate over. |
| * @param {Function|String} callback|property The function called per iteration |
| * or property name to count by. |
| * @param {Mixed} [thisArg] The `this` binding of `callback`. |
| * @returns {Object} Returns the composed aggregate object. |
| * @example |
| * |
| * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); }); |
| * // => { '4': 1, '6': 2 } |
| * |
| * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math); |
| * // => { '4': 1, '6': 2 } |
| * |
| * _.countBy(['one', 'two', 'three'], 'length'); |
| * // => { '3': 2, '5': 1 } |
| */ |
| function countBy(collection, callback, thisArg) { |
| var result = {}; |
| callback = createCallback(callback, thisArg); |
| forEach(collection, function(value, key, collection) { |
| key = callback(value, key, collection); |
| (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1); |
| }); |
| return result; |
| } |
| |
| /** |
| * Checks if the `callback` returns a truthy value for **all** elements of a |
| * `collection`. The `callback` is bound to `thisArg` and invoked with three |
| * arguments; (value, index|key, collection). |
| * |
| * @static |
| * @memberOf _ |
| * @alias all |
| * @category Collections |
| * @param {Array|Object|String} collection The collection to iterate over. |
| * @param {Function} [callback=identity] The function called per iteration. |
| * @param {Mixed} [thisArg] The `this` binding of `callback`. |
| * @returns {Boolean} Returns `true` if all elements pass the callback check, |
| * else `false`. |
| * @example |
| * |
| * _.every([true, 1, null, 'yes'], Boolean); |
| * // => false |
| */ |
| function every(collection, callback, thisArg) { |
| var result = true; |
| callback = createCallback(callback, thisArg); |
| |
| if (isArray(collection)) { |
| var index = -1, |
| length = collection.length; |
| |
| while (++index < length) { |
| if (!(result = !!callback(collection[index], index, collection))) { |
| break; |
| } |
| } |
| } else { |
| 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); |
| |
| if (isArray(collection)) { |
| var index = -1, |
| length = collection.length; |
| |
| while (++index < length) { |
| var value = collection[index]; |
| if (callback(value, index, collection)) { |
| result.push(value); |
| } |
| } |
| } else { |
| 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], Boolean); |
| * // => true |
| */ |
| function some(collection, callback, thisArg) { |
| var result; |
| callback = createCallback(callback, thisArg); |
| |
| if (isArray(collection)) { |
| var index = -1, |
| length = collection.length; |
| |
| while (++index < length) { |
| if ((result = callback(collection[index], index, collection))) { |
| break; |
| } |
| } |
| } else { |
| 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 = keys(properties); |
| return filter(collection, function(object) { |
| var length = props.length; |
| while (length--) { |
| var result = object[props[length]] === properties[props[length]]; |
| if (!result) { |
| break; |
| } |
| } |
| return !!result; |
| }); |
| } |
| |
| /*--------------------------------------------------------------------------*/ |
| |
| /** |
| * Creates an array with all falsey values of `array` removed. The values |
| * `false`, `null`, `0`, `""`, `undefined` and `NaN` are all falsey. |
| * |
| * @static |
| * @memberOf _ |
| * @category Arrays |
| * @param {Array} array The array to compact. |
| * @returns {Array} Returns a new filtered array. |
| * @example |
| * |
| * _.compact([0, 1, false, 2, '', 3]); |
| * // => [1, 2, 3] |
| */ |
| function compact(array) { |
| var index = -1, |
| length = array ? array.length : 0, |
| result = []; |
| |
| while (++index < length) { |
| var value = array[index]; |
| if (value) { |
| result.push(value); |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Creates an array of `array` elements not present in the other arrays |
| * using strict equality for comparisons, i.e. `===`. |
| * |
| * @static |
| * @memberOf _ |
| * @category Arrays |
| * @param {Array} array The array to process. |
| * @param {Array} [array1, array2, ...] Arrays to check. |
| * @returns {Array} Returns a new array of `array` elements not present in the |
| * other arrays. |
| * @example |
| * |
| * _.difference([1, 2, 3, 4, 5], [5, 2, 10]); |
| * // => [1, 3, 4] |
| */ |
| function difference(array) { |
| var index = -1, |
| length = array ? array.length : 0, |
| flattened = concat.apply(arrayRef, arguments), |
| contains = cachedContains(flattened, length), |
| result = []; |
| |
| while (++index < length) { |
| var value = array[index]; |
| if (!contains(value)) { |
| result.push(value); |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Gets the first element of the `array`. Pass `n` to return the first `n` |
| * elements of the `array`. |
| * |
| * @static |
| * @memberOf _ |
| * @alias head, take |
| * @category Arrays |
| * @param {Array} array The array to query. |
| * @param {Number} [n] The number of elements to return. |
| * @param- {Object} [guard] Internally used to allow this method to work with |
| * others like `_.map` without using their callback `index` argument for `n`. |
| * @returns {Mixed} Returns the first element or an array of the first `n` |
| * elements of `array`. |
| * @example |
| * |
| * _.first([5, 4, 3, 2, 1]); |
| * // => 5 |
| */ |
| function first(array, n, guard) { |
| if (array) { |
| 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, when called, invokes the method at `object[key]` |
| * and prepends any additional `bindKey` arguments to those passed to the bound |
| * function. This method differs from `_.bind` by allowing bound functions to |
| * reference methods that will be redefined or don't yet exist. |
| * See http://michaux.ca/articles/lazy-function-definition-pattern. |
| * |
| * @static |
| * @memberOf _ |
| * @category Functions |
| * @param {Object} object The object the method belongs to. |
| * @param {String} key The key of the method. |
| * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied. |
| * @returns {Function} Returns the new bound function. |
| * @example |
| * |
| * var object = { |
| * 'name': 'moe', |
| * 'greet': function(greeting) { |
| * return greeting + ' ' + this.name; |
| * } |
| * }; |
| * |
| * var func = _.bindKey(object, 'greet', 'hi'); |
| * func(); |
| * // => 'hi moe' |
| * |
| * object.greet = function(greeting) { |
| * return greeting + ', ' + this.name + '!'; |
| * }; |
| * |
| * func(); |
| * // => 'hi, moe!' |
| */ |
| function bindKey(object, key) { |
| return createBound(object, key, slice.call(arguments, 2)); |
| } |
| |
| /** |
| * Creates a function that is the composition of the passed functions, |
| * where each function consumes the return value of the function that follows. |
| * In math terms, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`. |
| * Each function is executed with the `this` binding of the composed function. |
| * |
| * @static |
| * @memberOf _ |
| * @category Functions |
| * @param {Function} [func1, func2, ...] Functions to compose. |
| * @returns {Function} Returns the new composed function. |
| * @example |
| * |
| * var greet = function(name) { return 'hi: ' + name; }; |
| * var exclaim = function(statement) { return statement + '!'; }; |
| * var welcome = _.compose(exclaim, greet); |
| * welcome('moe'); |
| * // => 'hi: moe!' |
| */ |
| function compose() { |
| var funcs = arguments; |
| return function() { |
| var args = arguments, |
| length = funcs.length; |
| |
| while (length--) { |
| args = [funcs[length].apply(this, args)]; |
| } |
| return args[0]; |
| }; |
| } |
| |
| /** |
| * Creates a function that will delay the execution of `func` until after |
| * `wait` milliseconds have elapsed since the last time it was invoked. Pass |
| * `true` for `immediate` to cause debounce to invoke `func` on the leading, |
| * instead of the trailing, edge of the `wait` timeout. Subsequent calls to |
| * the debounced function will return the result of the last `func` call. |
| * |
| * @static |
| * @memberOf _ |
| * @category Functions |
| * @param {Function} func The function to debounce. |
| * @param {Number} wait The number of milliseconds to delay. |
| * @param {Boolean} immediate A flag to indicate execution is on the leading |
| * edge of the timeout. |
| * @returns {Function} Returns the new debounced function. |
| * @example |
| * |
| * var lazyLayout = _.debounce(calculateLayout, 300); |
| * jQuery(window).on('resize', lazyLayout); |
| */ |
| function debounce(func, wait, immediate) { |
| var args, |
| result, |
| thisArg, |
| timeoutId; |
| |
| function delayed() { |
| timeoutId = null; |
| if (!immediate) { |
| result = func.apply(thisArg, args); |
| } |
| } |
| return function() { |
| var isImmediate = immediate && !timeoutId; |
| args = arguments; |
| thisArg = this; |
| |
| clearTimeout(timeoutId); |
| timeoutId = setTimeout(delayed, wait); |
| |
| if (isImmediate) { |
| result = func.apply(thisArg, args); |
| } |
| return result; |
| }; |
| } |
| |
| /** |
| * Executes the `func` function after `wait` milliseconds. Additional arguments |
| * will be passed to `func` when it is invoked. |
| * |
| * @static |
| * @memberOf _ |
| * @category Functions |
| * @param {Function} func The function to delay. |
| * @param {Number} wait The number of milliseconds to delay execution. |
| * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with. |
| * @returns {Number} Returns the `setTimeout` timeout id. |
| * @example |
| * |
| * var log = _.bind(console.log, console); |
| * _.delay(log, 1000, 'logged later'); |
| * // => 'logged later' (Appears after one second.) |
| */ |
| function delay(func, wait) { |
| var args = slice.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 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) { %><li><%= name %></li><% }); %>'; |
| * _.template(list, { 'people': ['moe', 'larry', 'curly'] }); |
| * // => '<li>moe</li><li>larry</li><li>curly</li>' |
| * |
| * // using the "escape" delimiter to escape HTML in data property values |
| * _.template('<b><%- value %></b>', { 'value': '<script>' }); |
| * // => '<b><script></b>' |
| * |
| * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter |
| * _.template('hello ${ name }', { 'name': 'curly' }); |
| * // => 'hello curly' |
| * |
| * // using the internal `print` function in "evaluate" delimiters |
| * _.template('<% print("hello " + epithet); %>!', { 'epithet': 'stooge' }); |
| * // => 'hello stooge!' |
| * |
| * // using custom template delimiters |
| * _.templateSettings = { |
| * 'interpolate': /{{([\s\S]+?)}}/g |
| * }; |
| * |
| * _.template('hello {{ name }}!', { 'name': 'mustache' }); |
| * // => 'hello mustache!' |
| * |
| * // using the `sourceURL` option to specify a custom sourceURL for the template |
| * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' }); |
| * compiled(data); |
| * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector |
| * |
| * // using the `variable` option to ensure a with-statement isn't used in the compiled template |
| * var compiled = _.template('hello <%= data.name %>!', null, { 'variable': 'data' }); |
| * compiled.source; |
| * // => function(data) { |
| * var __t, __p = '', __e = _.escape; |
| * __p += 'hello ' + ((__t = ( data.name )) == null ? '' : __t) + '!'; |
| * return __p; |
| * } |
| * |
| * // using the `source` property to inline compiled templates for meaningful |
| * // line numbers in error messages and a stack trace |
| * fs.writeFileSync(path.join(cwd, 'jst.js'), '\ |
| * var JST = {\ |
| * "main": ' + _.template(mainText).source + '\ |
| * };\ |
| * '); |
| */ |
| function template(text, data, options) { |
| // based on John Resig's `tmpl` implementation |
| // http://ejohn.org/blog/javascript-micro-templating/ |
| // and Laura Doktorova's doT.js |
| // https://github.com/olado/doT |
| text || (text = ''); |
| options || (options = {}); |
| |
| var isEvaluating, |
| result, |
| settings = lodash.templateSettings, |
| index = 0, |
| interpolate = options.interpolate || settings.interpolate || reNoMatch, |
| source = "__p += '", |
| variable = options.variable || settings.variable, |
| hasVariable = variable; |
| |
| // compile regexp to match each delimiter |
| var reDelimiters = RegExp( |
| (options.escape || settings.escape || reNoMatch).source + '|' + |
| interpolate.source + '|' + |
| (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' + |
| (options.evaluate || settings.evaluate || reNoMatch).source + '|$' |
| , 'g'); |
| |
| text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) { |
| interpolateValue || (interpolateValue = esTemplateValue); |
| |
| // escape characters that cannot be included in string literals |
| source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar); |
| |
| // replace delimiters with snippets |
| source += |
| escapeValue ? "' +\n__e(" + escapeValue + ") +\n'" : |
| evaluateValue ? "';\n" + evaluateValue + ";\n__p += '" : |
| interpolateValue ? "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'" : ''; |
| |
| isEvaluating || (isEvaluating = evaluateValue || reComplexDelimiter.test(escapeValue || interpolateValue)); |
| index = offset + match.length; |
| }); |
| |
| source += "';\n"; |
| |
| // if `variable` is not specified and the template contains "evaluate" |
| // delimiters, wrap a with-statement around the generated code to add the |
| // data object to the top of the scope chain |
| if (!hasVariable) { |
| variable = 'obj'; |
| if (isEvaluating) { |
| source = 'with (' + variable + ') {\n' + source + '\n}\n'; |
| } |
| else { |
| // avoid a with-statement by prepending data object references to property names |
| var reDoubleVariable = RegExp('(\\(\\s*)' + variable + '\\.' + variable + '\\b', 'g'); |
| source = source |
| .replace(reInsertVariable, '$&' + variable + '.') |
| .replace(reDoubleVariable, '$1__d'); |
| } |
| } |
| |
| // cleanup code by stripping empty strings |
| source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source) |
| .replace(reEmptyStringMiddle, '$1') |
| .replace(reEmptyStringTrailing, '$1;'); |
| |
| // frame code as the function body |
| source = 'function(' + variable + ') {\n' + |
| (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') + |
| 'var __t, __p = \'\', __e = _.escape' + |
| (isEvaluating |
| ? ', __j = Array.prototype.join;\n' + |
| 'function print() { __p += __j.call(arguments, \'\') }\n' |
| : (hasVariable ? '' : ', __d = ' + variable + '.' + variable + ' || ' + variable) + ';\n' |
| ) + |
| source + |
| 'return __p\n}'; |
| |
| // use a sourceURL for easier debugging |
| // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl |
| var sourceURL = useSourceURL |
| ? '\n//@ sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') |
| : ''; |
| |
| try { |
| result = Function('_', 'return ' + source + sourceURL)(lodash); |
| } catch(e) { |
| e.source = source; |
| throw e; |
| } |
| |
| if (data) { |
| return result(data); |
| } |
| // provide the compiled function's source via its `toString` method, in |
| // supported environments, or the `source` property as a convenience for |
| // inlining compiled templates during the build process |
| result.source = source; |
| return result; |
| } |
| |
| /** |
| * Executes the `callback` function `n` times, returning an array of the results |
| * of each `callback` execution. The `callback` is bound to `thisArg` and invoked |
| * with one argument; (index). |
| * |
| * @static |
| * @memberOf _ |
| * @category Utilities |
| * @param {Number} n The number of times to execute the callback. |
| * @param {Function} callback The function called per iteration. |
| * @param {Mixed} [thisArg] The `this` binding of `callback`. |
| * @returns {Array} Returns a new array of the results of each `callback` execution. |
| * @example |
| * |
| * var diceRolls = _.times(3, _.partial(_.random, 1, 6)); |
| * // => [3, 6, 4] |
| * |
| * _.times(3, function(n) { mage.castSpell(n); }); |
| * // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively |
| * |
| * _.times(3, function(n) { this.cast(n); }, mage); |
| * // => also calls `mage.castSpell(n)` three times |
| */ |
| function times(n, callback, thisArg) { |
| n = +n || 0; |
| var index = -1, |
| result = Array(n); |
| |
| while (++index < n) { |
| result[index] = callback.call(thisArg, index); |
| } |
| return result; |
| } |
| |
| /** |
| * The opposite of `_.escape`, this method converts the HTML entities |
| * `&`, `<`, `>`, `"`, and `'` in `string` to their |
| * corresponding characters. |
| * |
| * @static |
| * @memberOf _ |
| * @category Utilities |
| * @param {String} string The string to unescape. |
| * @returns {String} Returns the unescaped string. |
| * @example |
| * |
| * _.unescape('Moe, Larry & Curly'); |
| * // => "Moe, Larry & Curly" |
| */ |
| function unescape(string) { |
| return string == null ? '' : (string + '').replace(reEscapedHtml, unescapeHtmlChar); |
| } |
| |
| /** |
| * Generates a unique id. If `prefix` is passed, the id will be appended to it. |
| * |
| * @static |
| * @memberOf _ |
| * @category Utilities |
| * @param {String} [prefix] The value to prefix the id with. |
| * @returns {Number|String} Returns a numeric id if no prefix is passed, else |
| * a string id may be returned. |
| * @example |
| * |
| * _.uniqueId('contact_'); |
| * // => 'contact_104' |
| */ |
| function uniqueId(prefix) { |
| var id = idCounter++; |
| return prefix ? prefix + id : id; |
| } |
| |
| /*--------------------------------------------------------------------------*/ |
| |
| /** |
| * Wraps the value in a `lodash` wrapper object. |
| * |
| * @static |
| * @memberOf _ |
| * @category Chaining |
| * @param {Mixed} value The value to wrap. |
| * @returns {Object} Returns the wrapper object. |
| * @example |
| * |
| * var stooges = [ |
| * { 'name': 'moe', 'age': 40 }, |
| * { 'name': 'larry', 'age': 50 }, |
| * { 'name': 'curly', 'age': 60 } |
| * ]; |
| * |
| * var youngest = _.chain(stooges) |
| * .sortBy(function(stooge) { return stooge.age; }) |
| * .map(function(stooge) { return stooge.name + ' is ' + stooge.age; }) |
| * .first() |
| * .value(); |
| * // => 'moe is 40' |
| */ |
| function chain(value) { |
| value = new lodash(value); |
| value.__chain__ = true; |
| return value; |
| } |
| |
| /** |
| * Invokes `interceptor` with the `value` as the first argument, and then |
| * returns `value`. The purpose of this method is to "tap into" a method chain, |
| * in order to perform operations on intermediate results within the chain. |
| * |
| * @static |
| * @memberOf _ |
| * @category Chaining |
| * @param {Mixed} value The value to pass to `interceptor`. |
| * @param {Function} interceptor The function to invoke. |
| * @returns {Mixed} Returns `value`. |
| * @example |
| * |
| * _.chain([1, 2, 3, 200]) |
| * .filter(function(num) { return num % 2 == 0; }) |
| * .tap(alert) |
| * .map(function(num) { return num * num }) |
| * .value(); |
| * // => // [2, 200] (alerted) |
| * // => [4, 40000] |
| */ |
| function tap(value, interceptor) { |
| interceptor(value); |
| return value; |
| } |
| |
| /** |
| * Enables method chaining on the wrapper object. |
| * |
| * @name chain |
| * @deprecated |
| * @memberOf _ |
| * @category Chaining |
| * @returns {Mixed} Returns the wrapper object. |
| * @example |
| * |
| * _([1, 2, 3]).value(); |
| * // => [1, 2, 3] |
| */ |
| function wrapperChain() { |
| this.__chain__ = true; |
| return this; |
| } |
| |
| /** |
| * Extracts the wrapped value. |
| * |
| * @name value |
| * @memberOf _ |
| * @category Chaining |
| * @returns {Mixed} Returns the wrapped value. |
| * @example |
| * |
| * _([1, 2, 3]).value(); |
| * // => [1, 2, 3] |
| */ |
| function wrapperValue() { |
| return this.__wrapped__; |
| } |
| |
| /*--------------------------------------------------------------------------*/ |
| |
| /** |
| * The semantic version number. |
| * |
| * @static |
| * @memberOf _ |
| * @type String |
| */ |
| lodash.VERSION = '0.10.0'; |
| |
| // assign static methods |
| lodash.assign = assign; |
| lodash.after = after; |
| lodash.bind = bind; |
| lodash.bindAll = bindAll; |
| lodash.bindKey = bindKey; |
| lodash.chain = chain; |
| lodash.clone = clone; |
| lodash.compact = compact; |
| lodash.compose = compose; |
| lodash.contains = contains; |
| lodash.countBy = countBy; |
| lodash.debounce = debounce; |
| lodash.defaults = defaults; |
| lodash.defer = defer; |
| lodash.delay = delay; |
| lodash.difference = difference; |
| lodash.escape = escape; |
| lodash.every = every; |
| lodash.filter = filter; |
| lodash.find = find; |
| lodash.first = first; |
| lodash.flatten = flatten; |
| lodash.forEach = forEach; |
| lodash.forIn = forIn; |
| lodash.forOwn = forOwn; |
| lodash.functions = functions; |
| lodash.groupBy = groupBy; |
| lodash.has = has; |
| lodash.identity = identity; |
| lodash.indexOf = indexOf; |
| lodash.initial = initial; |
| lodash.intersection = intersection; |
| lodash.invert = invert; |
| lodash.invoke = invoke; |
| lodash.isArguments = isArguments; |
| lodash.isArray = isArray; |
| lodash.isBoolean = isBoolean; |
| lodash.isDate = isDate; |
| lodash.isElement = isElement; |
| lodash.isEmpty = isEmpty; |
| lodash.isEqual = isEqual; |
| lodash.isFinite = isFinite; |
| lodash.isFunction = isFunction; |
| lodash.isNaN = isNaN; |
| lodash.isNull = isNull; |
| lodash.isNumber = isNumber; |
| lodash.isObject = isObject; |
| lodash.isPlainObject = isPlainObject; |
| lodash.isRegExp = isRegExp; |
| lodash.isString = isString; |
| lodash.isUndefined = isUndefined; |
| lodash.keys = keys; |
| lodash.last = last; |
| lodash.lastIndexOf = lastIndexOf; |
| lodash.map = map; |
| lodash.max = max; |
| lodash.memoize = memoize; |
| lodash.merge = merge; |
| lodash.min = min; |
| lodash.mixin = mixin; |
| lodash.noConflict = noConflict; |
| lodash.object = object; |
| lodash.omit = omit; |
| lodash.once = once; |
| lodash.pairs = pairs; |
| lodash.partial = partial; |
| lodash.pick = pick; |
| lodash.pluck = pluck; |
| lodash.random = random; |
| lodash.range = range; |
| lodash.reduce = reduce; |
| lodash.reduceRight = reduceRight; |
| lodash.reject = reject; |
| lodash.rest = rest; |
| lodash.result = result; |
| lodash.shuffle = shuffle; |
| lodash.size = size; |
| lodash.some = some; |
| lodash.sortBy = sortBy; |
| lodash.sortedIndex = sortedIndex; |
| lodash.tap = tap; |
| lodash.template = template; |
| lodash.throttle = throttle; |
| lodash.times = times; |
| lodash.toArray = toArray; |
| lodash.unescape = unescape; |
| lodash.union = union; |
| lodash.uniq = uniq; |
| lodash.uniqueId = uniqueId; |
| lodash.values = values; |
| lodash.where = where; |
| lodash.without = without; |
| lodash.wrap = wrap; |
| lodash.zip = zip; |
| |
| // assign aliases |
| lodash.all = every; |
| lodash.any = some; |
| lodash.collect = map; |
| lodash.detect = find; |
| lodash.drop = rest; |
| lodash.each = forEach; |
| lodash.extend = assign; |
| lodash.foldl = reduce; |
| lodash.foldr = reduceRight; |
| lodash.head = first; |
| lodash.include = contains; |
| lodash.inject = reduce; |
| lodash.methods = functions; |
| lodash.select = filter; |
| lodash.tail = rest; |
| lodash.take = first; |
| lodash.unique = uniq; |
| |
| // add pseudo private property to be used and removed during the build process |
| lodash._iteratorTemplate = iteratorTemplate; |
| |
| /*--------------------------------------------------------------------------*/ |
| |
| // add all static functions to `lodash.prototype` |
| mixin(lodash); |
| |
| // add `lodash.prototype.chain` after calling `mixin()` to avoid overwriting |
| // it with the wrapped `lodash.chain` |
| lodash.prototype.chain = wrapperChain; |
| lodash.prototype.value = wrapperValue; |
| |
| // add all mutator Array functions to the wrapper. |
| forEach(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(methodName) { |
| var func = arrayRef[methodName]; |
| |
| lodash.prototype[methodName] = function() { |
| var value = this.__wrapped__; |
| func.apply(value, arguments); |
| |
| // avoid array-like object bugs with `Array#shift` and `Array#splice` in |
| // Firefox < 10 and IE < 9 |
| if (hasObjectSpliceBug && value.length === 0) { |
| delete value[0]; |
| } |
| if (this.__chain__) { |
| value = new lodash(value); |
| value.__chain__ = true; |
| } |
| return value; |
| }; |
| }); |
| |
| // add all accessor Array functions to the wrapper. |
| forEach(['concat', 'join', 'slice'], function(methodName) { |
| var func = arrayRef[methodName]; |
| |
| lodash.prototype[methodName] = function() { |
| var value = this.__wrapped__, |
| result = func.apply(value, arguments); |
| |
| if (this.__chain__) { |
| result = new lodash(result); |
| result.__chain__ = true; |
| } |
| return result; |
| }; |
| }); |
| |
| /*--------------------------------------------------------------------------*/ |
| |
| // expose Lo-Dash |
| // some AMD build optimizers, like r.js, check for specific condition patterns like the following: |
| if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { |
| // Expose Lo-Dash to the global object even when an AMD loader is present in |
| // case Lo-Dash was injected by a third-party script and not intended to be |
| // loaded as a module. The global assignment can be reverted in the Lo-Dash |
| // module via its `noConflict()` method. |
| window._ = lodash; |
| |
| // define as an anonymous module so, through path mapping, it can be |
| // referenced as the "underscore" module |
| define(function() { |
| return lodash; |
| }); |
| } |
| // check for `exports` after `define` in case a build optimizer adds an `exports` object |
| else if (freeExports) { |
| // in Node.js or RingoJS v0.8.0+ |
| if (typeof module == 'object' && module && module.exports == freeExports) { |
| (module.exports = lodash)._ = lodash; |
| } |
| // in Narwhal or RingoJS v0.7.0- |
| else { |
| freeExports._ = lodash; |
| } |
| } |
| else { |
| // in a browser or Rhino |
| window._ = lodash; |
| } |
| }(this)); |