/** * @license * Lo-Dash 1.3.0 (Custom Build) <http://lodash.com/> * Build: `lodash minus="template" -d` * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/> * Based on Underscore.js 1.4.4 <http://underscorejs.org/> * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud Inc. * Available under MIT license <http://lodash.com/license> */ ;(function(window) { /** Used as a safe reference for `undefined` in pre ES5 environments */ var undefined; /** Used to pool arrays and objects used internally */ var arrayPool = [], objectPool = []; /** Used to generate unique IDs */ var idCounter = 0; /** Used internally to indicate various things */ var indicatorObject = {}; /** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */ var keyPrefix = +new Date + ''; /** Used as the size when optimizations are enabled for large arrays */ var largeArraySize = 75; /** Used as the max size of the `arrayPool` and `objectPool` */ var maxPoolSize = 10; /** 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 HTML entities */ var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g; /** * Used to match ES6 template delimiters * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-7.8.6 */ var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; /** Used to match regexp flags from their coerced string values */ var reFlags = /\w*$/; /** Used to match "interpolate" template delimiters */ var reInterpolate = /<%=([\s\S]+?)%>/g; /** Used to detect functions containing a `this` reference */ var reThis = (reThis = /\bthis\b/) && reThis.test(runInContext) && reThis; /** Used to detect and test whitespace */ var whitespace = ( // whitespace ' \t\x0B\f\xA0\ufeff' + // line terminators '\n\r\u2028\u2029' + // unicode category "Zs" space separators '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000' ); /** Used to match leading whitespace and zeros to be removed */ var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)'); /** Used to ensure capturing order of template delimiters */ var reNoMatch = /($^)/; /** Used to match HTML characters */ var reUnescapedHtml = /[&<>"']/g; /** Used to match unescaped characters in compiled string literals */ var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g; /** Used to assign default `context` object properties */ var contextProps = [ 'Array', 'Boolean', 'Date', 'Error', 'Function', 'Math', 'Number', 'Object', 'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN', 'parseInt', 'setImmediate', 'setTimeout' ]; /** Used to fix the JScript [[DontEnum]] bug */ var shadowedProps = [ 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf' ]; /** Used to make template sourceURLs easier to identify */ var templateCounter = 0; /** `Object#toString` result shortcuts */ var argsClass = '[object Arguments]', arrayClass = '[object Array]', boolClass = '[object Boolean]', dateClass = '[object Date]', errorClass = '[object Error]', funcClass = '[object Function]', numberClass = '[object Number]', objectClass = '[object Object]', regexpClass = '[object RegExp]', stringClass = '[object String]'; /** Used to identify object classifications that `_.clone` supports */ var cloneableClasses = {}; cloneableClasses[funcClass] = false; cloneableClasses[argsClass] = cloneableClasses[arrayClass] = cloneableClasses[boolClass] = cloneableClasses[dateClass] = cloneableClasses[numberClass] = cloneableClasses[objectClass] = cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true; /** Used to determine if values are of the language type Object */ var objectTypes = { 'boolean': false, 'function': true, 'object': true, 'number': false, 'string': false, 'undefined': false }; /** Used to escape characters for inclusion in compiled string literals */ var stringEscapes = { '\\': '\\', "'": "'", '\n': 'n', '\r': 'r', '\t': 't', '\u2028': 'u2028', '\u2029': 'u2029' }; /** Detect free variable `exports` */ var freeExports = objectTypes[typeof exports] && exports; /** Detect free variable `module` */ var freeModule = objectTypes[typeof module] && module && module.exports == freeExports && module; /** Detect free variable `global`, from Node.js or Browserified code, and use it as `window` */ var freeGlobal = objectTypes[typeof global] && global; if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) { window = freeGlobal; } /*--------------------------------------------------------------------------*/ /** * A basic implementation of `_.indexOf` without support for binary searches * or `fromIndex` constraints. * * @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. * @returns {Number} Returns the index of the matched value or `-1`. */ function basicIndexOf(array, value, fromIndex) { var index = (fromIndex || 0) - 1, length = array.length; while (++index < length) { if (array[index] === value) { return index; } } return -1; } /** * An implementation of `_.contains` for cache objects that mimics the return * signature of `_.indexOf` by returning `0` if the value is found, else `-1`. * * @private * @param {Object} cache The cache object to inspect. * @param {Mixed} value The value to search for. * @returns {Number} Returns `0` if `value` is found, else `-1`. */ function cacheIndexOf(cache, value) { var type = typeof value; cache = cache.cache; if (type == 'boolean' || value == null) { return cache[value]; } if (type != 'number' && type != 'string') { type = 'object'; } var key = type == 'number' ? value : keyPrefix + value; cache = cache[type] || (cache[type] = {}); return type == 'object' ? (cache[key] && basicIndexOf(cache[key], value) > -1 ? 0 : -1) : (cache[key] ? 0 : -1); } /** * Adds a given `value` to the corresponding cache object. * * @private * @param {Mixed} value The value to add to the cache. */ function cachePush(value) { var cache = this.cache, type = typeof value; if (type == 'boolean' || value == null) { cache[value] = true; } else { if (type != 'number' && type != 'string') { type = 'object'; } var key = type == 'number' ? value : keyPrefix + value, typeCache = cache[type] || (cache[type] = {}); if (type == 'object') { if ((typeCache[key] || (typeCache[key] = [])).push(value) == this.array.length) { cache[type] = false; } } else { typeCache[key] = true; } } } /** * Used by `_.max` and `_.min` as the default `callback` when a given * `collection` is a string value. * * @private * @param {String} value The character to inspect. * @returns {Number} Returns the code unit of given character. */ function charAtCallback(value) { return value.charCodeAt(0); } /** * Used by `sortBy` to compare transformed `collection` values, stable sorting * them in ascending order. * * @private * @param {Object} a The object to compare to `b`. * @param {Object} b The object to compare to `a`. * @returns {Number} Returns the sort order indicator of `1` or `-1`. */ function compareAscending(a, b) { var ai = a.index, bi = b.index; a = a.criteria; b = b.criteria; // ensure a stable sort in V8 and other engines // http://code.google.com/p/v8/issues/detail?id=90 if (a !== b) { if (a > b || typeof a == 'undefined') { return 1; } if (a < b || typeof b == 'undefined') { return -1; } } return ai < bi ? -1 : 1; } /** * Creates a cache object to optimize linear searches of large arrays. * * @private * @param {Array} [array=[]] The array to search. * @returns {Null|Object} Returns the cache object or `null` if caching should not be used. */ function createCache(array) { var index = -1, length = array.length; var cache = getObject(); cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false; var result = getObject(); result.array = array; result.cache = cache; result.push = cachePush; while (++index < length) { result.push(array[index]); } return cache.object === false ? (releaseObject(result), null) : result; } /** * 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]; } /** * Gets an array from the array pool or creates a new one if the pool is empty. * * @private * @returns {Array} The array from the pool. */ function getArray() { return arrayPool.pop() || []; } /** * Gets an object from the object pool or creates a new one if the pool is empty. * * @private * @returns {Object} The object from the pool. */ function getObject() { return objectPool.pop() || { 'args': '', 'array': null, 'bottom': '', 'criteria': null, 'false': false, 'firstArg': '', 'index': 0, 'init': '', 'leading': false, 'loop': '', 'maxWait': 0, 'null': false, 'number': null, 'object': null, 'push': null, 'shadowedProps': null, 'string': null, 'top': '', 'trailing': false, 'true': false, 'undefined': false, 'useHas': false, 'useKeys': false, 'value': null }; } /** * Checks if `value` is a DOM node in IE < 9. * * @private * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is a DOM node, else `false`. */ function isNode(value) { // IE < 9 presents DOM nodes as `Object` objects except they have `toString` // methods that are `typeof` "string" and still can coerce nodes to strings return typeof value.toString != 'function' && typeof (value + '') == 'string'; } /** * A no-operation function. * * @private */ function noop() { // no operation performed } /** * Releases the given `array` back to the array pool. * * @private * @param {Array} [array] The array to release. */ function releaseArray(array) { if (arrayPool.length == maxPoolSize) { arrayPool.length = maxPoolSize - 1; } array.length = 0; arrayPool.push(array); } /** * Releases the given `object` back to the object pool. * * @private * @param {Object} [object] The object to release. */ function releaseObject(object) { var cache = object.cache; if (cache) { releaseObject(cache); } if (objectPool.length == maxPoolSize) { objectPool.length = maxPoolSize - 1; } object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null; objectPool.push(object); } /** * Slices the `collection` from the `start` index up to, but not including, * the `end` index. * * Note: This function is used, instead of `Array#slice`, to support node lists * in IE < 9 and to ensure dense arrays are returned. * * @private * @param {Array|Object|String} collection The collection to slice. * @param {Number} start The start index. * @param {Number} end The end index. * @returns {Array} Returns the new array. */ function slice(array, start, end) { start || (start = 0); if (typeof end == 'undefined') { end = array ? array.length : 0; } var index = -1, length = end - start || 0, result = Array(length < 0 ? 0 : length); while (++index < length) { result[index] = array[start + index]; } return result; } /*--------------------------------------------------------------------------*/ /** * Create a new `lodash` function using the given `context` object. * * @static * @memberOf _ * @category Utilities * @param {Object} [context=window] The context object. * @returns {Function} Returns the `lodash` function. */ function runInContext(context) { // Avoid issues with some ES3 environments that attempt to use values, named // after built-in constructors like `Object`, for the creation of literals. // ES5 clears this up by stating that literals must use built-in constructors. // See http://es5.github.com/#x11.1.5. context = context ? _.defaults(window.Object(), context, _.pick(window, contextProps)) : window; /** Native constructor references */ var Array = context.Array, Boolean = context.Boolean, Date = context.Date, Error = context.Error, Function = context.Function, Math = context.Math, Number = context.Number, Object = context.Object, RegExp = context.RegExp, String = context.String, TypeError = context.TypeError; /** * Used for `Array` method references. * * Normally `Array.prototype` would suffice, however, using an array literal * avoids issues in Narwhal. */ var arrayRef = []; /** Used for native method references */ var errorProto = Error.prototype, objectProto = Object.prototype, stringProto = String.prototype; /** Used to restore the original `_` reference in `noConflict` */ var oldDash = context._; /** Used to detect if a method is native */ var reNative = RegExp('^' + String(objectProto.valueOf) .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') .replace(/valueOf|for [^\]]+/g, '.+?') + '$' ); /** Native method shortcuts */ var ceil = Math.ceil, clearTimeout = context.clearTimeout, concat = arrayRef.concat, floor = Math.floor, fnToString = Function.prototype.toString, getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf, hasOwnProperty = objectProto.hasOwnProperty, push = arrayRef.push, propertyIsEnumerable = objectProto.propertyIsEnumerable, setImmediate = context.setImmediate, setTimeout = context.setTimeout, toString = objectProto.toString; /* Native method shortcuts for methods with the same name as other `lodash` methods */ var nativeBind = reNative.test(nativeBind = toString.bind) && nativeBind, nativeCreate = reNative.test(nativeCreate = Object.create) && nativeCreate, nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray, nativeIsFinite = context.isFinite, nativeIsNaN = context.isNaN, nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys, nativeMax = Math.max, nativeMin = Math.min, nativeParseInt = context.parseInt, nativeRandom = Math.random, nativeSlice = arrayRef.slice; /** Detect various environments */ var isIeOpera = reNative.test(context.attachEvent), isV8 = nativeBind && !/\n|true/.test(nativeBind + isIeOpera); /** Used to lookup a built-in constructor by [[Class]] */ var ctorByClass = {}; ctorByClass[arrayClass] = Array; ctorByClass[boolClass] = Boolean; ctorByClass[dateClass] = Date; ctorByClass[funcClass] = Function; ctorByClass[objectClass] = Object; ctorByClass[numberClass] = Number; ctorByClass[regexpClass] = RegExp; ctorByClass[stringClass] = String; /** Used to avoid iterating non-enumerable properties in IE < 9 */ var nonEnumProps = {}; nonEnumProps[arrayClass] = nonEnumProps[dateClass] = nonEnumProps[numberClass] = { 'constructor': true, 'toLocaleString': true, 'toString': true, 'valueOf': true }; nonEnumProps[boolClass] = nonEnumProps[stringClass] = { 'constructor': true, 'toString': true, 'valueOf': true }; nonEnumProps[errorClass] = nonEnumProps[funcClass] = nonEnumProps[regexpClass] = { 'constructor': true, 'toString': true }; nonEnumProps[objectClass] = { 'constructor': true }; (function() { var length = shadowedProps.length; while (length--) { var prop = shadowedProps[length]; for (var className in nonEnumProps) { if (hasOwnProperty.call(nonEnumProps, className) && !hasOwnProperty.call(nonEnumProps[className], prop)) { nonEnumProps[className][prop] = false; } } } }()); /*--------------------------------------------------------------------------*/ /** * Creates a `lodash` object, which wraps the given `value`, to enable method * chaining. * * In addition to Lo-Dash methods, wrappers also have the following `Array` methods: * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`, * and `unshift` * * Chaining is supported in custom builds as long as the `value` method is * implicitly or explicitly included in the build. * * The chainable wrapper functions are: * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`, * `compose`, `concat`, `countBy`, `createCallback`, `debounce`, `defaults`, * `defer`, `delay`, `difference`, `filter`, `flatten`, `forEach`, `forIn`, * `forOwn`, `functions`, `groupBy`, `initial`, `intersection`, `invert`, * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`, * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `push`, `range`, * `reject`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, `sortBy`, `splice`, * `tap`, `throttle`, `times`, `toArray`, `transform`, `union`, `uniq`, `unshift`, * `unzip`, `values`, `where`, `without`, `wrap`, and `zip` * * The non-chainable wrapper functions are: * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `has`, * `identity`, `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, * `isElement`, `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, * `isNull`, `isNumber`, `isObject`, `isPlainObject`, `isRegExp`, `isString`, * `isUndefined`, `join`, `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, * `pop`, `random`, `reduce`, `reduceRight`, `result`, `shift`, `size`, `some`, * `sortedIndex`, `runInContext`, `template`, `unescape`, `uniqueId`, and `value` * * The wrapper functions `first` and `last` return wrapped values when `n` is * passed, otherwise they return unwrapped values. * * @name _ * @constructor * @alias chain * @category Chaining * @param {Mixed} value The value to wrap in a `lodash` instance. * @returns {Object} Returns a `lodash` instance. * @example * * var wrapped = _([1, 2, 3]); * * // returns an unwrapped value * wrapped.reduce(function(sum, num) { * return sum + num; * }); * // => 6 * * // returns a wrapped value * var squares = wrapped.map(function(num) { * return num * num; * }); * * _.isArray(squares); * // => false * * _.isArray(squares.value()); * // => true */ function lodash(value) { // don't wrap if already wrapped, even if wrapped by a different `lodash` constructor return (value && typeof value == 'object' && !isArray(value) && hasOwnProperty.call(value, '__wrapped__')) ? value : new lodashWrapper(value); } /** * A fast path for creating `lodash` wrapper objects. * * @private * @param {Mixed} value The value to wrap in a `lodash` instance. * @returns {Object} Returns a `lodash` instance. */ function lodashWrapper(value) { this.__wrapped__ = value; } // ensure `new lodashWrapper` is an instance of `lodash` lodashWrapper.prototype = lodash.prototype; /** * An object used to flag environments features. * * @static * @memberOf _ * @type Object */ var support = lodash.support = {}; (function() { var ctor = function() { this.x = 1; }, object = { '0': 1, 'length': 1 }, props = []; ctor.prototype = { 'valueOf': 1, 'y': 1 }; for (var prop in new ctor) { props.push(prop); } for (prop in arguments) { } /** * Detect if `arguments` objects are `Object` objects (all but Narwhal and Opera < 10.5). * * @memberOf _.support * @type Boolean */ support.argsObject = arguments.constructor == Object && !(arguments instanceof Array); /** * Detect if an `arguments` object's [[Class]] is resolvable (all but Firefox < 4, IE < 9). * * @memberOf _.support * @type Boolean */ support.argsClass = isArguments(arguments); /** * Detect if `name` or `message` properties of `Error.prototype` are * enumerable by default. (IE < 9, Safari < 5.1) * * @memberOf _.support * @type Boolean */ support.enumErrorProps = propertyIsEnumerable.call(errorProto, 'message') || propertyIsEnumerable.call(errorProto, 'name'); /** * Detect if `prototype` properties are enumerable by default. * * 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`. * * @memberOf _.support * @type Boolean */ support.enumPrototypes = propertyIsEnumerable.call(ctor, 'prototype'); /** * Detect if `Function#bind` exists and is inferred to be fast (all but V8). * * @memberOf _.support * @type Boolean */ support.fastBind = nativeBind && !isV8; /** * Detect if own properties are iterated after inherited properties (all but IE < 9). * * @memberOf _.support * @type Boolean */ support.ownLast = props[0] != 'x'; /** * Detect if `arguments` object indexes are non-enumerable * (Firefox < 4, IE < 9, PhantomJS, Safari < 5.1). * * @memberOf _.support * @type Boolean */ support.nonEnumArgs = prop != 0; /** * Detect if properties shadowing those on `Object.prototype` are non-enumerable. * * In IE < 9 an objects own properties, shadowing non-enumerable ones, are * made non-enumerable as well (a.k.a the JScript [[DontEnum]] bug). * * @memberOf _.support * @type Boolean */ support.nonEnumShadows = !/valueOf/.test(props); /** * Detect if `Array#shift` and `Array#splice` augment array-like objects correctly. * * 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. * * @memberOf _.support * @type Boolean */ support.spliceObjects = (arrayRef.splice.call(object, 0, 1), !object[0]); /** * 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. * * @memberOf _.support * @type Boolean */ support.unindexedChars = ('x'[0] + Object('x')[0]) != 'xx'; /** * Detect if a DOM node's [[Class]] is resolvable (all but IE < 9) * and that the JS engine errors when attempting to coerce an object to * a string without a `toString` function. * * @memberOf _.support * @type Boolean */ try { support.nodeClass = !(toString.call(document) == objectClass && !({ 'toString': 0 } + '')); } catch(e) { support.nodeClass = true; } }(1)); /*--------------------------------------------------------------------------*/ /** * The template used to create iterator functions. * * @private * @param {Object} data The data object used to populate the text. * @returns {String} Returns the interpolated text. */ var iteratorTemplate = function(obj) { var __p = 'var index, iterable = ' + (obj.firstArg) + ', result = ' + (obj.init) + ';\nif (!iterable) return result;\n' + (obj.top) + ';'; if (obj.array) { __p += '\nvar length = iterable.length; index = -1;\nif (' + (obj.array) + ') { '; if (support.unindexedChars) { __p += '\n if (isString(iterable)) {\n iterable = iterable.split(\'\')\n } '; } __p += '\n while (++index < length) {\n ' + (obj.loop) + ';\n }\n}\nelse { '; } else if (support.nonEnumArgs) { __p += '\n var length = iterable.length; index = -1;\n if (length && isArguments(iterable)) {\n while (++index < length) {\n index += \'\';\n ' + (obj.loop) + ';\n }\n } else { '; } if (support.enumPrototypes) { __p += '\n var skipProto = typeof iterable == \'function\';\n '; } if (support.enumErrorProps) { __p += '\n var skipErrorProps = iterable === errorProto || iterable instanceof Error;\n '; } var conditions = []; if (support.enumPrototypes) { conditions.push('!(skipProto && index == "prototype")'); } if (support.enumErrorProps) { conditions.push('!(skipErrorProps && (index == "message" || index == "name"))'); } if (obj.useHas && obj.useKeys) { __p += '\n var ownIndex = -1,\n ownProps = objectTypes[typeof iterable] && keys(iterable),\n length = ownProps ? ownProps.length : 0;\n\n while (++ownIndex < length) {\n index = ownProps[ownIndex];\n'; if (conditions.length) { __p += ' if (' + (conditions.join(' && ')) + ') {\n '; } __p += (obj.loop) + '; '; if (conditions.length) { __p += '\n }'; } __p += '\n } '; } else { __p += '\n for (index in iterable) {\n'; if (obj.useHas) { conditions.push("hasOwnProperty.call(iterable, index)"); } if (conditions.length) { __p += ' if (' + (conditions.join(' && ')) + ') {\n '; } __p += (obj.loop) + '; '; if (conditions.length) { __p += '\n }'; } __p += '\n } '; if (support.nonEnumShadows) { __p += '\n\n if (iterable !== objectProto) {\n var ctor = iterable.constructor,\n isProto = iterable === (ctor && ctor.prototype),\n className = iterable === stringProto ? stringClass : iterable === errorProto ? errorClass : toString.call(iterable),\n nonEnum = nonEnumProps[className];\n '; for (k = 0; k < 7; k++) { __p += '\n index = \'' + (obj.shadowedProps[k]) + '\';\n if ((!(isProto && nonEnum[index]) && hasOwnProperty.call(iterable, index))'; if (!obj.useHas) { __p += ' || (!nonEnum[index] && iterable[index] !== objectProto[index])'; } __p += ') {\n ' + (obj.loop) + ';\n } '; } __p += '\n } '; } } if (obj.array || support.nonEnumArgs) { __p += '\n}'; } __p += (obj.bottom) + ';\nreturn result'; return __p }; /** Reusable iterator options for `assign` and `defaults` */ var defaultsIteratorOptions = { 'args': 'object, source, guard', 'top': 'var args = arguments,\n' + ' argsIndex = 0,\n' + " argsLength = typeof guard == 'number' ? 2 : args.length;\n" + 'while (++argsIndex < argsLength) {\n' + ' iterable = args[argsIndex];\n' + ' if (iterable && objectTypes[typeof iterable]) {', 'loop': "if (typeof result[index] == 'undefined') result[index] = iterable[index]", 'bottom': ' }\n}' }; /** Reusable iterator options shared by `each`, `forIn`, and `forOwn` */ var eachIteratorOptions = { 'args': 'collection, callback, thisArg', 'top': "callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg)", 'array': "typeof length == 'number'", 'loop': 'if (callback(iterable[index], index, collection) === false) return result' }; /** Reusable iterator options for `forIn` and `forOwn` */ var forOwnIteratorOptions = { 'top': 'if (!objectTypes[typeof iterable]) return result;\n' + eachIteratorOptions.top, 'array': false }; /*--------------------------------------------------------------------------*/ /** * Creates a function that, when called, invokes `func` with the `this` binding * of `thisArg` and prepends any `partialArgs` to the arguments passed to the * bound function. * * @private * @param {Function|String} func The function to bind or the method name. * @param {Mixed} [thisArg] The `this` binding of `func`. * @param {Array} partialArgs An array of arguments to be partially applied. * @param {Object} [idicator] Used to indicate binding by key or partially * applying arguments from the right. * @returns {Function} Returns the new bound function. */ function createBound(func, thisArg, partialArgs, indicator) { var isFunc = isFunction(func), isPartial = !partialArgs, key = thisArg; // juggle arguments if (isPartial) { var rightIndicator = indicator; partialArgs = thisArg; } else if (!isFunc) { if (!indicator) { throw new TypeError; } thisArg = func; } function bound() { // `Function#bind` spec // http://es5.github.com/#x15.3.4.5 var args = arguments, thisBinding = isPartial ? this : thisArg; if (!isFunc) { func = thisArg[key]; } if (partialArgs.length) { args = args.length ? (args = nativeSlice.call(args), rightIndicator ? args.concat(partialArgs) : partialArgs.concat(args)) : partialArgs; } if (this instanceof bound) { // ensure `new bound` is an instance of `func` thisBinding = createObject(func.prototype); // 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; } /** * Creates compiled iteration functions. * * @private * @param {Object} [options1, options2, ...] The compile options object(s). * array - A string of code to determine if the iterable is an array or array-like. * useHas - A boolean to specify using `hasOwnProperty` checks in the object loop. * useKeys - A boolean to specify using `_.keys` for own property iteration. * args - A string of comma separated arguments the iteration function will accept. * top - A string of code to execute before the iteration branches. * loop - A string of code to execute in the object loop. * bottom - A string of code to execute after the iteration branches. * @returns {Function} Returns the compiled function. */ function createIterator() { var data = getObject(); // data properties data.shadowedProps = shadowedProps; // iterator options data.array = data.bottom = data.loop = data.top = ''; data.init = 'iterable'; data.useHas = true; data.useKeys = !!keys; // 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( 'errorClass, errorProto, hasOwnProperty, isArguments, isArray, ' + 'isString, keys, lodash, objectProto, objectTypes, nonEnumProps, ' + 'stringClass, stringProto, toString', 'return function(' + args + ') {\n' + iteratorTemplate(data) + '\n}' ); releaseObject(data); // return the compiled function return factory( errorClass, errorProto, hasOwnProperty, isArguments, isArray, isString, keys, lodash, objectProto, objectTypes, nonEnumProps, stringClass, stringProto, toString ); } /** * Creates a new object with the specified `prototype`. * * @private * @param {Object} prototype The prototype object. * @returns {Object} Returns the new object. */ function createObject(prototype) { return isObject(prototype) ? nativeCreate(prototype) : {}; } // fallback for browsers without `Object.create` if (!nativeCreate) { var createObject = function(prototype) { if (isObject(prototype)) { noop.prototype = prototype; var result = new noop; noop.prototype = null; } return result || {}; }; } /** * 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]; } /** * Gets the appropriate "indexOf" function. If the `_.indexOf` method is * customized, this method returns the custom method, otherwise it returns * the `basicIndexOf` function. * * @private * @returns {Function} Returns the "indexOf" function. */ function getIndexOf(array, value, fromIndex) { var result = (result = lodash.indexOf) === indexOf ? basicIndexOf : result; return result; } /** * Creates a function that juggles arguments, allowing argument overloading * for `_.flatten` and `_.uniq`, before passing them to the given `func`. * * @private * @param {Function} func The function to wrap. * @returns {Function} Returns the new function. */ function overloadWrapper(func) { return function(array, flag, callback, thisArg) { // juggle arguments if (typeof flag != 'boolean' && flag != null) { thisArg = callback; callback = !(thisArg && thisArg[flag] === array) ? flag : undefined; flag = false; } if (callback != null) { callback = lodash.createCallback(callback, thisArg); } return func(array, flag, callback, thisArg); }; } /** * A fallback implementation of `isPlainObject` which 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) { var ctor, result; // avoid non Object objects, `arguments` objects, and DOM elements if (!(value && toString.call(value) == objectClass) || (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor)) || (!support.argsClass && isArguments(value)) || (!support.nodeClass && isNode(value))) { return false; } // 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 (support.ownLast) { 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 === undefined || hasOwnProperty.call(value, result); } /** * Used by `unescape` to convert HTML entities to characters. * * @private * @param {String} match The matched character to unescape. * @returns {String} Returns the unescaped character. */ function unescapeHtmlChar(match) { return htmlUnescapes[match]; } /*--------------------------------------------------------------------------*/ /** * Checks if `value` is an `arguments` object. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true`, if the `value` is an `arguments` object, else `false`. * @example * * (function() { return _.isArguments(arguments); })(1, 2, 3); * // => true * * _.isArguments([1, 2, 3]); * // => false */ function isArguments(value) { return toString.call(value) == argsClass; } // fallback for browsers that can't detect `arguments` objects by [[Class]] if (!support.argsClass) { isArguments = function(value) { return value ? hasOwnProperty.call(value, 'callee') : false; }; } /** * 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 value ? (typeof value == 'object' && toString.call(value) == arrayClass) : false; }; /** * A fallback implementation of `Object.keys` which produces an array of the * given object's own enumerable property names. * * @private * @type Function * @param {Object} object The object to inspect. * @returns {Array} Returns a new array of property names. */ var shimKeys = createIterator({ 'args': 'object', 'init': '[]', 'top': 'if (!(objectTypes[typeof object])) return result', 'loop': 'result.push(index)' }); /** * Creates an array composed of the own enumerable property names of `object`. * * @static * @memberOf _ * @category Objects * @param {Object} object The object to inspect. * @returns {Array} Returns a new array of property names. * @example * * _.keys({ 'one': 1, 'two': 2, 'three': 3 }); * // => ['one', 'two', 'three'] (order is not guaranteed) */ var keys = !nativeKeys ? shimKeys : function(object) { if (!isObject(object)) { return []; } if ((support.enumPrototypes && typeof object == 'function') || (support.nonEnumArgs && object.length && isArguments(object))) { return shimKeys(object); } return nativeKeys(object); }; /** * A function compiled to iterate `arguments` objects, arrays, objects, and * strings consistenly across environments, executing the `callback` for each * element in the `collection`. The `callback` is bound to `thisArg` and invoked * with three arguments; (value, index|key, collection). Callbacks may exit * iteration early by explicitly returning `false`. * * @private * @type Function * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array|Object|String} Returns `collection`. */ var basicEach = createIterator(eachIteratorOptions); /** * Used to convert characters to HTML entities: * * Though the `>` character is escaped for symmetry, characters like `>` and `/` * don't require escaping in HTML and have no special meaning unless they're part * of a tag or an unquoted attribute value. * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact") */ var htmlEscapes = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; /** Used to convert HTML entities to characters */ var htmlUnescapes = invert(htmlEscapes); /*--------------------------------------------------------------------------*/ /** * Assigns own enumerable properties of source object(s) to the destination * object. Subsequent sources will overwrite property assignments of previous * sources. If a `callback` function is passed, it will be executed to produce * the assigned values. The `callback` is bound to `thisArg` and invoked with * two arguments; (objectValue, sourceValue). * * @static * @memberOf _ * @type Function * @alias extend * @category Objects * @param {Object} object The destination object. * @param {Object} [source1, source2, ...] The source objects. * @param {Function} [callback] The function to customize assigning values. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns the destination object. * @example * * _.assign({ 'name': 'moe' }, { 'age': 40 }); * // => { 'name': 'moe', 'age': 40 } * * var defaults = _.partialRight(_.assign, function(a, b) { * return typeof a == 'undefined' ? b : a; * }); * * var food = { 'name': 'apple' }; * defaults(food, { 'name': 'banana', 'type': 'fruit' }); * // => { 'name': 'apple', 'type': 'fruit' } */ var assign = createIterator(defaultsIteratorOptions, { 'top': defaultsIteratorOptions.top.replace(';', ';\n' + "if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {\n" + ' var callback = lodash.createCallback(args[--argsLength - 1], args[argsLength--], 2);\n' + "} else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {\n" + ' callback = args[--argsLength];\n' + '}' ), 'loop': 'result[index] = callback ? callback(result[index], iterable[index]) : iterable[index]' }); /** * Creates a clone of `value`. If `deep` is `true`, nested objects will also * be cloned, otherwise they will be assigned by reference. If a `callback` * function is passed, it will be executed to produce the cloned values. If * `callback` returns `undefined`, cloning will be handled by the method instead. * The `callback` is bound to `thisArg` and invoked with one argument; (value). * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to clone. * @param {Boolean} [deep=false] A flag to indicate a deep clone. * @param {Function} [callback] The function to customize cloning values. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @param- {Array} [stackA=[]] Tracks traversed source objects. * @param- {Array} [stackB=[]] Associates clones with source counterparts. * @returns {Mixed} Returns the cloned `value`. * @example * * var stooges = [ * { 'name': 'moe', 'age': 40 }, * { 'name': 'larry', 'age': 50 } * ]; * * var shallow = _.clone(stooges); * shallow[0] === stooges[0]; * // => true * * var deep = _.clone(stooges, true); * deep[0] === stooges[0]; * // => false * * _.mixin({ * 'clone': _.partialRight(_.clone, function(value) { * return _.isElement(value) ? value.cloneNode(false) : undefined; * }) * }); * * var clone = _.clone(document.body); * clone.childNodes.length; * // => 0 */ function clone(value, deep, callback, thisArg, stackA, stackB) { var result = value; // allows working with "Collections" methods without using their `callback` // argument, `index|key`, for this method's `callback` if (typeof deep != 'boolean' && deep != null) { thisArg = callback; callback = deep; deep = false; } if (typeof callback == 'function') { callback = (typeof thisArg == 'undefined') ? callback : lodash.createCallback(callback, thisArg, 1); result = callback(result); if (typeof result != 'undefined') { return result; } result = value; } // inspect [[Class]] var isObj = isObject(result); if (isObj) { var className = toString.call(result); if (!cloneableClasses[className] || (!support.nodeClass && isNode(result))) { return result; } var isArr = isArray(result); } // shallow clone if (!isObj || !deep) { return isObj ? (isArr ? slice(result) : assign({}, result)) : result; } var ctor = ctorByClass[className]; switch (className) { case boolClass: case dateClass: return new ctor(+result); case numberClass: case stringClass: return new ctor(result); case regexpClass: return ctor(result.source, reFlags.exec(result)); } // check for circular references and return corresponding clone var initedStack = !stackA; stackA || (stackA = getArray()); stackB || (stackB = getArray()); var length = stackA.length; while (length--) { if (stackA[length] == value) { return stackB[length]; } } // init cloned object result = isArr ? ctor(result.length) : {}; // add array properties assigned by `RegExp#exec` if (isArr) { if (hasOwnProperty.call(value, 'index')) { result.index = value.index; } if (hasOwnProperty.call(value, 'input')) { result.input = value.input; } } // add the source value to the stack of traversed objects // and associate it with its clone stackA.push(value); stackB.push(result); // recursively populate clone (susceptible to call stack limits) (isArr ? basicEach : forOwn)(value, function(objValue, key) { result[key] = clone(objValue, deep, callback, undefined, stackA, stackB); }); if (initedStack) { releaseArray(stackA); releaseArray(stackB); } return result; } /** * Creates a deep clone of `value`. If a `callback` function is passed, * it will be executed to produce the cloned values. If `callback` returns * `undefined`, cloning will be handled by the method instead. The `callback` * is bound to `thisArg` and invoked with one argument; (value). * * Note: This method is loosely based on the structured clone algorithm. Functions * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and * objects created by constructors other than `Object` are cloned to plain `Object` objects. * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to deep clone. * @param {Function} [callback] The function to customize cloning values. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the deep cloned `value`. * @example * * var stooges = [ * { 'name': 'moe', 'age': 40 }, * { 'name': 'larry', 'age': 50 } * ]; * * var deep = _.cloneDeep(stooges); * deep[0] === stooges[0]; * // => false * * var view = { * 'label': 'docs', * 'node': element * }; * * var clone = _.cloneDeep(view, function(value) { * return _.isElement(value) ? value.cloneNode(true) : undefined; * }); * * clone.node == view.node; * // => false */ function cloneDeep(value, callback, thisArg) { return clone(value, true, callback, thisArg); } /** * Assigns own enumerable properties of source object(s) to the destination * object for all destination properties that resolve to `undefined`. Once a * property is set, additional defaults of the same property will be ignored. * * @static * @memberOf _ * @type Function * @category Objects * @param {Object} object The destination object. * @param {Object} [source1, source2, ...] The source objects. * @param- {Object} [guard] Allows working with `_.reduce` without using its * callback's `key` and `object` arguments as sources. * @returns {Object} Returns the destination object. * @example * * var food = { 'name': 'apple' }; * _.defaults(food, { 'name': 'banana', 'type': 'fruit' }); * // => { 'name': 'apple', 'type': 'fruit' } */ var defaults = createIterator(defaultsIteratorOptions); /** * This method is similar to `_.find`, except that it returns the key of the * element that passes the callback check, instead of the element itself. * * @static * @memberOf _ * @category Objects * @param {Object} object The object to search. * @param {Function|Object|String} [callback=identity] The function called per * iteration. If a property name or object is passed, it will be used to create * a "_.pluck" or "_.where" style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the key of the found element, else `undefined`. * @example * * _.findKey({ 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, function(num) { * return num % 2 == 0; * }); * // => 'b' */ function findKey(object, callback, thisArg) { var result; callback = lodash.createCallback(callback, thisArg); forOwn(object, function(value, key, object) { if (callback(value, key, object)) { result = key; return false; } }); return result; } /** * Iterates over `object`'s own and inherited enumerable properties, executing * the `callback` for each property. The `callback` is bound to `thisArg` and * invoked with three arguments; (value, key, object). Callbacks may exit iteration * early by explicitly returning `false`. * * @static * @memberOf _ * @type Function * @category Objects * @param {Object} object The object to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns `object`. * @example * * function Dog(name) { * this.name = name; * } * * Dog.prototype.bark = function() { * alert('Woof, woof!'); * }; * * _.forIn(new Dog('Dagny'), function(value, key) { * alert(key); * }); * // => alerts 'name' and 'bark' (order is not guaranteed) */ var forIn = createIterator(eachIteratorOptions, forOwnIteratorOptions, { 'useHas': false }); /** * Iterates over an object's own enumerable properties, executing the `callback` * for each property. The `callback` is bound to `thisArg` and invoked with three * arguments; (value, key, object). Callbacks may exit iteration early by explicitly * returning `false`. * * @static * @memberOf _ * @type Function * @category Objects * @param {Object} object The object to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns `object`. * @example * * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) { * alert(key); * }); * // => alerts '0', '1', and 'length' (order is not guaranteed) */ var forOwn = createIterator(eachIteratorOptions, forOwnIteratorOptions); /** * Creates a sorted array of all enumerable properties, own and inherited, * of `object` that have function values. * * @static * @memberOf _ * @alias methods * @category Objects * @param {Object} object The object to inspect. * @returns {Array} Returns a new array of property names that have function values. * @example * * _.functions(_); * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...] */ function functions(object) { var result = []; forIn(object, function(value, key) { if (isFunction(value)) { result.push(key); } }); return result.sort(); } /** * Checks if the specified object `property` exists and is a direct property, * instead of an inherited property. * * @static * @memberOf _ * @category Objects * @param {Object} object The object to check. * @param {String} property The property to check for. * @returns {Boolean} Returns `true` if key is a direct property, else `false`. * @example * * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b'); * // => true */ function has(object, property) { return object ? hasOwnProperty.call(object, property) : false; } /** * Creates an object composed of the inverted keys and values of the given `object`. * * @static * @memberOf _ * @category Objects * @param {Object} object The object to invert. * @returns {Object} Returns the created inverted object. * @example * * _.invert({ 'first': 'moe', 'second': 'larry' }); * // => { 'moe': 'first', 'larry': 'second' } */ function invert(object) { var index = -1, props = keys(object), length = props.length, result = {}; while (++index < length) { var key = props[index]; result[object[key]] = key; } return result; } /** * Checks if `value` is a boolean value. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true`, if the `value` is a boolean value, else `false`. * @example * * _.isBoolean(null); * // => false */ function isBoolean(value) { return value === true || value === false || toString.call(value) == boolClass; } /** * Checks if `value` is a date. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true`, if the `value` is a date, else `false`. * @example * * _.isDate(new Date); * // => true */ function isDate(value) { return value ? (typeof value == 'object' && toString.call(value) == dateClass) : false; } /** * 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 || (support.argsClass ? className == argsClass : 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. If `callback` is passed, it will be executed to * compare values. If `callback` returns `undefined`, comparisons will be handled * by the method instead. The `callback` is bound to `thisArg` and invoked with * two arguments; (a, b). * * @static * @memberOf _ * @category Objects * @param {Mixed} a The value to compare. * @param {Mixed} b The other value to compare. * @param {Function} [callback] The function to customize comparing values. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @param- {Array} [stackA=[]] Tracks traversed `a` objects. * @param- {Array} [stackB=[]] Tracks traversed `b` objects. * @returns {Boolean} Returns `true`, if the values are equivalent, else `false`. * @example * * var moe = { 'name': 'moe', 'age': 40 }; * var copy = { 'name': 'moe', 'age': 40 }; * * moe == copy; * // => false * * _.isEqual(moe, copy); * // => true * * var words = ['hello', 'goodbye']; * var otherWords = ['hi', 'goodbye']; * * _.isEqual(words, otherWords, function(a, b) { * var reGreet = /^(?:hello|hi)$/i, * aGreet = _.isString(a) && reGreet.test(a), * bGreet = _.isString(b) && reGreet.test(b); * * return (aGreet || bGreet) ? (aGreet == bGreet) : undefined; * }); * // => true */ function isEqual(a, b, callback, thisArg, stackA, stackB) { // used to indicate that when comparing objects, `a` has at least the properties of `b` var whereIndicator = callback === indicatorObject; if (typeof callback == 'function' && !whereIndicator) { callback = lodash.createCallback(callback, thisArg, 2); var result = callback(a, b); if (typeof result != 'undefined') { return !!result; } } // exit early for identical values if (a === b) { // treat `+0` vs. `-0` as not equal return a !== 0 || (1 / a == 1 / b); } var type = typeof a, otherType = typeof b; // exit early for unlike primitive values if (a === a && (!a || (type != 'function' && type != 'object')) && (!b || (otherType != 'function' && otherType != 'object'))) { return false; } // exit early for `null` and `undefined`, avoiding ES3's Function#call behavior // http://es5.github.com/#x15.3.4.4 if (a == null || b == null) { return a === b; } // compare [[Class]] names var className = toString.call(a), otherClass = toString.call(b); if (className == argsClass) { className = objectClass; } if (otherClass == argsClass) { otherClass = objectClass; } if (className != otherClass) { return false; } switch (className) { case boolClass: case dateClass: // coerce dates and booleans to numbers, dates to milliseconds and booleans // to `1` or `0`, treating invalid dates coerced to `NaN` as not equal return +a == +b; case numberClass: // treat `NaN` vs. `NaN` as equal return (a != +a) ? b != +b // but treat `+0` vs. `-0` as not equal : (a == 0 ? (1 / a == 1 / b) : a == +b); case regexpClass: case stringClass: // coerce regexes to strings (http://es5.github.com/#x15.10.6.4) // treat string primitives and their corresponding object instances as equal return a == String(b); } var isArr = className == arrayClass; if (!isArr) { // unwrap any `lodash` wrapped values if (hasOwnProperty.call(a, '__wrapped__ ') || hasOwnProperty.call(b, '__wrapped__')) { return isEqual(a.__wrapped__ || a, b.__wrapped__ || b, callback, thisArg, stackA, stackB); } // exit for functions and DOM nodes if (className != objectClass || (!support.nodeClass && (isNode(a) || isNode(b)))) { return false; } // in older versions of Opera, `arguments` objects have `Array` constructors var ctorA = !support.argsObject && isArguments(a) ? Object : a.constructor, ctorB = !support.argsObject && isArguments(b) ? Object : b.constructor; // non `Object` object instances with different constructors are not equal if (ctorA != ctorB && !( isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB )) { return false; } } // assume cyclic structures are equal // the algorithm for detecting cyclic structures is adapted from ES 5.1 // section 15.12.3, abstract operation `JO` (http://es5.github.com/#x15.12.3) var initedStack = !stackA; stackA || (stackA = getArray()); stackB || (stackB = getArray()); var length = stackA.length; while (length--) { if (stackA[length] == a) { return stackB[length] == b; } } var size = 0; result = true; // add `a` and `b` to the stack of traversed objects stackA.push(a); stackB.push(b); // recursively compare objects and arrays (susceptible to call stack limits) if (isArr) { length = a.length; size = b.length; // compare lengths to determine if a deep comparison is necessary result = size == a.length; if (!result && !whereIndicator) { return result; } // deep compare the contents, ignoring non-numeric properties while (size--) { var index = length, value = b[size]; if (whereIndicator) { while (index--) { if ((result = isEqual(a[index], value, callback, thisArg, stackA, stackB))) { break; } } } else if (!(result = isEqual(a[size], value, callback, thisArg, stackA, stackB))) { break; } } return result; } // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys` // which, in this case, is more costly forIn(b, function(value, key, b) { if (hasOwnProperty.call(b, key)) { // count the number of properties. size++; // deep compare each property value. return (result = hasOwnProperty.call(a, key) && isEqual(a[key], value, callback, thisArg, stackA, stackB)); } }); if (result && !whereIndicator) { // ensure both objects have the same number of properties forIn(a, function(value, key, a) { if (hasOwnProperty.call(a, key)) { // `size` will be `-1` if `a` has more properties than `b` return (result = --size > -1); } }); } if (initedStack) { releaseArray(stackA); releaseArray(stackB); } return result; } /** * Checks if `value` is, or can be coerced to, a finite number. * * Note: This is not the same as native `isFinite`, which will return true for * booleans and empty strings. See http://es5.github.com/#x15.1.2.5. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true`, if the `value` is finite, else `false`. * @example * * _.isFinite(-101); * // => true * * _.isFinite('10'); * // => true * * _.isFinite(true); * // => false * * _.isFinite(''); * // => false * * _.isFinite(Infinity); * // => false */ function isFinite(value) { return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value)); } /** * Checks if `value` is a function. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true`, if the `value` is a function, else `false`. * @example * * _.isFunction(_); * // => true */ function isFunction(value) { return typeof value == 'function'; } // fallback for older versions of Chrome and Safari if (isFunction(/x/)) { isFunction = function(value) { return typeof value == 'function' && toString.call(value) == funcClass; }; } /** * Checks if `value` is the language type of Object. * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true`, if the `value` is an object, else `false`. * @example * * _.isObject({}); * // => true * * _.isObject([1, 2, 3]); * // => true * * _.isObject(1); * // => false */ function isObject(value) { // check if the value is the ECMAScript language type of Object // http://es5.github.com/#x8 // and avoid a V8 bug // http://code.google.com/p/v8/issues/detail?id=2291 return !!(value && objectTypes[typeof value]); } /** * Checks if `value` is `NaN`. * * Note: This is not the same as native `isNaN`, which will return `true` for * `undefined` and other values. See http://es5.github.com/#x15.1.2.4. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true`, if the `value` is `NaN`, else `false`. * @example * * _.isNaN(NaN); * // => true * * _.isNaN(new Number(NaN)); * // => true * * isNaN(undefined); * // => true * * _.isNaN(undefined); * // => false */ function isNaN(value) { // `NaN` as a primitive is the only value that is not equal to itself // (perform the [[Class]] check first to avoid errors with some host objects in IE) return isNumber(value) && value != +value } /** * Checks if `value` is `null`. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true`, if the `value` is `null`, else `false`. * @example * * _.isNull(null); * // => true * * _.isNull(undefined); * // => false */ function isNull(value) { return value === null; } /** * Checks if `value` is a number. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true`, if the `value` is a number, else `false`. * @example * * _.isNumber(8.4 * 5); * // => true */ function isNumber(value) { return typeof value == 'number' || toString.call(value) == numberClass; } /** * Checks if a given `value` is an object created by the `Object` constructor. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true`, if `value` is a plain object, else `false`. * @example * * function Stooge(name, age) { * this.name = name; * this.age = age; * } * * _.isPlainObject(new Stooge('moe', 40)); * // => false * * _.isPlainObject([1, 2, 3]); * // => false * * _.isPlainObject({ 'name': 'moe', 'age': 40 }); * // => true */ var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) { if (!(value && toString.call(value) == objectClass) || (!support.argsClass && isArguments(value))) { return false; } var valueOf = value.valueOf, objProto = typeof valueOf == 'function' && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto); return objProto ? (value == objProto || getPrototypeOf(value) == objProto) : shimIsPlainObject(value); }; /** * Checks if `value` is a regular expression. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true`, if the `value` is a regular expression, else `false`. * @example * * _.isRegExp(/moe/); * // => true */ function isRegExp(value) { return !!(value && objectTypes[typeof value]) && toString.call(value) == regexpClass; } /** * Checks if `value` is a string. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true`, if the `value` is a string, else `false`. * @example * * _.isString('moe'); * // => true */ function isString(value) { return typeof value == 'string' || toString.call(value) == stringClass; } /** * Checks if `value` is `undefined`. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true`, if the `value` is `undefined`, else `false`. * @example * * _.isUndefined(void 0); * // => true */ function isUndefined(value) { return typeof value == 'undefined'; } /** * Recursively merges own enumerable properties of the source object(s), that * don't resolve to `undefined`, into the destination object. Subsequent sources * will overwrite property assignments of previous sources. If a `callback` function * is passed, it will be executed to produce the merged values of the destination * and source properties. If `callback` returns `undefined`, merging will be * handled by the method instead. The `callback` is bound to `thisArg` and * invoked with two arguments; (objectValue, sourceValue). * * @static * @memberOf _ * @category Objects * @param {Object} object The destination object. * @param {Object} [source1, source2, ...] The source objects. * @param {Function} [callback] The function to customize merging properties. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @param- {Object} [deepIndicator] Indicates that `stackA` and `stackB` are * arrays of traversed objects, instead of source objects. * @param- {Array} [stackA=[]] Tracks traversed source objects. * @param- {Array} [stackB=[]] Associates values with source counterparts. * @returns {Object} Returns the destination object. * @example * * var names = { * 'stooges': [ * { 'name': 'moe' }, * { 'name': 'larry' } * ] * }; * * var ages = { * 'stooges': [ * { 'age': 40 }, * { 'age': 50 } * ] * }; * * _.merge(names, ages); * // => { 'stooges': [{ 'name': 'moe', 'age': 40 }, { 'name': 'larry', 'age': 50 }] } * * var food = { * 'fruits': ['apple'], * 'vegetables': ['beet'] * }; * * var otherFood = { * 'fruits': ['banana'], * 'vegetables': ['carrot'] * }; * * _.merge(food, otherFood, function(a, b) { * return _.isArray(a) ? a.concat(b) : undefined; * }); * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] } */ function merge(object, source, deepIndicator) { var args = arguments, index = 0, length = 2; if (!isObject(object)) { return object; } if (deepIndicator === indicatorObject) { var callback = args[3], stackA = args[4], stackB = args[5]; } else { var initedStack = true; stackA = getArray(); stackB = getArray(); // allows working with `_.reduce` and `_.reduceRight` without // using their `callback` arguments, `index|key` and `collection` if (typeof deepIndicator != 'number') { length = args.length; } if (length > 3 && typeof args[length - 2] == 'function') { callback = lodash.createCallback(args[--length - 1], args[length--], 2); } else if (length > 2 && typeof args[length - 1] == 'function') { callback = args[--length]; } } while (++index < length) { (isArray(args[index]) ? forEach : forOwn)(args[index], function(source, key) { var found, isArr, result = source, value = object[key]; if (source && ((isArr = isArray(source)) || isPlainObject(source))) { // avoid merging previously merged cyclic sources var stackLength = stackA.length; while (stackLength--) { if ((found = stackA[stackLength] == source)) { value = stackB[stackLength]; break; } } if (!found) { var isShallow; if (callback) { result = callback(value, source); if ((isShallow = typeof result != 'undefined')) { value = result; } } if (!isShallow) { value = isArr ? (isArray(value) ? value : []) : (isPlainObject(value) ? value : {}); } // add `source` and associated `value` to the stack of traversed objects stackA.push(source); stackB.push(value); // recursively merge objects and arrays (susceptible to call stack limits) if (!isShallow) { value = merge(value, source, indicatorObject, callback, stackA, stackB); } } } else { if (callback) { result = callback(value, source); if (typeof result == 'undefined') { result = source; } } if (typeof result != 'undefined') { value = result; } } object[key] = value; }); } if (initedStack) { releaseArray(stackA); releaseArray(stackB); } return object; } /** * Creates a shallow clone of `object` excluding the specified properties. * Property names may be specified as individual arguments or as arrays of * property names. If a `callback` function is passed, it will be executed * for each property in the `object`, omitting the properties `callback` * returns truthy for. The `callback` is bound to `thisArg` and invoked * with three arguments; (value, key, object). * * @static * @memberOf _ * @category Objects * @param {Object} object The source object. * @param {Function|String} callback|[prop1, prop2, ...] The properties to omit * or the function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns an object without the omitted properties. * @example * * _.omit({ 'name': 'moe', 'age': 40 }, 'age'); * // => { 'name': 'moe' } * * _.omit({ 'name': 'moe', 'age': 40 }, function(value) { * return typeof value == 'number'; * }); * // => { 'name': 'moe' } */ function omit(object, callback, thisArg) { var indexOf = getIndexOf(), isFunc = typeof callback == 'function', result = {}; if (isFunc) { callback = lodash.createCallback(callback, thisArg); } else { var props = concat.apply(arrayRef, nativeSlice.call(arguments, 1)); } forIn(object, function(value, key, object) { if (isFunc ? !callback(value, key, object) : indexOf(props, key) < 0 ) { result[key] = value; } }); return result; } /** * Creates a two dimensional array of the given object's key-value pairs, * i.e. `[[key1, value1], [key2, value2]]`. * * @static * @memberOf _ * @category Objects * @param {Object} object The object to inspect. * @returns {Array} Returns new array of key-value pairs. * @example * * _.pairs({ 'moe': 30, 'larry': 40 }); * // => [['moe', 30], ['larry', 40]] (order is not guaranteed) */ function pairs(object) { var index = -1, props = keys(object), length = props.length, result = Array(length); while (++index < length) { var key = props[index]; result[index] = [key, object[key]]; } return result; } /** * Creates a shallow clone of `object` composed of the specified properties. * Property names may be specified as individual arguments or as arrays of property * names. If `callback` is passed, it will be executed for each property in the * `object`, picking the properties `callback` returns truthy for. The `callback` * is bound to `thisArg` and invoked with three arguments; (value, key, object). * * @static * @memberOf _ * @category Objects * @param {Object} object The source object. * @param {Array|Function|String} callback|[prop1, prop2, ...] The function called * per iteration or properties to pick, either as individual arguments or arrays. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns an object composed of the picked properties. * @example * * _.pick({ 'name': 'moe', '_userid': 'moe1' }, 'name'); * // => { 'name': 'moe' } * * _.pick({ 'name': 'moe', '_userid': 'moe1' }, function(value, key) { * return key.charAt(0) != '_'; * }); * // => { 'name': 'moe' } */ function pick(object, callback, thisArg) { var result = {}; if (typeof callback != 'function') { var index = -1, props = concat.apply(arrayRef, nativeSlice.call(arguments, 1)), length = isObject(object) ? props.length : 0; while (++index < length) { var key = props[index]; if (key in object) { result[key] = object[key]; } } } else { callback = lodash.createCallback(callback, thisArg); forIn(object, function(value, key, object) { if (callback(value, key, object)) { result[key] = value; } }); } return result; } /** * An alternative to `_.reduce`, this method transforms an `object` to a new * `accumulator` object which is the result of running each of its elements * through the `callback`, with each `callback` execution potentially mutating * the `accumulator` object. The `callback` is bound to `thisArg` and invoked * with four arguments; (accumulator, value, key, object). Callbacks may exit * iteration early by explicitly returning `false`. * * @static * @memberOf _ * @category Objects * @param {Array|Object} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [accumulator] The custom accumulator value. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the accumulated value. * @example * * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) { * num *= num; * if (num % 2) { * return result.push(num) < 3; * } * }); * // => [1, 9, 25] * * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) { * result[key] = num * 3; * }); * // => { 'a': 3, 'b': 6, 'c': 9 } */ function transform(object, callback, accumulator, thisArg) { var isArr = isArray(object); callback = lodash.createCallback(callback, thisArg, 4); if (accumulator == null) { if (isArr) { accumulator = []; } else { var ctor = object && object.constructor, proto = ctor && ctor.prototype; accumulator = createObject(proto); } } (isArr ? basicEach : forOwn)(object, function(value, index, object) { return callback(accumulator, value, index, object); }); return accumulator; } /** * 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] (order is not guaranteed) */ function values(object) { var index = -1, props = keys(object), length = props.length, result = Array(length); while (++index < length) { result[index] = object[props[index]]; } return result; } /*--------------------------------------------------------------------------*/ /** * Creates an array of elements from the specified indexes, or keys, of the * `collection`. Indexes may be specified as individual arguments or as arrays * of indexes. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Array|Number|String} [index1, index2, ...] The indexes of * `collection` to retrieve, either as individual arguments or arrays. * @returns {Array} Returns a new array of elements corresponding to the * provided indexes. * @example * * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]); * // => ['a', 'c', 'e'] * * _.at(['moe', 'larry', 'curly'], 0, 2); * // => ['moe', 'curly'] */ function at(collection) { var index = -1, props = concat.apply(arrayRef, nativeSlice.call(arguments, 1)), length = props.length, result = Array(length); if (support.unindexedChars && isString(collection)) { collection = collection.split(''); } while(++index < length) { result[index] = collection[props[index]]; } return result; } /** * Checks if a given `target` element is present in a `collection` using strict * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used * as the offset from the end of the collection. * * @static * @memberOf _ * @alias include * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Mixed} target The value to check for. * @param {Number} [fromIndex=0] The index to search from. * @returns {Boolean} Returns `true` if the `target` element is found, else `false`. * @example * * _.contains([1, 2, 3], 1); * // => true * * _.contains([1, 2, 3], 1, 2); * // => false * * _.contains({ 'name': 'moe', 'age': 40 }, 'moe'); * // => true * * _.contains('curly', 'ur'); * // => true */ function contains(collection, target, fromIndex) { var index = -1, indexOf = getIndexOf(), length = collection ? collection.length : 0, result = false; fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0; if (length && typeof length == 'number') { result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex) ) > -1; } else { basicEach(collection, function(value) { if (++index >= fromIndex) { return !(result = value === target); } }); } return result; } /** * Creates an object composed of keys returned from running each element of the * `collection` through the given `callback`. The corresponding value of each key * is the number of times the key was returned by the `callback`. The `callback` * is bound to `thisArg` and invoked with three arguments; (value, index|key, collection). * * If a property name is passed for `callback`, the created "_.pluck" style * callback will return the property value of the given element. * * If an object is passed for `callback`, the created "_.where" style callback * will return `true` for elements that have the properties of the given object, * else `false`. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|Object|String} [callback=identity] The function called per * iteration. If a property name or object is passed, it will be used to create * a "_.pluck" or "_.where" style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns the composed aggregate object. * @example * * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); }); * // => { '4': 1, '6': 2 } * * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math); * // => { '4': 1, '6': 2 } * * _.countBy(['one', 'two', 'three'], 'length'); * // => { '3': 2, '5': 1 } */ function countBy(collection, callback, thisArg) { var result = {}; callback = lodash.createCallback(callback, thisArg); forEach(collection, function(value, key, collection) { key = String(callback(value, key, collection)); (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1); }); return result; } /** * Checks if the `callback` returns a truthy value for **all** elements of a * `collection`. The `callback` is bound to `thisArg` and invoked with three * arguments; (value, index|key, collection). * * If a property name is passed for `callback`, the created "_.pluck" style * callback will return the property value of the given element. * * If an object is passed for `callback`, the created "_.where" style callback * will return `true` for elements that have the properties of the given object, * else `false`. * * @static * @memberOf _ * @alias all * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|Object|String} [callback=identity] The function called per * iteration. If a property name or object is passed, it will be used to create * a "_.pluck" or "_.where" style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Boolean} Returns `true` if all elements pass the callback check, * else `false`. * @example * * _.every([true, 1, null, 'yes'], Boolean); * // => false * * var stooges = [ * { 'name': 'moe', 'age': 40 }, * { 'name': 'larry', 'age': 50 } * ]; * * // using "_.pluck" callback shorthand * _.every(stooges, 'age'); * // => true * * // using "_.where" callback shorthand * _.every(stooges, { 'age': 50 }); * // => false */ function every(collection, callback, thisArg) { var result = true; callback = lodash.createCallback(callback, thisArg); if (isArray(collection)) { var index = -1, length = collection.length; while (++index < length) { if (!(result = !!callback(collection[index], index, collection))) { break; } } } else { basicEach(collection, function(value, index, collection) { return (result = !!callback(value, index, collection)); }); } return result; } /** * Examines each element in a `collection`, returning an array of all elements * the `callback` returns truthy for. The `callback` is bound to `thisArg` and * invoked with three arguments; (value, index|key, collection). * * If a property name is passed for `callback`, the created "_.pluck" style * callback will return the property value of the given element. * * If an object is passed for `callback`, the created "_.where" style callback * will return `true` for elements that have the properties of the given object, * else `false`. * * @static * @memberOf _ * @alias select * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|Object|String} [callback=identity] The function called per * iteration. If a property name or object is passed, it will be used to create * a "_.pluck" or "_.where" style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array} Returns a new array of elements that passed the callback check. * @example * * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); * // => [2, 4, 6] * * var food = [ * { 'name': 'apple', 'organic': false, 'type': 'fruit' }, * { 'name': 'carrot', 'organic': true, 'type': 'vegetable' } * ]; * * // using "_.pluck" callback shorthand * _.filter(food, 'organic'); * // => [{ 'name': 'carrot', 'organic': true, 'type': 'vegetable' }] * * // using "_.where" callback shorthand * _.filter(food, { 'type': 'fruit' }); * // => [{ 'name': 'apple', 'organic': false, 'type': 'fruit' }] */ function filter(collection, callback, thisArg) { var result = []; callback = lodash.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 { basicEach(collection, function(value, index, collection) { if (callback(value, index, collection)) { result.push(value); } }); } return result; } /** * Examines each element in a `collection`, returning the first that the `callback` * returns truthy for. The `callback` is bound to `thisArg` and invoked with three * arguments; (value, index|key, collection). * * If a property name is passed for `callback`, the created "_.pluck" style * callback will return the property value of the given element. * * If an object is passed for `callback`, the created "_.where" style callback * will return `true` for elements that have the properties of the given object, * else `false`. * * @static * @memberOf _ * @alias detect, findWhere * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|Object|String} [callback=identity] The function called per * iteration. If a property name or object is passed, it will be used to create * a "_.pluck" or "_.where" style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the found element, else `undefined`. * @example * * _.find([1, 2, 3, 4], function(num) { * return num % 2 == 0; * }); * // => 2 * * var food = [ * { 'name': 'apple', 'organic': false, 'type': 'fruit' }, * { 'name': 'banana', 'organic': true, 'type': 'fruit' }, * { 'name': 'beet', 'organic': false, 'type': 'vegetable' } * ]; * * // using "_.where" callback shorthand * _.find(food, { 'type': 'vegetable' }); * // => { 'name': 'beet', 'organic': false, 'type': 'vegetable' } * * // using "_.pluck" callback shorthand * _.find(food, 'organic'); * // => { 'name': 'banana', 'organic': true, 'type': 'fruit' } */ function find(collection, callback, thisArg) { callback = lodash.createCallback(callback, thisArg); if (isArray(collection)) { var index = -1, length = collection.length; while (++index < length) { var value = collection[index]; if (callback(value, index, collection)) { return value; } } } else { var result; basicEach(collection, function(value, index, collection) { if (callback(value, index, collection)) { result = value; return false; } }); return result; } } /** * Iterates over a `collection`, executing the `callback` for each element in * the `collection`. The `callback` is bound to `thisArg` and invoked with three * arguments; (value, index|key, collection). Callbacks may exit iteration early * by explicitly returning `false`. * * @static * @memberOf _ * @alias each * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array|Object|String} Returns `collection`. * @example * * _([1, 2, 3]).forEach(alert).join(','); * // => alerts each number and returns '1,2,3' * * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, alert); * // => alerts each number value (order is not guaranteed) */ function forEach(collection, callback, thisArg) { if (callback && typeof thisArg == 'undefined' && isArray(collection)) { var index = -1, length = collection.length; while (++index < length) { if (callback(collection[index], index, collection) === false) { break; } } } else { basicEach(collection, callback, thisArg); } return collection; } /** * Creates an object composed of keys returned from running each element of the * `collection` through the `callback`. The corresponding value of each key is * an array of elements passed to `callback` that returned the key. The `callback` * is bound to `thisArg` and invoked with three arguments; (value, index|key, collection). * * If a property name is passed for `callback`, the created "_.pluck" style * callback will return the property value of the given element. * * If an object is passed for `callback`, the created "_.where" style callback * will return `true` for elements that have the properties of the given object, * else `false` * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|Object|String} [callback=identity] The function called per * iteration. If a property name or object is passed, it will be used to create * a "_.pluck" or "_.where" style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns the composed aggregate object. * @example * * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); }); * // => { '4': [4.2], '6': [6.1, 6.4] } * * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math); * // => { '4': [4.2], '6': [6.1, 6.4] } * * // using "_.pluck" callback shorthand * _.groupBy(['one', 'two', 'three'], 'length'); * // => { '3': ['one', 'two'], '5': ['three'] } */ function groupBy(collection, callback, thisArg) { var result = {}; callback = lodash.createCallback(callback, thisArg); forEach(collection, function(value, key, collection) { key = String(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 = nativeSlice.call(arguments, 2), index = -1, isFunc = typeof methodName == 'function', length = collection ? collection.length : 0, result = Array(typeof length == 'number' ? length : 0); forEach(collection, function(value) { result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args); }); return result; } /** * Creates an array of values by running each element in the `collection` * through the `callback`. The `callback` is bound to `thisArg` and invoked with * three arguments; (value, index|key, collection). * * If a property name is passed for `callback`, the created "_.pluck" style * callback will return the property value of the given element. * * If an object is passed for `callback`, the created "_.where" style callback * will return `true` for elements that have the properties of the given object, * else `false`. * * @static * @memberOf _ * @alias collect * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|Object|String} [callback=identity] The function called per * iteration. If a property name or object is passed, it will be used to create * a "_.pluck" or "_.where" style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array} Returns a new array of the results of each `callback` execution. * @example * * _.map([1, 2, 3], function(num) { return num * 3; }); * // => [3, 6, 9] * * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; }); * // => [3, 6, 9] (order is not guaranteed) * * var stooges = [ * { 'name': 'moe', 'age': 40 }, * { 'name': 'larry', 'age': 50 } * ]; * * // using "_.pluck" callback shorthand * _.map(stooges, 'name'); * // => ['moe', 'larry'] */ function map(collection, callback, thisArg) { var index = -1, length = collection ? collection.length : 0, result = Array(typeof length == 'number' ? length : 0); callback = lodash.createCallback(callback, thisArg); if (isArray(collection)) { while (++index < length) { result[index] = callback(collection[index], index, collection); } } else { basicEach(collection, function(value, key, collection) { result[++index] = callback(value, key, collection); }); } return result; } /** * Retrieves the maximum value of an `array`. If `callback` is passed, * it will be executed for each value in the `array` to generate the * criterion by which the value is ranked. The `callback` is bound to * `thisArg` and invoked with three arguments; (value, index, collection). * * If a property name is passed for `callback`, the created "_.pluck" style * callback will return the property value of the given element. * * If an object is passed for `callback`, the created "_.where" style callback * will return `true` for elements that have the properties of the given object, * else `false`. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|Object|String} [callback=identity] The function called per * iteration. If a property name or object is passed, it will be used to create * a "_.pluck" or "_.where" style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the maximum value. * @example * * _.max([4, 2, 8, 6]); * // => 8 * * var stooges = [ * { 'name': 'moe', 'age': 40 }, * { 'name': 'larry', 'age': 50 } * ]; * * _.max(stooges, function(stooge) { return stooge.age; }); * // => { 'name': 'larry', 'age': 50 }; * * // using "_.pluck" callback shorthand * _.max(stooges, 'age'); * // => { 'name': 'larry', 'age': 50 }; */ function max(collection, callback, thisArg) { var computed = -Infinity, result = computed; if (!callback && isArray(collection)) { var index = -1, length = collection.length; while (++index < length) { var value = collection[index]; if (value > result) { result = value; } } } else { callback = (!callback && isString(collection)) ? charAtCallback : lodash.createCallback(callback, thisArg); basicEach(collection, function(value, index, collection) { var current = callback(value, index, collection); if (current > computed) { computed = current; result = value; } }); } return result; } /** * Retrieves the minimum value of an `array`. If `callback` is passed, * it will be executed for each value in the `array` to generate the * criterion by which the value is ranked. The `callback` is bound to `thisArg` * and invoked with three arguments; (value, index, collection). * * If a property name is passed for `callback`, the created "_.pluck" style * callback will return the property value of the given element. * * If an object is passed for `callback`, the created "_.where" style callback * will return `true` for elements that have the properties of the given object, * else `false`. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|Object|String} [callback=identity] The function called per * iteration. If a property name or object is passed, it will be used to create * a "_.pluck" or "_.where" style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the minimum value. * @example * * _.min([4, 2, 8, 6]); * // => 2 * * var stooges = [ * { 'name': 'moe', 'age': 40 }, * { 'name': 'larry', 'age': 50 } * ]; * * _.min(stooges, function(stooge) { return stooge.age; }); * // => { 'name': 'moe', 'age': 40 }; * * // using "_.pluck" callback shorthand * _.min(stooges, 'age'); * // => { 'name': 'moe', 'age': 40 }; */ function min(collection, callback, thisArg) { var computed = Infinity, result = computed; if (!callback && isArray(collection)) { var index = -1, length = collection.length; while (++index < length) { var value = collection[index]; if (value < result) { result = value; } } } else { callback = (!callback && isString(collection)) ? charAtCallback : lodash.createCallback(callback, thisArg); basicEach(collection, function(value, index, collection) { var current = callback(value, index, collection); if (current < computed) { computed = current; result = value; } }); } return result; } /** * Retrieves the value of a specified property from all elements in the `collection`. * * @static * @memberOf _ * @type Function * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {String} property The property to pluck. * @returns {Array} Returns a new array of property values. * @example * * var stooges = [ * { 'name': 'moe', 'age': 40 }, * { 'name': 'larry', 'age': 50 } * ]; * * _.pluck(stooges, 'name'); * // => ['moe', 'larry'] */ var pluck = map; /** * Reduces a `collection` to a value which is the accumulated result of running * each element in the `collection` through the `callback`, where each successive * `callback` execution consumes the return value of the previous execution. * If `accumulator` is not passed, the first element of the `collection` will be * used as the initial `accumulator` value. The `callback` is bound to `thisArg` * and invoked with four arguments; (accumulator, value, index|key, collection). * * @static * @memberOf _ * @alias foldl, inject * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [accumulator] Initial value of the accumulator. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the accumulated value. * @example * * var sum = _.reduce([1, 2, 3], function(sum, num) { * return sum + num; * }); * // => 6 * * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) { * result[key] = num * 3; * return result; * }, {}); * // => { 'a': 3, 'b': 6, 'c': 9 } */ function reduce(collection, callback, accumulator, thisArg) { var noaccum = arguments.length < 3; callback = lodash.createCallback(callback, thisArg, 4); if (isArray(collection)) { var index = -1, length = collection.length; if (noaccum) { accumulator = collection[++index]; } while (++index < length) { accumulator = callback(accumulator, collection[index], index, collection); } } else { basicEach(collection, function(value, index, collection) { accumulator = noaccum ? (noaccum = false, value) : callback(accumulator, value, index, collection) }); } return accumulator; } /** * This method is similar to `_.reduce`, except that it iterates over a * `collection` from right to left. * * @static * @memberOf _ * @alias foldr * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [accumulator] Initial value of the accumulator. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the accumulated value. * @example * * var list = [[0, 1], [2, 3], [4, 5]]; * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []); * // => [4, 5, 2, 3, 0, 1] */ function reduceRight(collection, callback, accumulator, thisArg) { var iterable = collection, length = collection ? collection.length : 0, noaccum = arguments.length < 3; if (typeof length != 'number') { var props = keys(collection); length = props.length; } else if (support.unindexedChars && isString(collection)) { iterable = collection.split(''); } callback = lodash.createCallback(callback, thisArg, 4); forEach(collection, function(value, index, collection) { index = props ? props[--length] : --length; accumulator = noaccum ? (noaccum = false, iterable[index]) : callback(accumulator, iterable[index], index, collection); }); return accumulator; } /** * The opposite of `_.filter`, this method returns the elements of a * `collection` that `callback` does **not** return truthy for. * * If a property name is passed for `callback`, the created "_.pluck" style * callback will return the property value of the given element. * * If an object is passed for `callback`, the created "_.where" style callback * will return `true` for elements that have the properties of the given object, * else `false`. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|Object|String} [callback=identity] The function called per * iteration. If a property name or object is passed, it will be used to create * a "_.pluck" or "_.where" style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array} Returns a new array of elements that did **not** pass the * callback check. * @example * * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); * // => [1, 3, 5] * * var food = [ * { 'name': 'apple', 'organic': false, 'type': 'fruit' }, * { 'name': 'carrot', 'organic': true, 'type': 'vegetable' } * ]; * * // using "_.pluck" callback shorthand * _.reject(food, 'organic'); * // => [{ 'name': 'apple', 'organic': false, 'type': 'fruit' }] * * // using "_.where" callback shorthand * _.reject(food, { 'type': 'fruit' }); * // => [{ 'name': 'carrot', 'organic': true, 'type': 'vegetable' }] */ function reject(collection, callback, thisArg) { callback = lodash.createCallback(callback, thisArg); return filter(collection, function(value, index, collection) { return !callback(value, index, collection); }); } /** * Creates an array of shuffled `array` values, using a version of the * Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to shuffle. * @returns {Array} Returns a new shuffled collection. * @example * * _.shuffle([1, 2, 3, 4, 5, 6]); * // => [4, 1, 6, 3, 5, 2] */ function shuffle(collection) { var index = -1, length = collection ? collection.length : 0, result = Array(typeof length == 'number' ? length : 0); forEach(collection, function(value) { var rand = floor(nativeRandom() * (++index + 1)); result[index] = result[rand]; result[rand] = value; }); return result; } /** * Gets the size of the `collection` by returning `collection.length` for arrays * and array-like objects or the number of own enumerable properties for objects. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to inspect. * @returns {Number} Returns `collection.length` or number of own enumerable properties. * @example * * _.size([1, 2]); * // => 2 * * _.size({ 'one': 1, 'two': 2, 'three': 3 }); * // => 3 * * _.size('curly'); * // => 5 */ function size(collection) { var length = collection ? collection.length : 0; return typeof length == 'number' ? length : keys(collection).length; } /** * Checks if the `callback` returns a truthy value for **any** element of a * `collection`. The function returns as soon as it finds passing value, and * does not iterate over the entire `collection`. The `callback` is bound to * `thisArg` and invoked with three arguments; (value, index|key, collection). * * If a property name is passed for `callback`, the created "_.pluck" style * callback will return the property value of the given element. * * If an object is passed for `callback`, the created "_.where" style callback * will return `true` for elements that have the properties of the given object, * else `false`. * * @static * @memberOf _ * @alias any * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|Object|String} [callback=identity] The function called per * iteration. If a property name or object is passed, it will be used to create * a "_.pluck" or "_.where" style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Boolean} Returns `true` if any element passes the callback check, * else `false`. * @example * * _.some([null, 0, 'yes', false], Boolean); * // => true * * var food = [ * { 'name': 'apple', 'organic': false, 'type': 'fruit' }, * { 'name': 'carrot', 'organic': true, 'type': 'vegetable' } * ]; * * // using "_.pluck" callback shorthand * _.some(food, 'organic'); * // => true * * // using "_.where" callback shorthand * _.some(food, { 'type': 'meat' }); * // => false */ function some(collection, callback, thisArg) { var result; callback = lodash.createCallback(callback, thisArg); if (isArray(collection)) { var index = -1, length = collection.length; while (++index < length) { if ((result = callback(collection[index], index, collection))) { break; } } } else { basicEach(collection, function(value, index, collection) { return !(result = callback(value, index, collection)); }); } return !!result; } /** * Creates an array of elements, sorted in ascending order by the results of * running each element in the `collection` through the `callback`. This method * performs a stable sort, that is, it will preserve the original sort order of * equal elements. The `callback` is bound to `thisArg` and invoked with three * arguments; (value, index|key, collection). * * If a property name is passed for `callback`, the created "_.pluck" style * callback will return the property value of the given element. * * If an object is passed for `callback`, the created "_.where" style callback * will return `true` for elements that have the properties of the given object, * else `false`. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|Object|String} [callback=identity] The function called per * iteration. If a property name or object is passed, it will be used to create * a "_.pluck" or "_.where" style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array} Returns a new array of sorted elements. * @example * * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); }); * // => [3, 1, 2] * * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math); * // => [3, 1, 2] * * // using "_.pluck" callback shorthand * _.sortBy(['banana', 'strawberry', 'apple'], 'length'); * // => ['apple', 'banana', 'strawberry'] */ function sortBy(collection, callback, thisArg) { var index = -1, length = collection ? collection.length : 0, result = Array(typeof length == 'number' ? length : 0); callback = lodash.createCallback(callback, thisArg); forEach(collection, function(value, key, collection) { var object = result[++index] = getObject(); object.criteria = callback(value, key, collection); object.index = index; object.value = value; }); length = result.length; result.sort(compareAscending); while (length--) { var object = result[length]; result[length] = object.value; releaseObject(object); } 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 (support.unindexedChars && isString(collection)) ? collection.split('') : slice(collection); } return values(collection); } /** * Examines each element in a `collection`, returning an array of all elements * that have the given `properties`. When checking `properties`, this method * performs a deep comparison between values to determine if they are equivalent * to each other. * * @static * @memberOf _ * @type Function * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Object} properties The object of property values to filter by. * @returns {Array} Returns a new array of elements that have the given `properties`. * @example * * var stooges = [ * { 'name': 'moe', 'age': 40 }, * { 'name': 'larry', 'age': 50 } * ]; * * _.where(stooges, { 'age': 40 }); * // => [{ 'name': 'moe', 'age': 40 }] */ var where = filter; /*--------------------------------------------------------------------------*/ /** * Creates an array with all falsey values of `array` removed. The values * `false`, `null`, `0`, `""`, `undefined` and `NaN` are all falsey. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to compact. * @returns {Array} Returns a new filtered array. * @example * * _.compact([0, 1, false, 2, '', 3]); * // => [1, 2, 3] */ function compact(array) { var index = -1, length = array ? array.length : 0, result = []; while (++index < length) { var value = array[index]; if (value) { result.push(value); } } return result; } /** * Creates an array of `array` elements not present in the other arrays * using strict equality for comparisons, i.e. `===`. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to process. * @param {Array} [array1, array2, ...] Arrays to check. * @returns {Array} Returns a new array of `array` elements not present in the * other arrays. * @example * * _.difference([1, 2, 3, 4, 5], [5, 2, 10]); * // => [1, 3, 4] */ function difference(array) { var index = -1, indexOf = getIndexOf(), length = array ? array.length : 0, seen = concat.apply(arrayRef, nativeSlice.call(arguments, 1)), result = []; var isLarge = length >= largeArraySize && indexOf === basicIndexOf; if (isLarge) { var cache = createCache(seen); if (cache) { indexOf = cacheIndexOf; seen = cache; } else { isLarge = false; } } while (++index < length) { var value = array[index]; if (indexOf(seen, value) < 0) { result.push(value); } } if (isLarge) { releaseObject(seen); } return result; } /** * This method is similar to `_.find`, except that it returns the index of * the element that passes the callback check, instead of the element itself. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to search. * @param {Function|Object|String} [callback=identity] The function called per * iteration. If a property name or object is passed, it will be used to create * a "_.pluck" or "_.where" style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the index of the found element, else `-1`. * @example * * _.findIndex(['apple', 'banana', 'beet'], function(food) { * return /^b/.test(food); * }); * // => 1 */ function findIndex(array, callback, thisArg) { var index = -1, length = array ? array.length : 0; callback = lodash.createCallback(callback, thisArg); while (++index < length) { if (callback(array[index], index, array)) { return index; } } return -1; } /** * Gets the first element of the `array`. If a number `n` is passed, the first * `n` elements of the `array` are returned. If a `callback` function is passed, * elements at the beginning of the array are returned as long as the `callback` * returns truthy. The `callback` is bound to `thisArg` and invoked with three * arguments; (value, index, array). * * If a property name is passed for `callback`, the created "_.pluck" style * callback will return the property value of the given element. * * If an object is passed for `callback`, the created "_.where" style callback * will return `true` for elements that have the properties of the given object, * else `false`. * * @static * @memberOf _ * @alias head, take * @category Arrays * @param {Array} array The array to query. * @param {Function|Object|Number|String} [callback|n] The function called * per element or the number of elements to return. If a property name or * object is passed, it will be used to create a "_.pluck" or "_.where" * style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the first element(s) of `array`. * @example * * _.first([1, 2, 3]); * // => 1 * * _.first([1, 2, 3], 2); * // => [1, 2] * * _.first([1, 2, 3], function(num) { * return num < 3; * }); * // => [1, 2] * * var food = [ * { 'name': 'banana', 'organic': true }, * { 'name': 'beet', 'organic': false }, * ]; * * // using "_.pluck" callback shorthand * _.first(food, 'organic'); * // => [{ 'name': 'banana', 'organic': true }] * * var food = [ * { 'name': 'apple', 'type': 'fruit' }, * { 'name': 'banana', 'type': 'fruit' }, * { 'name': 'beet', 'type': 'vegetable' } * ]; * * // using "_.where" callback shorthand * _.first(food, { 'type': 'fruit' }); * // => [{ 'name': 'apple', 'type': 'fruit' }, { 'name': 'banana', 'type': 'fruit' }] */ function first(array, callback, thisArg) { if (array) { var n = 0, length = array.length; if (typeof callback != 'number' && callback != null) { var index = -1; callback = lodash.createCallback(callback, thisArg); while (++index < length && callback(array[index], index, array)) { n++; } } else { n = callback; if (n == null || thisArg) { return array[0]; } } return slice(array, 0, nativeMin(nativeMax(0, n), length)); } } /** * Flattens a nested array (the nesting can be to any depth). If `isShallow` * is truthy, `array` will only be flattened a single level. If `callback` * is passed, each element of `array` is passed through a `callback` before * flattening. The `callback` is bound to `thisArg` and invoked with three * arguments; (value, index, array). * * If a property name is passed for `callback`, the created "_.pluck" style * callback will return the property value of the given element. * * If an object is passed for `callback`, the created "_.where" style callback * will return `true` for elements that have the properties of the given object, * else `false`. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to flatten. * @param {Boolean} [isShallow=false] A flag to indicate only flattening a single level. * @param {Function|Object|String} [callback=identity] The function called per * iteration. If a property name or object is passed, it will be used to create * a "_.pluck" or "_.where" style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array} Returns a new flattened array. * @example * * _.flatten([1, [2], [3, [[4]]]]); * // => [1, 2, 3, 4]; * * _.flatten([1, [2], [3, [[4]]]], true); * // => [1, 2, 3, [[4]]]; * * var stooges = [ * { 'name': 'curly', 'quotes': ['Oh, a wise guy, eh?', 'Poifect!'] }, * { 'name': 'moe', 'quotes': ['Spread out!', 'You knucklehead!'] } * ]; * * // using "_.pluck" callback shorthand * _.flatten(stooges, 'quotes'); * // => ['Oh, a wise guy, eh?', 'Poifect!', 'Spread out!', 'You knucklehead!'] */ var flatten = overloadWrapper(function flatten(array, isShallow, callback) { var index = -1, length = array ? array.length : 0, result = []; while (++index < length) { var value = array[index]; if (callback) { value = callback(value, index, array); } // recursively flatten arrays (susceptible to call stack limits) if (isArray(value)) { push.apply(result, isShallow ? 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) { if (typeof fromIndex == 'number') { var length = array ? array.length : 0; fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0); } else if (fromIndex) { var index = sortedIndex(array, value); return array[index] === value ? index : -1; } return array ? basicIndexOf(array, value, fromIndex) : -1; } /** * Gets all but the last element of `array`. If a number `n` is passed, the * last `n` elements are excluded from the result. If a `callback` function * is passed, elements at the end of the array are excluded from the result * as long as the `callback` returns truthy. The `callback` is bound to * `thisArg` and invoked with three arguments; (value, index, array). * * If a property name is passed for `callback`, the created "_.pluck" style * callback will return the property value of the given element. * * If an object is passed for `callback`, the created "_.where" style callback * will return `true` for elements that have the properties of the given object, * else `false`. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to query. * @param {Function|Object|Number|String} [callback|n=1] The function called * per element or the number of elements to exclude. If a property name or * object is passed, it will be used to create a "_.pluck" or "_.where" * style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array} Returns a slice of `array`. * @example * * _.initial([1, 2, 3]); * // => [1, 2] * * _.initial([1, 2, 3], 2); * // => [1] * * _.initial([1, 2, 3], function(num) { * return num > 1; * }); * // => [1] * * var food = [ * { 'name': 'beet', 'organic': false }, * { 'name': 'carrot', 'organic': true } * ]; * * // using "_.pluck" callback shorthand * _.initial(food, 'organic'); * // => [{ 'name': 'beet', 'organic': false }] * * var food = [ * { 'name': 'banana', 'type': 'fruit' }, * { 'name': 'beet', 'type': 'vegetable' }, * { 'name': 'carrot', 'type': 'vegetable' } * ]; * * // using "_.where" callback shorthand * _.initial(food, { 'type': 'vegetable' }); * // => [{ 'name': 'banana', 'type': 'fruit' }] */ function initial(array, callback, thisArg) { if (!array) { return []; } var n = 0, length = array.length; if (typeof callback != 'number' && callback != null) { var index = length; callback = lodash.createCallback(callback, thisArg); while (index-- && callback(array[index], index, array)) { n++; } } else { n = (callback == null || thisArg) ? 1 : callback || n; } return slice(array, 0, nativeMin(nativeMax(0, length - n), length)); } /** * Computes the intersection of all the passed-in arrays using strict equality * for comparisons, i.e. `===`. * * @static * @memberOf _ * @category Arrays * @param {Array} [array1, array2, ...] Arrays to process. * @returns {Array} Returns a new array of unique elements that are present * in **all** of the arrays. * @example * * _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]); * // => [1, 2] */ function intersection(array) { var args = arguments, argsLength = args.length, argsIndex = -1, caches = getArray(), index = -1, indexOf = getIndexOf(), length = array ? array.length : 0, result = [], seen = getArray(); while (++argsIndex < argsLength) { var value = args[argsIndex]; caches[argsIndex] = indexOf === basicIndexOf && (value ? value.length : 0) >= largeArraySize && createCache(argsIndex ? args[argsIndex] : seen); } outer: while (++index < length) { var cache = caches[0]; value = array[index]; if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) { argsIndex = argsLength; (cache || seen).push(value); while (--argsIndex) { cache = caches[argsIndex]; if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) { continue outer; } } result.push(value); } } while (argsLength--) { cache = caches[argsLength]; if (cache) { releaseObject(cache); } } releaseArray(caches); releaseArray(seen); return result; } /** * Gets the last element of the `array`. If a number `n` is passed, the * last `n` elements of the `array` are returned. If a `callback` function * is passed, elements at the end of the array are returned as long as the * `callback` returns truthy. The `callback` is bound to `thisArg` and * invoked with three arguments;(value, index, array). * * * If a property name is passed for `callback`, the created "_.pluck" style * callback will return the property value of the given element. * * If an object is passed for `callback`, the created "_.where" style callback * will return `true` for elements that have the properties of the given object, * else `false`. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to query. * @param {Function|Object|Number|String} [callback|n] The function called * per element or the number of elements to return. If a property name or * object is passed, it will be used to create a "_.pluck" or "_.where" * style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the last element(s) of `array`. * @example * * _.last([1, 2, 3]); * // => 3 * * _.last([1, 2, 3], 2); * // => [2, 3] * * _.last([1, 2, 3], function(num) { * return num > 1; * }); * // => [2, 3] * * var food = [ * { 'name': 'beet', 'organic': false }, * { 'name': 'carrot', 'organic': true } * ]; * * // using "_.pluck" callback shorthand * _.last(food, 'organic'); * // => [{ 'name': 'carrot', 'organic': true }] * * var food = [ * { 'name': 'banana', 'type': 'fruit' }, * { 'name': 'beet', 'type': 'vegetable' }, * { 'name': 'carrot', 'type': 'vegetable' } * ]; * * // using "_.where" callback shorthand * _.last(food, { 'type': 'vegetable' }); * // => [{ 'name': 'beet', 'type': 'vegetable' }, { 'name': 'carrot', 'type': 'vegetable' }] */ function last(array, callback, thisArg) { if (array) { var n = 0, length = array.length; if (typeof callback != 'number' && callback != null) { var index = length; callback = lodash.createCallback(callback, thisArg); while (index-- && callback(array[index], index, array)) { n++; } } else { n = callback; if (n == null || thisArg) { return array[length - 1]; } } return slice(array, nativeMax(0, length - n)); } } /** * Gets the index at which the last occurrence of `value` is found using strict * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used * as the offset from the end of the collection. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to search. * @param {Mixed} value The value to search for. * @param {Number} [fromIndex=array.length-1] The index to search from. * @returns {Number} Returns the index of the matched value or `-1`. * @example * * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2); * // => 4 * * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3); * // => 1 */ function lastIndexOf(array, value, fromIndex) { var index = array ? array.length : 0; if (typeof fromIndex == 'number') { index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1; } while (index--) { if (array[index] === value) { return index; } } return -1; } /** * Creates an array of numbers (positive and/or negative) progressing from * `start` up to but not including `end`. * * @static * @memberOf _ * @category Arrays * @param {Number} [start=0] The start of the range. * @param {Number} end The end of the range. * @param {Number} [step=1] The value to increment or decrement by. * @returns {Array} Returns a new range array. * @example * * _.range(10); * // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] * * _.range(1, 11); * // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] * * _.range(0, 30, 5); * // => [0, 5, 10, 15, 20, 25] * * _.range(0, -10, -1); * // => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] * * _.range(0); * // => [] */ function range(start, end, step) { start = +start || 0; step = +step || 1; if (end == null) { end = start; start = 0; } // use `Array(length)` so V8 will avoid the slower "dictionary" mode // http://youtu.be/XAqIpGU8ZZk#t=17m25s var index = -1, length = nativeMax(0, ceil((end - start) / step)), result = Array(length); while (++index < length) { result[index] = start; start += step; } return result; } /** * The opposite of `_.initial`, this method gets all but the first value of * `array`. If a number `n` is passed, the first `n` values are excluded from * the result. If a `callback` function is passed, elements at the beginning * of the array are excluded from the result as long as the `callback` returns * truthy. The `callback` is bound to `thisArg` and invoked with three * arguments; (value, index, array). * * If a property name is passed for `callback`, the created "_.pluck" style * callback will return the property value of the given element. * * If an object is passed for `callback`, the created "_.where" style callback * will return `true` for elements that have the properties of the given object, * else `false`. * * @static * @memberOf _ * @alias drop, tail * @category Arrays * @param {Array} array The array to query. * @param {Function|Object|Number|String} [callback|n=1] The function called * per element or the number of elements to exclude. If a property name or * object is passed, it will be used to create a "_.pluck" or "_.where" * style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array} Returns a slice of `array`. * @example * * _.rest([1, 2, 3]); * // => [2, 3] * * _.rest([1, 2, 3], 2); * // => [3] * * _.rest([1, 2, 3], function(num) { * return num < 3; * }); * // => [3] * * var food = [ * { 'name': 'banana', 'organic': true }, * { 'name': 'beet', 'organic': false }, * ]; * * // using "_.pluck" callback shorthand * _.rest(food, 'organic'); * // => [{ 'name': 'beet', 'organic': false }] * * var food = [ * { 'name': 'apple', 'type': 'fruit' }, * { 'name': 'banana', 'type': 'fruit' }, * { 'name': 'beet', 'type': 'vegetable' } * ]; * * // using "_.where" callback shorthand * _.rest(food, { 'type': 'fruit' }); * // => [{ 'name': 'beet', 'type': 'vegetable' }] */ function rest(array, callback, thisArg) { if (typeof callback != 'number' && callback != null) { var n = 0, index = -1, length = array ? array.length : 0; callback = lodash.createCallback(callback, thisArg); while (++index < length && callback(array[index], index, array)) { n++; } } else { n = (callback == null || thisArg) ? 1 : nativeMax(0, callback); } return slice(array, n); } /** * Uses a binary search to determine the smallest index at which the `value` * should be inserted into `array` in order to maintain the sort order of the * sorted `array`. If `callback` is passed, it will be executed for `value` and * each element in `array` to compute their sort ranking. The `callback` is * bound to `thisArg` and invoked with one argument; (value). * * If a property name is passed for `callback`, the created "_.pluck" style * callback will return the property value of the given element. * * If an object is passed for `callback`, the created "_.where" style callback * will return `true` for elements that have the properties of the given object, * else `false`. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to inspect. * @param {Mixed} value The value to evaluate. * @param {Function|Object|String} [callback=identity] The function called per * iteration. If a property name or object is passed, it will be used to create * a "_.pluck" or "_.where" style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Number} Returns the index at which the value should be inserted * into `array`. * @example * * _.sortedIndex([20, 30, 50], 40); * // => 2 * * // using "_.pluck" callback shorthand * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x'); * // => 2 * * var dict = { * 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 } * }; * * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) { * return dict.wordToNumber[word]; * }); * // => 2 * * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) { * return this.wordToNumber[word]; * }, dict); * // => 2 */ function sortedIndex(array, value, callback, thisArg) { var low = 0, high = array ? array.length : low; // explicitly reference `identity` for better inlining in Firefox callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity; value = callback(value); while (low < high) { var mid = (low + high) >>> 1; (callback(array[mid]) < value) ? low = mid + 1 : high = mid; } return low; } /** * Computes the union of the passed-in arrays using strict equality for * comparisons, i.e. `===`. * * @static * @memberOf _ * @category Arrays * @param {Array} [array1, array2, ...] Arrays to process. * @returns {Array} Returns a new array of unique values, in order, that are * present in one or more of the arrays. * @example * * _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]); * // => [1, 2, 3, 101, 10] */ function union(array) { if (!isArray(array)) { arguments[0] = array ? nativeSlice.call(array) : arrayRef; } 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 the `callback` before uniqueness is computed. * The `callback` is bound to `thisArg` and invoked with three arguments; (value, index, array). * * If a property name is passed for `callback`, the created "_.pluck" style * callback will return the property value of the given element. * * If an object is passed for `callback`, the created "_.where" style callback * will return `true` for elements that have the properties of the given object, * else `false`. * * @static * @memberOf _ * @alias unique * @category Arrays * @param {Array} array The array to process. * @param {Boolean} [isSorted=false] A flag to indicate that the `array` is already sorted. * @param {Function|Object|String} [callback=identity] The function called per * iteration. If a property name or object is passed, it will be used to create * a "_.pluck" or "_.where" style callback, respectively. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array} Returns a duplicate-value-free array. * @example * * _.uniq([1, 2, 1, 3, 1]); * // => [1, 2, 3] * * _.uniq([1, 1, 2, 2, 3], true); * // => [1, 2, 3] * * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); }); * // => ['A', 'b', 'C'] * * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math); * // => [1, 2.5, 3] * * // using "_.pluck" callback shorthand * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); * // => [{ 'x': 1 }, { 'x': 2 }] */ var uniq = overloadWrapper(function(array, isSorted, callback) { var index = -1, indexOf = getIndexOf(), length = array ? array.length : 0, result = []; var isLarge = !isSorted && length >= largeArraySize && indexOf === basicIndexOf, seen = (callback || isLarge) ? getArray() : result; if (isLarge) { var cache = createCache(seen); if (cache) { indexOf = cacheIndexOf; seen = cache; } else { isLarge = false; seen = callback ? seen : (releaseArray(seen), result); } } while (++index < length) { var value = array[index], computed = callback ? callback(value, index, array) : value; if (isSorted ? !index || seen[seen.length - 1] !== computed : indexOf(seen, computed) < 0 ) { if (callback || isLarge) { seen.push(computed); } result.push(value); } } if (isLarge) { releaseArray(seen.array); releaseObject(seen); } else if (callback) { releaseArray(seen); } return result; }); /** * The inverse of `_.zip`, this method splits groups of elements into arrays * composed of elements from each group at their corresponding indexes. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to process. * @returns {Array} Returns a new array of the composed arrays. * @example * * _.unzip([['moe', 30, true], ['larry', 40, false]]); * // => [['moe', 'larry'], [30, 40], [true, false]]; */ function unzip(array) { var index = -1, length = array ? max(pluck(array, 'length')) : 0, result = Array(length < 0 ? 0 : length); while (++index < length) { result[index] = pluck(array, index); } 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) { return difference(array, nativeSlice.call(arguments, 1)); } /** * Groups the elements of each array at their corresponding indexes. Useful for * separate data sources that are coordinated through matching array indexes. * For a matrix of nested arrays, `_.zip.apply(...)` can transpose the matrix * in a similar fashion. * * @static * @memberOf _ * @category Arrays * @param {Array} [array1, array2, ...] Arrays to process. * @returns {Array} Returns a new array of grouped elements. * @example * * _.zip(['moe', 'larry'], [30, 40], [true, false]); * // => [['moe', 30, true], ['larry', 40, false]] */ function zip(array) { return array ? unzip(arguments) : []; } /** * 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 _ * @alias object * @category Arrays * @param {Array} keys The array of keys. * @param {Array} [values=[]] The array of values. * @returns {Object} Returns an object composed of the given keys and * corresponding values. * @example * * _.zipObject(['moe', 'larry'], [30, 40]); * // => { 'moe': 30, 'larry': 40 } */ function zipObject(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; } /*--------------------------------------------------------------------------*/ /** * If `n` is greater than `0`, a function is created that is restricted to * executing `func`, with the `this` binding and arguments of the created * function, only after it is called `n` times. If `n` is less than `1`, * `func` is executed immediately, without a `this` binding or additional * arguments, and its result is returned. * * @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 support.fastBind || (nativeBind && arguments.length > 2) ? nativeBind.call.apply(nativeBind, arguments) : createBound(func, thisArg, nativeSlice.call(arguments, 2)); } /** * Binds methods on `object` to `object`, overwriting the existing method. * Method names may be specified as individual arguments or as arrays of method * names. If no method names are provided, all the function properties of `object` * will be bound. * * @static * @memberOf _ * @category Functions * @param {Object} object The object to bind and assign the bound methods to. * @param {String} [methodName1, methodName2, ...] Method names on the object to bind. * @returns {Object} Returns `object`. * @example * * var view = { * 'label': 'docs', * 'onClick': function() { alert('clicked ' + this.label); } * }; * * _.bindAll(view); * jQuery('#docs').on('click', view.onClick); * // => alerts 'clicked docs', when the button is clicked */ function bindAll(object) { var funcs = arguments.length > 1 ? concat.apply(arrayRef, nativeSlice.call(arguments, 1)) : functions(object), index = -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, nativeSlice.call(arguments, 2), indicatorObject); } /** * Creates a function that is the composition of the passed functions, * where each function consumes the return value of the function that follows. * For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`. * Each function is executed with the `this` binding of the composed function. * * @static * @memberOf _ * @category Functions * @param {Function} [func1, func2, ...] Functions to compose. * @returns {Function} Returns the new composed function. * @example * * var greet = function(name) { return 'hi ' + name; }; * var exclaim = function(statement) { return statement + '!'; }; * var welcome = _.compose(exclaim, greet); * welcome('moe'); * // => 'hi moe!' */ function compose() { var funcs = arguments; return function() { var args = arguments, length = funcs.length; while (length--) { args = [funcs[length].apply(this, args)]; } return args[0]; }; } /** * Produces a callback bound to an optional `thisArg`. If `func` is a property * name, the created callback will return the property value for a given element. * If `func` is an object, the created callback will return `true` for elements * that contain the equivalent object properties, otherwise it will return `false`. * * Note: All Lo-Dash methods, that accept a `callback` argument, use `_.createCallback`. * * @static * @memberOf _ * @category Functions * @param {Mixed} [func=identity] The value to convert to a callback. * @param {Mixed} [thisArg] The `this` binding of the created callback. * @param {Number} [argCount=3] The number of arguments the callback accepts. * @returns {Function} Returns a callback function. * @example * * var stooges = [ * { 'name': 'moe', 'age': 40 }, * { 'name': 'larry', 'age': 50 } * ]; * * // wrap to create custom callback shorthands * _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) { * var match = /^(.+?)__([gl]t)(.+)$/.exec(callback); * return !match ? func(callback, thisArg) : function(object) { * return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3]; * }; * }); * * _.filter(stooges, 'age__gt45'); * // => [{ 'name': 'larry', 'age': 50 }] * * // create mixins with support for "_.pluck" and "_.where" callback shorthands * _.mixin({ * 'toLookup': function(collection, callback, thisArg) { * callback = _.createCallback(callback, thisArg); * return _.reduce(collection, function(result, value, index, collection) { * return (result[callback(value, index, collection)] = value, result); * }, {}); * } * }); * * _.toLookup(stooges, 'name'); * // => { 'moe': { 'name': 'moe', 'age': 40 }, 'larry': { 'name': 'larry', 'age': 50 } } */ function createCallback(func, thisArg, argCount) { if (func == null) { return identity; } var type = typeof func; if (type != 'function') { if (type != 'object') { return function(object) { return object[func]; }; } var props = keys(func); return function(object) { var length = props.length, result = false; while (length--) { if (!(result = isEqual(object[props[length]], func[props[length]], indicatorObject))) { break; } } return result; }; } if (typeof thisArg == 'undefined' || (reThis && !reThis.test(fnToString.call(func)))) { return func; } if (argCount === 1) { return function(value) { return func.call(thisArg, value); }; } if (argCount === 2) { return function(a, b) { return func.call(thisArg, a, b); }; } if (argCount === 4) { return function(accumulator, value, index, collection) { return func.call(thisArg, accumulator, value, index, collection); }; } return function(value, index, collection) { return func.call(thisArg, value, index, collection); }; } /** * Creates a function that will delay the execution of `func` until after * `wait` milliseconds have elapsed since the last time it was invoked. Pass * an `options` object to indicate that `func` should be invoked on the leading * and/or trailing edge of the `wait` timeout. Subsequent calls to the debounced * function will return the result of the last `func` call. * * Note: If `leading` and `trailing` options are `true`, `func` will be called * on the trailing edge of the timeout only if the the debounced function is * invoked more than once during the `wait` timeout. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to debounce. * @param {Number} wait The number of milliseconds to delay. * @param {Object} options The options object. * [leading=false] A boolean to specify execution on the leading edge of the timeout. * [maxWait] The maximum time `func` is allowed to be delayed before it's called. * [trailing=true] A boolean to specify execution on the trailing edge of the timeout. * @returns {Function} Returns the new debounced function. * @example * * var lazyLayout = _.debounce(calculateLayout, 300); * jQuery(window).on('resize', lazyLayout); * * jQuery('#postbox').on('click', _.debounce(sendMail, 200, { * 'leading': true, * 'trailing': false * }); */ function debounce(func, wait, options) { var args, result, thisArg, callCount = 0, lastCalled = 0, maxWait = false, maxTimeoutId = null, timeoutId = null, trailing = true; function clear() { clearTimeout(maxTimeoutId); clearTimeout(timeoutId); callCount = 0; maxTimeoutId = timeoutId = null; } function delayed() { var isCalled = trailing && (!leading || callCount > 1); clear(); if (isCalled) { if (maxWait !== false) { lastCalled = new Date; } result = func.apply(thisArg, args); } } function maxDelayed() { clear(); if (trailing || (maxWait !== wait)) { lastCalled = new Date; result = func.apply(thisArg, args); } } wait = nativeMax(0, wait || 0); if (options === true) { var leading = true; trailing = false; } else if (isObject(options)) { leading = options.leading; maxWait = 'maxWait' in options && nativeMax(wait, options.maxWait || 0); trailing = 'trailing' in options ? options.trailing : trailing; } return function() { args = arguments; thisArg = this; callCount++; // avoid issues with Titanium and `undefined` timeout ids // https://github.com/appcelerator/titanium_mobile/blob/3_1_0_GA/android/titanium/src/java/ti/modules/titanium/TitaniumModule.java#L185-L192 clearTimeout(timeoutId); if (maxWait === false) { if (leading && callCount < 2) { result = func.apply(thisArg, args); } } else { var now = new Date; if (!maxTimeoutId && !leading) { lastCalled = now; } var remaining = maxWait - (now - lastCalled); if (remaining <= 0) { clearTimeout(maxTimeoutId); maxTimeoutId = null; lastCalled = now; result = func.apply(thisArg, args); } else if (!maxTimeoutId) { maxTimeoutId = setTimeout(maxDelayed, remaining); } } if (wait !== maxWait) { timeoutId = setTimeout(delayed, wait); } return result; }; } /** * Defers executing the `func` function until the current call stack has cleared. * Additional arguments will be passed to `func` when it is invoked. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to defer. * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with. * @returns {Number} Returns the timer id. * @example * * _.defer(function() { alert('deferred'); }); * // returns from the function before `alert` is called */ function defer(func) { var args = nativeSlice.call(arguments, 1); return setTimeout(function() { func.apply(undefined, args); }, 1); } // use `setImmediate` if it's available in Node.js if (isV8 && freeModule && typeof setImmediate == 'function') { defer = bind(setImmediate, context); } /** * Executes the `func` function after `wait` milliseconds. Additional arguments * will be passed to `func` when it is invoked. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to delay. * @param {Number} wait The number of milliseconds to delay execution. * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with. * @returns {Number} Returns the timer id. * @example * * var log = _.bind(console.log, console); * _.delay(log, 1000, 'logged later'); * // => 'logged later' (Appears after one second.) */ function delay(func, wait) { var args = nativeSlice.call(arguments, 2); return setTimeout(function() { func.apply(undefined, args); }, wait); } /** * 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. The result * cache is exposed as the `cache` property on 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) { function memoized() { var cache = memoized.cache, key = keyPrefix + (resolver ? resolver.apply(this, arguments) : arguments[0]); return hasOwnProperty.call(cache, key) ? cache[key] : (cache[key] = func.apply(this, arguments)); } memoized.cache = {}; return memoized; } /** * Creates a function that is restricted to execute `func` once. Repeat calls to * the function will return the value of the first call. The `func` is executed * with the `this` binding of the created function. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to restrict. * @returns {Function} Returns the new restricted function. * @example * * var initialize = _.once(createApplication); * initialize(); * initialize(); * // `initialize` executes `createApplication` once */ function once(func) { var ran, result; return function() { if (ran) { return result; } ran = true; result = func.apply(this, arguments); // clear the `func` variable so the function may be garbage collected func = null; return result; }; } /** * Creates a function that, when called, invokes `func` with any additional * `partial` arguments prepended to those passed to the new function. This * method is similar to `_.bind`, except it does **not** alter the `this` binding. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to partially apply arguments to. * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied. * @returns {Function} Returns the new partially applied function. * @example * * var greet = function(greeting, name) { return greeting + ' ' + name; }; * var hi = _.partial(greet, 'hi'); * hi('moe'); * // => 'hi moe' */ function partial(func) { return createBound(func, nativeSlice.call(arguments, 1)); } /** * This method is similar to `_.partial`, except that `partial` arguments are * appended to those passed to the new function. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to partially apply arguments to. * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied. * @returns {Function} Returns the new partially applied function. * @example * * var defaultsDeep = _.partialRight(_.merge, _.defaults); * * var options = { * 'variable': 'data', * 'imports': { 'jq': $ } * }; * * defaultsDeep(options, _.templateSettings); * * options.variable * // => 'data' * * options.imports * // => { '_': _, 'jq': $ } */ function partialRight(func) { return createBound(func, nativeSlice.call(arguments, 1), null, indicatorObject); } /** * Creates a function that, when executed, will only call the `func` function * at most once per every `wait` milliseconds. Pass an `options` object to * indicate that `func` should be invoked on the leading and/or trailing edge * of the `wait` timeout. Subsequent calls to the throttled function will * return the result of the last `func` call. * * Note: If `leading` and `trailing` options are `true`, `func` will be called * on the trailing edge of the timeout only if the the throttled function is * invoked more than once during the `wait` timeout. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to throttle. * @param {Number} wait The number of milliseconds to throttle executions to. * @param {Object} options The options object. * [leading=true] A boolean to specify execution on the leading edge of the timeout. * [trailing=true] A boolean to specify execution on the trailing edge of the timeout. * @returns {Function} Returns the new throttled function. * @example * * var throttled = _.throttle(updatePosition, 100); * jQuery(window).on('scroll', throttled); * * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, { * 'trailing': false * })); */ function throttle(func, wait, options) { var leading = true, trailing = true; if (options === false) { leading = false; } else if (isObject(options)) { leading = 'leading' in options ? options.leading : leading; trailing = 'trailing' in options ? options.trailing : trailing; } options = getObject(); options.leading = leading; options.maxWait = wait; options.trailing = trailing; var result = debounce(func, wait, options); releaseObject(options); 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(string).replace(reUnescapedHtml, escapeHtmlChar); } /** * This method returns the first argument passed to it. * * @static * @memberOf _ * @category Utilities * @param {Mixed} value Any value. * @returns {Mixed} Returns `value`. * @example * * var moe = { 'name': 'moe' }; * moe === _.identity(moe); * // => true */ function identity(value) { return value; } /** * Adds functions properties of `object` to the `lodash` function and chainable * wrapper. * * @static * @memberOf _ * @category Utilities * @param {Object} object The object of function properties to add to `lodash`. * @example * * _.mixin({ * 'capitalize': function(string) { * return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase(); * } * }); * * _.capitalize('moe'); * // => 'Moe' * * _('moe').capitalize(); * // => 'Moe' */ function mixin(object) { forEach(functions(object), function(methodName) { var func = lodash[methodName] = object[methodName]; lodash.prototype[methodName] = function() { var value = this.__wrapped__, args = [value]; push.apply(args, arguments); var result = func.apply(lodash, args); return (value && typeof value == 'object' && value === result) ? this : new lodashWrapper(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() { context._ = oldDash; return this; } /** * Converts the given `value` into an integer of the specified `radix`. * If `radix` is `undefined` or `0`, a `radix` of `10` is used unless the * `value` is a hexadecimal, in which case a `radix` of `16` is used. * * Note: This method avoids differences in native ES3 and ES5 `parseInt` * implementations. See http://es5.github.com/#E. * * @static * @memberOf _ * @category Utilities * @param {String} value The value to parse. * @param {Number} [radix] The radix used to interpret the value to parse. * @returns {Number} Returns the new integer value. * @example * * _.parseInt('08'); * // => 8 */ var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) { // Firefox and Opera still follow the ES3 specified implementation of `parseInt` return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0); }; /** * Produces a random number between `min` and `max` (inclusive). If only one * argument is passed, a number between `0` and the given number will be returned. * * @static * @memberOf _ * @category Utilities * @param {Number} [min=0] The minimum possible value. * @param {Number} [max=1] The maximum possible value. * @returns {Number} Returns a random number. * @example * * _.random(0, 5); * // => a number between 0 and 5 * * _.random(5); * // => also a number between 0 and 5 */ function random(min, max) { if (min == null && max == null) { max = 1; } min = +min || 0; if (max == null) { max = min; min = 0; } else { max = +max || 0; } var rand = nativeRandom(); return (min % 1 || max % 1) ? min + nativeMin(rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1))), max) : min + floor(rand * (max - min + 1)); } /** * Resolves the value of `property` on `object`. If `property` is a function, * it will be invoked with the `this` binding of `object` and its result returned, * else the property value is returned. If `object` is falsey, then `undefined` * is returned. * * @static * @memberOf _ * @category Utilities * @param {Object} object The object to inspect. * @param {String} property The property to get the value of. * @returns {Mixed} Returns the resolved value. * @example * * var object = { * 'cheese': 'crumpets', * 'stuff': function() { * return 'nonsense'; * } * }; * * _.result(object, 'cheese'); * // => 'crumpets' * * _.result(object, 'stuff'); * // => 'nonsense' */ function result(object, property) { var value = object ? object[property] : undefined; return isFunction(value) ? object[property]() : value; } /** * 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 = +n) > -1 ? n : 0; var index = -1, result = Array(n); callback = lodash.createCallback(callback, thisArg, 1); while (++index < n) { result[index] = callback(index); } return result; } /** * The inverse 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(string).replace(reEscapedHtml, unescapeHtmlChar); } /** * Generates a unique ID. If `prefix` is passed, the ID will be appended to it. * * @static * @memberOf _ * @category Utilities * @param {String} [prefix] The value to prefix the ID with. * @returns {String} Returns the unique ID. * @example * * _.uniqueId('contact_'); * // => 'contact_104' * * _.uniqueId(); * // => '105' */ function uniqueId(prefix) { var id = ++idCounter; return String(prefix == null ? '' : prefix) + id; } /*--------------------------------------------------------------------------*/ /** * Invokes `interceptor` with the `value` as the first argument, and then * returns `value`. The purpose of this method is to "tap into" a method chain, * in order to perform operations on intermediate results within the chain. * * @static * @memberOf _ * @category Chaining * @param {Mixed} value The value to pass to `interceptor`. * @param {Function} interceptor The function to invoke. * @returns {Mixed} Returns `value`. * @example * * _([1, 2, 3, 4]) * .filter(function(num) { return num % 2 == 0; }) * .tap(alert) * .map(function(num) { return num * num; }) * .value(); * // => // [2, 4] (alerted) * // => [4, 16] */ function tap(value, interceptor) { interceptor(value); return value; } /** * Produces the `toString` result of the wrapped value. * * @name toString * @memberOf _ * @category Chaining * @returns {String} Returns the string result. * @example * * _([1, 2, 3]).toString(); * // => '1,2,3' */ function wrapperToString() { return String(this.__wrapped__); } /** * Extracts the wrapped value. * * @name valueOf * @memberOf _ * @alias value * @category Chaining * @returns {Mixed} Returns the wrapped value. * @example * * _([1, 2, 3]).valueOf(); * // => [1, 2, 3] */ function wrapperValueOf() { return this.__wrapped__; } /*--------------------------------------------------------------------------*/ // add functions that return wrapped values when chaining lodash.after = after; lodash.assign = assign; lodash.at = at; lodash.bind = bind; lodash.bindAll = bindAll; lodash.bindKey = bindKey; lodash.compact = compact; lodash.compose = compose; lodash.countBy = countBy; lodash.createCallback = createCallback; lodash.debounce = debounce; lodash.defaults = defaults; lodash.defer = defer; lodash.delay = delay; lodash.difference = difference; lodash.filter = filter; lodash.flatten = flatten; lodash.forEach = forEach; lodash.forIn = forIn; lodash.forOwn = forOwn; lodash.functions = functions; lodash.groupBy = groupBy; lodash.initial = initial; lodash.intersection = intersection; lodash.invert = invert; lodash.invoke = invoke; lodash.keys = keys; lodash.map = map; lodash.max = max; lodash.memoize = memoize; lodash.merge = merge; lodash.min = min; lodash.omit = omit; lodash.once = once; lodash.pairs = pairs; lodash.partial = partial; lodash.partialRight = partialRight; lodash.pick = pick; lodash.pluck = pluck; lodash.range = range; lodash.reject = reject; lodash.rest = rest; lodash.shuffle = shuffle; lodash.sortBy = sortBy; lodash.tap = tap; lodash.throttle = throttle; lodash.times = times; lodash.toArray = toArray; lodash.transform = transform; lodash.union = union; lodash.uniq = uniq; lodash.unzip = unzip; lodash.values = values; lodash.where = where; lodash.without = without; lodash.wrap = wrap; lodash.zip = zip; lodash.zipObject = zipObject; // add aliases lodash.collect = map; lodash.drop = rest; lodash.each = forEach; lodash.extend = assign; lodash.methods = functions; lodash.object = zipObject; lodash.select = filter; lodash.tail = rest; lodash.unique = uniq; // add functions to `lodash.prototype` mixin(lodash); // add Underscore compat lodash.chain = lodash; lodash.prototype.chain = function() { return this; }; /*--------------------------------------------------------------------------*/ // add functions that return unwrapped values when chaining lodash.clone = clone; lodash.cloneDeep = cloneDeep; lodash.contains = contains; lodash.escape = escape; lodash.every = every; lodash.find = find; lodash.findIndex = findIndex; lodash.findKey = findKey; lodash.has = has; lodash.identity = identity; lodash.indexOf = indexOf; lodash.isArguments = isArguments; lodash.isArray = isArray; lodash.isBoolean = isBoolean; lodash.isDate = isDate; lodash.isElement = isElement; lodash.isEmpty = isEmpty; lodash.isEqual = isEqual; lodash.isFinite = isFinite; lodash.isFunction = isFunction; lodash.isNaN = isNaN; lodash.isNull = isNull; lodash.isNumber = isNumber; lodash.isObject = isObject; lodash.isPlainObject = isPlainObject; lodash.isRegExp = isRegExp; lodash.isString = isString; lodash.isUndefined = isUndefined; lodash.lastIndexOf = lastIndexOf; lodash.mixin = mixin; lodash.noConflict = noConflict; lodash.parseInt = parseInt; lodash.random = random; lodash.reduce = reduce; lodash.reduceRight = reduceRight; lodash.result = result; lodash.runInContext = runInContext; lodash.size = size; lodash.some = some; lodash.sortedIndex = sortedIndex; lodash.unescape = unescape; lodash.uniqueId = uniqueId; // add aliases lodash.all = every; lodash.any = some; lodash.detect = find; lodash.findWhere = find; lodash.foldl = reduce; lodash.foldr = reduceRight; lodash.include = contains; lodash.inject = reduce; forOwn(lodash, function(func, methodName) { if (!lodash.prototype[methodName]) { lodash.prototype[methodName] = function() { var args = [this.__wrapped__]; push.apply(args, arguments); return func.apply(lodash, args); }; } }); /*--------------------------------------------------------------------------*/ // add functions capable of returning wrapped and unwrapped values when chaining lodash.first = first; lodash.last = last; // add aliases lodash.take = first; lodash.head = first; forOwn(lodash, function(func, methodName) { if (!lodash.prototype[methodName]) { lodash.prototype[methodName]= function(callback, thisArg) { var result = func(this.__wrapped__, callback, thisArg); return callback == null || (thisArg && typeof callback != 'function') ? result : new lodashWrapper(result); }; } }); /*--------------------------------------------------------------------------*/ /** * The semantic version number. * * @static * @memberOf _ * @type String */ lodash.VERSION = '1.3.0'; // add "Chaining" functions to the wrapper lodash.prototype.toString = wrapperToString; lodash.prototype.value = wrapperValueOf; lodash.prototype.valueOf = wrapperValueOf; // add `Array` functions that return unwrapped values basicEach(['join', 'pop', 'shift'], function(methodName) { var func = arrayRef[methodName]; lodash.prototype[methodName] = function() { return func.apply(this.__wrapped__, arguments); }; }); // add `Array` functions that return the wrapped value basicEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) { var func = arrayRef[methodName]; lodash.prototype[methodName] = function() { func.apply(this.__wrapped__, arguments); return this; }; }); // add `Array` functions that return new wrapped values basicEach(['concat', 'slice', 'splice'], function(methodName) { var func = arrayRef[methodName]; lodash.prototype[methodName] = function() { return new lodashWrapper(func.apply(this.__wrapped__, arguments)); }; }); // avoid array-like object bugs with `Array#shift` and `Array#splice` // in Firefox < 10 and IE < 9 if (!support.spliceObjects) { basicEach(['pop', 'shift', 'splice'], function(methodName) { var func = arrayRef[methodName], isSplice = methodName == 'splice'; lodash.prototype[methodName] = function() { var value = this.__wrapped__, result = func.apply(value, arguments); if (value.length === 0) { delete value[0]; } return isSplice ? new lodashWrapper(result) : result; }; }); } return lodash; } /*--------------------------------------------------------------------------*/ // expose Lo-Dash var _ = runInContext(); // some AMD build optimizers, like r.js, check for specific condition patterns like the following: if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { // Expose Lo-Dash to the global object even when an AMD loader is present in // case Lo-Dash was injected by a third-party script and not intended to be // loaded as a module. The global assignment can be reverted in the Lo-Dash // module via its `noConflict()` method. window._ = _; // define as an anonymous module so, through path mapping, it can be // referenced as the "underscore" module define(function() { return _; }); } // check for `exports` after `define` in case a build optimizer adds an `exports` object else if (freeExports && !freeExports.nodeType) { // in Node.js or RingoJS v0.8.0+ if (freeModule) { (freeModule.exports = _)._ = _; } // in Narwhal or RingoJS v0.7.0- else { freeExports._ = _; } } else { // in a browser or Rhino window._ = _; } }(this));