underscore-rails 1.5.2 → 1.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
- // Underscore.js 1.5.2
1
+ // Underscore.js 1.8.3
2
2
  // http://underscorejs.org
3
- // (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
3
+ // (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
4
4
  // Underscore may be freely distributed under the MIT license.
5
5
 
6
6
  (function() {
@@ -14,9 +14,6 @@
14
14
  // Save the previous value of the `_` variable.
15
15
  var previousUnderscore = root._;
16
16
 
17
- // Establish the object that gets returned to break out of a loop iteration.
18
- var breaker = {};
19
-
20
17
  // Save bytes in the minified (but not gzipped) version:
21
18
  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
22
19
 
@@ -24,25 +21,19 @@
24
21
  var
25
22
  push = ArrayProto.push,
26
23
  slice = ArrayProto.slice,
27
- concat = ArrayProto.concat,
28
24
  toString = ObjProto.toString,
29
25
  hasOwnProperty = ObjProto.hasOwnProperty;
30
26
 
31
27
  // All **ECMAScript 5** native function implementations that we hope to use
32
28
  // are declared here.
33
29
  var
34
- nativeForEach = ArrayProto.forEach,
35
- nativeMap = ArrayProto.map,
36
- nativeReduce = ArrayProto.reduce,
37
- nativeReduceRight = ArrayProto.reduceRight,
38
- nativeFilter = ArrayProto.filter,
39
- nativeEvery = ArrayProto.every,
40
- nativeSome = ArrayProto.some,
41
- nativeIndexOf = ArrayProto.indexOf,
42
- nativeLastIndexOf = ArrayProto.lastIndexOf,
43
30
  nativeIsArray = Array.isArray,
44
31
  nativeKeys = Object.keys,
45
- nativeBind = FuncProto.bind;
32
+ nativeBind = FuncProto.bind,
33
+ nativeCreate = Object.create;
34
+
35
+ // Naked function reference for surrogate-prototype-swapping.
36
+ var Ctor = function(){};
46
37
 
47
38
  // Create a safe reference to the Underscore object for use below.
48
39
  var _ = function(obj) {
@@ -53,8 +44,7 @@
53
44
 
54
45
  // Export the Underscore object for **Node.js**, with
55
46
  // backwards-compatibility for the old `require()` API. If we're in
56
- // the browser, add `_` as a global object via a string identifier,
57
- // for Closure Compiler "advanced" mode.
47
+ // the browser, add `_` as a global object.
58
48
  if (typeof exports !== 'undefined') {
59
49
  if (typeof module !== 'undefined' && module.exports) {
60
50
  exports = module.exports = _;
@@ -65,160 +55,217 @@
65
55
  }
66
56
 
67
57
  // Current version.
68
- _.VERSION = '1.5.2';
58
+ _.VERSION = '1.8.3';
59
+
60
+ // Internal function that returns an efficient (for current engines) version
61
+ // of the passed-in callback, to be repeatedly applied in other Underscore
62
+ // functions.
63
+ var optimizeCb = function(func, context, argCount) {
64
+ if (context === void 0) return func;
65
+ switch (argCount == null ? 3 : argCount) {
66
+ case 1: return function(value) {
67
+ return func.call(context, value);
68
+ };
69
+ case 2: return function(value, other) {
70
+ return func.call(context, value, other);
71
+ };
72
+ case 3: return function(value, index, collection) {
73
+ return func.call(context, value, index, collection);
74
+ };
75
+ case 4: return function(accumulator, value, index, collection) {
76
+ return func.call(context, accumulator, value, index, collection);
77
+ };
78
+ }
79
+ return function() {
80
+ return func.apply(context, arguments);
81
+ };
82
+ };
83
+
84
+ // A mostly-internal function to generate callbacks that can be applied
85
+ // to each element in a collection, returning the desired result — either
86
+ // identity, an arbitrary callback, a property matcher, or a property accessor.
87
+ var cb = function(value, context, argCount) {
88
+ if (value == null) return _.identity;
89
+ if (_.isFunction(value)) return optimizeCb(value, context, argCount);
90
+ if (_.isObject(value)) return _.matcher(value);
91
+ return _.property(value);
92
+ };
93
+ _.iteratee = function(value, context) {
94
+ return cb(value, context, Infinity);
95
+ };
96
+
97
+ // An internal function for creating assigner functions.
98
+ var createAssigner = function(keysFunc, undefinedOnly) {
99
+ return function(obj) {
100
+ var length = arguments.length;
101
+ if (length < 2 || obj == null) return obj;
102
+ for (var index = 1; index < length; index++) {
103
+ var source = arguments[index],
104
+ keys = keysFunc(source),
105
+ l = keys.length;
106
+ for (var i = 0; i < l; i++) {
107
+ var key = keys[i];
108
+ if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key];
109
+ }
110
+ }
111
+ return obj;
112
+ };
113
+ };
114
+
115
+ // An internal function for creating a new object that inherits from another.
116
+ var baseCreate = function(prototype) {
117
+ if (!_.isObject(prototype)) return {};
118
+ if (nativeCreate) return nativeCreate(prototype);
119
+ Ctor.prototype = prototype;
120
+ var result = new Ctor;
121
+ Ctor.prototype = null;
122
+ return result;
123
+ };
124
+
125
+ var property = function(key) {
126
+ return function(obj) {
127
+ return obj == null ? void 0 : obj[key];
128
+ };
129
+ };
130
+
131
+ // Helper for collection methods to determine whether a collection
132
+ // should be iterated as an array or as an object
133
+ // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
134
+ // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
135
+ var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
136
+ var getLength = property('length');
137
+ var isArrayLike = function(collection) {
138
+ var length = getLength(collection);
139
+ return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
140
+ };
69
141
 
70
142
  // Collection Functions
71
143
  // --------------------
72
144
 
73
145
  // The cornerstone, an `each` implementation, aka `forEach`.
74
- // Handles objects with the built-in `forEach`, arrays, and raw objects.
75
- // Delegates to **ECMAScript 5**'s native `forEach` if available.
76
- var each = _.each = _.forEach = function(obj, iterator, context) {
77
- if (obj == null) return;
78
- if (nativeForEach && obj.forEach === nativeForEach) {
79
- obj.forEach(iterator, context);
80
- } else if (obj.length === +obj.length) {
81
- for (var i = 0, length = obj.length; i < length; i++) {
82
- if (iterator.call(context, obj[i], i, obj) === breaker) return;
146
+ // Handles raw objects in addition to array-likes. Treats all
147
+ // sparse array-likes as if they were dense.
148
+ _.each = _.forEach = function(obj, iteratee, context) {
149
+ iteratee = optimizeCb(iteratee, context);
150
+ var i, length;
151
+ if (isArrayLike(obj)) {
152
+ for (i = 0, length = obj.length; i < length; i++) {
153
+ iteratee(obj[i], i, obj);
83
154
  }
84
155
  } else {
85
156
  var keys = _.keys(obj);
86
- for (var i = 0, length = keys.length; i < length; i++) {
87
- if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
157
+ for (i = 0, length = keys.length; i < length; i++) {
158
+ iteratee(obj[keys[i]], keys[i], obj);
88
159
  }
89
160
  }
161
+ return obj;
90
162
  };
91
163
 
92
- // Return the results of applying the iterator to each element.
93
- // Delegates to **ECMAScript 5**'s native `map` if available.
94
- _.map = _.collect = function(obj, iterator, context) {
95
- var results = [];
96
- if (obj == null) return results;
97
- if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
98
- each(obj, function(value, index, list) {
99
- results.push(iterator.call(context, value, index, list));
100
- });
164
+ // Return the results of applying the iteratee to each element.
165
+ _.map = _.collect = function(obj, iteratee, context) {
166
+ iteratee = cb(iteratee, context);
167
+ var keys = !isArrayLike(obj) && _.keys(obj),
168
+ length = (keys || obj).length,
169
+ results = Array(length);
170
+ for (var index = 0; index < length; index++) {
171
+ var currentKey = keys ? keys[index] : index;
172
+ results[index] = iteratee(obj[currentKey], currentKey, obj);
173
+ }
101
174
  return results;
102
175
  };
103
176
 
104
- var reduceError = 'Reduce of empty array with no initial value';
105
-
106
- // **Reduce** builds up a single result from a list of values, aka `inject`,
107
- // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
108
- _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
109
- var initial = arguments.length > 2;
110
- if (obj == null) obj = [];
111
- if (nativeReduce && obj.reduce === nativeReduce) {
112
- if (context) iterator = _.bind(iterator, context);
113
- return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
177
+ // Create a reducing function iterating left or right.
178
+ function createReduce(dir) {
179
+ // Optimized iterator function as using arguments.length
180
+ // in the main function will deoptimize the, see #1991.
181
+ function iterator(obj, iteratee, memo, keys, index, length) {
182
+ for (; index >= 0 && index < length; index += dir) {
183
+ var currentKey = keys ? keys[index] : index;
184
+ memo = iteratee(memo, obj[currentKey], currentKey, obj);
185
+ }
186
+ return memo;
114
187
  }
115
- each(obj, function(value, index, list) {
116
- if (!initial) {
117
- memo = value;
118
- initial = true;
119
- } else {
120
- memo = iterator.call(context, memo, value, index, list);
188
+
189
+ return function(obj, iteratee, memo, context) {
190
+ iteratee = optimizeCb(iteratee, context, 4);
191
+ var keys = !isArrayLike(obj) && _.keys(obj),
192
+ length = (keys || obj).length,
193
+ index = dir > 0 ? 0 : length - 1;
194
+ // Determine the initial value if none is provided.
195
+ if (arguments.length < 3) {
196
+ memo = obj[keys ? keys[index] : index];
197
+ index += dir;
121
198
  }
122
- });
123
- if (!initial) throw new TypeError(reduceError);
124
- return memo;
125
- };
199
+ return iterator(obj, iteratee, memo, keys, index, length);
200
+ };
201
+ }
202
+
203
+ // **Reduce** builds up a single result from a list of values, aka `inject`,
204
+ // or `foldl`.
205
+ _.reduce = _.foldl = _.inject = createReduce(1);
126
206
 
127
207
  // The right-associative version of reduce, also known as `foldr`.
128
- // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
129
- _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
130
- var initial = arguments.length > 2;
131
- if (obj == null) obj = [];
132
- if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
133
- if (context) iterator = _.bind(iterator, context);
134
- return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
135
- }
136
- var length = obj.length;
137
- if (length !== +length) {
138
- var keys = _.keys(obj);
139
- length = keys.length;
140
- }
141
- each(obj, function(value, index, list) {
142
- index = keys ? keys[--length] : --length;
143
- if (!initial) {
144
- memo = obj[index];
145
- initial = true;
146
- } else {
147
- memo = iterator.call(context, memo, obj[index], index, list);
148
- }
149
- });
150
- if (!initial) throw new TypeError(reduceError);
151
- return memo;
152
- };
208
+ _.reduceRight = _.foldr = createReduce(-1);
153
209
 
154
210
  // Return the first value which passes a truth test. Aliased as `detect`.
155
- _.find = _.detect = function(obj, iterator, context) {
156
- var result;
157
- any(obj, function(value, index, list) {
158
- if (iterator.call(context, value, index, list)) {
159
- result = value;
160
- return true;
161
- }
162
- });
163
- return result;
211
+ _.find = _.detect = function(obj, predicate, context) {
212
+ var key;
213
+ if (isArrayLike(obj)) {
214
+ key = _.findIndex(obj, predicate, context);
215
+ } else {
216
+ key = _.findKey(obj, predicate, context);
217
+ }
218
+ if (key !== void 0 && key !== -1) return obj[key];
164
219
  };
165
220
 
166
221
  // Return all the elements that pass a truth test.
167
- // Delegates to **ECMAScript 5**'s native `filter` if available.
168
222
  // Aliased as `select`.
169
- _.filter = _.select = function(obj, iterator, context) {
223
+ _.filter = _.select = function(obj, predicate, context) {
170
224
  var results = [];
171
- if (obj == null) return results;
172
- if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
173
- each(obj, function(value, index, list) {
174
- if (iterator.call(context, value, index, list)) results.push(value);
225
+ predicate = cb(predicate, context);
226
+ _.each(obj, function(value, index, list) {
227
+ if (predicate(value, index, list)) results.push(value);
175
228
  });
176
229
  return results;
177
230
  };
178
231
 
179
232
  // Return all the elements for which a truth test fails.
180
- _.reject = function(obj, iterator, context) {
181
- return _.filter(obj, function(value, index, list) {
182
- return !iterator.call(context, value, index, list);
183
- }, context);
233
+ _.reject = function(obj, predicate, context) {
234
+ return _.filter(obj, _.negate(cb(predicate)), context);
184
235
  };
185
236
 
186
237
  // Determine whether all of the elements match a truth test.
187
- // Delegates to **ECMAScript 5**'s native `every` if available.
188
238
  // Aliased as `all`.
189
- _.every = _.all = function(obj, iterator, context) {
190
- iterator || (iterator = _.identity);
191
- var result = true;
192
- if (obj == null) return result;
193
- if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
194
- each(obj, function(value, index, list) {
195
- if (!(result = result && iterator.call(context, value, index, list))) return breaker;
196
- });
197
- return !!result;
239
+ _.every = _.all = function(obj, predicate, context) {
240
+ predicate = cb(predicate, context);
241
+ var keys = !isArrayLike(obj) && _.keys(obj),
242
+ length = (keys || obj).length;
243
+ for (var index = 0; index < length; index++) {
244
+ var currentKey = keys ? keys[index] : index;
245
+ if (!predicate(obj[currentKey], currentKey, obj)) return false;
246
+ }
247
+ return true;
198
248
  };
199
249
 
200
250
  // Determine if at least one element in the object matches a truth test.
201
- // Delegates to **ECMAScript 5**'s native `some` if available.
202
251
  // Aliased as `any`.
203
- var any = _.some = _.any = function(obj, iterator, context) {
204
- iterator || (iterator = _.identity);
205
- var result = false;
206
- if (obj == null) return result;
207
- if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
208
- each(obj, function(value, index, list) {
209
- if (result || (result = iterator.call(context, value, index, list))) return breaker;
210
- });
211
- return !!result;
252
+ _.some = _.any = function(obj, predicate, context) {
253
+ predicate = cb(predicate, context);
254
+ var keys = !isArrayLike(obj) && _.keys(obj),
255
+ length = (keys || obj).length;
256
+ for (var index = 0; index < length; index++) {
257
+ var currentKey = keys ? keys[index] : index;
258
+ if (predicate(obj[currentKey], currentKey, obj)) return true;
259
+ }
260
+ return false;
212
261
  };
213
262
 
214
- // Determine if the array or object contains a given value (using `===`).
215
- // Aliased as `include`.
216
- _.contains = _.include = function(obj, target) {
217
- if (obj == null) return false;
218
- if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
219
- return any(obj, function(value) {
220
- return value === target;
221
- });
263
+ // Determine if the array or object contains a given item (using `===`).
264
+ // Aliased as `includes` and `include`.
265
+ _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {
266
+ if (!isArrayLike(obj)) obj = _.values(obj);
267
+ if (typeof fromIndex != 'number' || guard) fromIndex = 0;
268
+ return _.indexOf(obj, item, fromIndex) >= 0;
222
269
  };
223
270
 
224
271
  // Invoke a method (with arguments) on every item in a collection.
@@ -226,100 +273,111 @@
226
273
  var args = slice.call(arguments, 2);
227
274
  var isFunc = _.isFunction(method);
228
275
  return _.map(obj, function(value) {
229
- return (isFunc ? method : value[method]).apply(value, args);
276
+ var func = isFunc ? method : value[method];
277
+ return func == null ? func : func.apply(value, args);
230
278
  });
231
279
  };
232
280
 
233
281
  // Convenience version of a common use case of `map`: fetching a property.
234
282
  _.pluck = function(obj, key) {
235
- return _.map(obj, function(value){ return value[key]; });
283
+ return _.map(obj, _.property(key));
236
284
  };
237
285
 
238
286
  // Convenience version of a common use case of `filter`: selecting only objects
239
287
  // containing specific `key:value` pairs.
240
- _.where = function(obj, attrs, first) {
241
- if (_.isEmpty(attrs)) return first ? void 0 : [];
242
- return _[first ? 'find' : 'filter'](obj, function(value) {
243
- for (var key in attrs) {
244
- if (attrs[key] !== value[key]) return false;
245
- }
246
- return true;
247
- });
288
+ _.where = function(obj, attrs) {
289
+ return _.filter(obj, _.matcher(attrs));
248
290
  };
249
291
 
250
292
  // Convenience version of a common use case of `find`: getting the first object
251
293
  // containing specific `key:value` pairs.
252
294
  _.findWhere = function(obj, attrs) {
253
- return _.where(obj, attrs, true);
295
+ return _.find(obj, _.matcher(attrs));
254
296
  };
255
297
 
256
- // Return the maximum element or (element-based computation).
257
- // Can't optimize arrays of integers longer than 65,535 elements.
258
- // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)
259
- _.max = function(obj, iterator, context) {
260
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
261
- return Math.max.apply(Math, obj);
298
+ // Return the maximum element (or element-based computation).
299
+ _.max = function(obj, iteratee, context) {
300
+ var result = -Infinity, lastComputed = -Infinity,
301
+ value, computed;
302
+ if (iteratee == null && obj != null) {
303
+ obj = isArrayLike(obj) ? obj : _.values(obj);
304
+ for (var i = 0, length = obj.length; i < length; i++) {
305
+ value = obj[i];
306
+ if (value > result) {
307
+ result = value;
308
+ }
309
+ }
310
+ } else {
311
+ iteratee = cb(iteratee, context);
312
+ _.each(obj, function(value, index, list) {
313
+ computed = iteratee(value, index, list);
314
+ if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
315
+ result = value;
316
+ lastComputed = computed;
317
+ }
318
+ });
262
319
  }
263
- if (!iterator && _.isEmpty(obj)) return -Infinity;
264
- var result = {computed : -Infinity, value: -Infinity};
265
- each(obj, function(value, index, list) {
266
- var computed = iterator ? iterator.call(context, value, index, list) : value;
267
- computed > result.computed && (result = {value : value, computed : computed});
268
- });
269
- return result.value;
320
+ return result;
270
321
  };
271
322
 
272
323
  // Return the minimum element (or element-based computation).
273
- _.min = function(obj, iterator, context) {
274
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
275
- return Math.min.apply(Math, obj);
324
+ _.min = function(obj, iteratee, context) {
325
+ var result = Infinity, lastComputed = Infinity,
326
+ value, computed;
327
+ if (iteratee == null && obj != null) {
328
+ obj = isArrayLike(obj) ? obj : _.values(obj);
329
+ for (var i = 0, length = obj.length; i < length; i++) {
330
+ value = obj[i];
331
+ if (value < result) {
332
+ result = value;
333
+ }
334
+ }
335
+ } else {
336
+ iteratee = cb(iteratee, context);
337
+ _.each(obj, function(value, index, list) {
338
+ computed = iteratee(value, index, list);
339
+ if (computed < lastComputed || computed === Infinity && result === Infinity) {
340
+ result = value;
341
+ lastComputed = computed;
342
+ }
343
+ });
276
344
  }
277
- if (!iterator && _.isEmpty(obj)) return Infinity;
278
- var result = {computed : Infinity, value: Infinity};
279
- each(obj, function(value, index, list) {
280
- var computed = iterator ? iterator.call(context, value, index, list) : value;
281
- computed < result.computed && (result = {value : value, computed : computed});
282
- });
283
- return result.value;
345
+ return result;
284
346
  };
285
347
 
286
- // Shuffle an array, using the modern version of the
287
- // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
348
+ // Shuffle a collection, using the modern version of the
349
+ // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/FisherYates_shuffle).
288
350
  _.shuffle = function(obj) {
289
- var rand;
290
- var index = 0;
291
- var shuffled = [];
292
- each(obj, function(value) {
293
- rand = _.random(index++);
294
- shuffled[index - 1] = shuffled[rand];
295
- shuffled[rand] = value;
296
- });
351
+ var set = isArrayLike(obj) ? obj : _.values(obj);
352
+ var length = set.length;
353
+ var shuffled = Array(length);
354
+ for (var index = 0, rand; index < length; index++) {
355
+ rand = _.random(0, index);
356
+ if (rand !== index) shuffled[index] = shuffled[rand];
357
+ shuffled[rand] = set[index];
358
+ }
297
359
  return shuffled;
298
360
  };
299
361
 
300
- // Sample **n** random values from an array.
301
- // If **n** is not specified, returns a single random element from the array.
362
+ // Sample **n** random values from a collection.
363
+ // If **n** is not specified, returns a single random element.
302
364
  // The internal `guard` argument allows it to work with `map`.
303
365
  _.sample = function(obj, n, guard) {
304
- if (arguments.length < 2 || guard) {
366
+ if (n == null || guard) {
367
+ if (!isArrayLike(obj)) obj = _.values(obj);
305
368
  return obj[_.random(obj.length - 1)];
306
369
  }
307
370
  return _.shuffle(obj).slice(0, Math.max(0, n));
308
371
  };
309
372
 
310
- // An internal function to generate lookup iterators.
311
- var lookupIterator = function(value) {
312
- return _.isFunction(value) ? value : function(obj){ return obj[value]; };
313
- };
314
-
315
- // Sort the object's values by a criterion produced by an iterator.
316
- _.sortBy = function(obj, value, context) {
317
- var iterator = lookupIterator(value);
373
+ // Sort the object's values by a criterion produced by an iteratee.
374
+ _.sortBy = function(obj, iteratee, context) {
375
+ iteratee = cb(iteratee, context);
318
376
  return _.pluck(_.map(obj, function(value, index, list) {
319
377
  return {
320
378
  value: value,
321
379
  index: index,
322
- criteria: iterator.call(context, value, index, list)
380
+ criteria: iteratee(value, index, list)
323
381
  };
324
382
  }).sort(function(left, right) {
325
383
  var a = left.criteria;
@@ -334,12 +392,12 @@
334
392
 
335
393
  // An internal function used for aggregate "group by" operations.
336
394
  var group = function(behavior) {
337
- return function(obj, value, context) {
395
+ return function(obj, iteratee, context) {
338
396
  var result = {};
339
- var iterator = value == null ? _.identity : lookupIterator(value);
340
- each(obj, function(value, index) {
341
- var key = iterator.call(context, value, index, obj);
342
- behavior(result, key, value);
397
+ iteratee = cb(iteratee, context);
398
+ _.each(obj, function(value, index) {
399
+ var key = iteratee(value, index, obj);
400
+ behavior(result, value, key);
343
401
  });
344
402
  return result;
345
403
  };
@@ -347,48 +405,46 @@
347
405
 
348
406
  // Groups the object's values by a criterion. Pass either a string attribute
349
407
  // to group by, or a function that returns the criterion.
350
- _.groupBy = group(function(result, key, value) {
351
- (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
408
+ _.groupBy = group(function(result, value, key) {
409
+ if (_.has(result, key)) result[key].push(value); else result[key] = [value];
352
410
  });
353
411
 
354
412
  // Indexes the object's values by a criterion, similar to `groupBy`, but for
355
413
  // when you know that your index values will be unique.
356
- _.indexBy = group(function(result, key, value) {
414
+ _.indexBy = group(function(result, value, key) {
357
415
  result[key] = value;
358
416
  });
359
417
 
360
418
  // Counts instances of an object that group by a certain criterion. Pass
361
419
  // either a string attribute to count by, or a function that returns the
362
420
  // criterion.
363
- _.countBy = group(function(result, key) {
364
- _.has(result, key) ? result[key]++ : result[key] = 1;
421
+ _.countBy = group(function(result, value, key) {
422
+ if (_.has(result, key)) result[key]++; else result[key] = 1;
365
423
  });
366
424
 
367
- // Use a comparator function to figure out the smallest index at which
368
- // an object should be inserted so as to maintain order. Uses binary search.
369
- _.sortedIndex = function(array, obj, iterator, context) {
370
- iterator = iterator == null ? _.identity : lookupIterator(iterator);
371
- var value = iterator.call(context, obj);
372
- var low = 0, high = array.length;
373
- while (low < high) {
374
- var mid = (low + high) >>> 1;
375
- iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
376
- }
377
- return low;
378
- };
379
-
380
425
  // Safely create a real, live array from anything iterable.
381
426
  _.toArray = function(obj) {
382
427
  if (!obj) return [];
383
428
  if (_.isArray(obj)) return slice.call(obj);
384
- if (obj.length === +obj.length) return _.map(obj, _.identity);
429
+ if (isArrayLike(obj)) return _.map(obj, _.identity);
385
430
  return _.values(obj);
386
431
  };
387
432
 
388
433
  // Return the number of elements in an object.
389
434
  _.size = function(obj) {
390
435
  if (obj == null) return 0;
391
- return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
436
+ return isArrayLike(obj) ? obj.length : _.keys(obj).length;
437
+ };
438
+
439
+ // Split a collection into two arrays: one whose elements all satisfy the given
440
+ // predicate, and one whose elements all do not satisfy the predicate.
441
+ _.partition = function(obj, predicate, context) {
442
+ predicate = cb(predicate, context);
443
+ var pass = [], fail = [];
444
+ _.each(obj, function(value, key, obj) {
445
+ (predicate(value, key, obj) ? pass : fail).push(value);
446
+ });
447
+ return [pass, fail];
392
448
  };
393
449
 
394
450
  // Array Functions
@@ -399,34 +455,30 @@
399
455
  // allows it to work with `_.map`.
400
456
  _.first = _.head = _.take = function(array, n, guard) {
401
457
  if (array == null) return void 0;
402
- return (n == null) || guard ? array[0] : slice.call(array, 0, n);
458
+ if (n == null || guard) return array[0];
459
+ return _.initial(array, array.length - n);
403
460
  };
404
461
 
405
462
  // Returns everything but the last entry of the array. Especially useful on
406
463
  // the arguments object. Passing **n** will return all the values in
407
- // the array, excluding the last N. The **guard** check allows it to work with
408
- // `_.map`.
464
+ // the array, excluding the last N.
409
465
  _.initial = function(array, n, guard) {
410
- return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
466
+ return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
411
467
  };
412
468
 
413
469
  // Get the last element of an array. Passing **n** will return the last N
414
- // values in the array. The **guard** check allows it to work with `_.map`.
470
+ // values in the array.
415
471
  _.last = function(array, n, guard) {
416
472
  if (array == null) return void 0;
417
- if ((n == null) || guard) {
418
- return array[array.length - 1];
419
- } else {
420
- return slice.call(array, Math.max(array.length - n, 0));
421
- }
473
+ if (n == null || guard) return array[array.length - 1];
474
+ return _.rest(array, Math.max(0, array.length - n));
422
475
  };
423
476
 
424
477
  // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
425
478
  // Especially useful on the arguments object. Passing an **n** will return
426
- // the rest N values in the array. The **guard**
427
- // check allows it to work with `_.map`.
479
+ // the rest N values in the array.
428
480
  _.rest = _.tail = _.drop = function(array, n, guard) {
429
- return slice.call(array, (n == null) || guard ? 1 : n);
481
+ return slice.call(array, n == null || guard ? 1 : n);
430
482
  };
431
483
 
432
484
  // Trim out all falsy values from an array.
@@ -435,23 +487,28 @@
435
487
  };
436
488
 
437
489
  // Internal implementation of a recursive `flatten` function.
438
- var flatten = function(input, shallow, output) {
439
- if (shallow && _.every(input, _.isArray)) {
440
- return concat.apply(output, input);
441
- }
442
- each(input, function(value) {
443
- if (_.isArray(value) || _.isArguments(value)) {
444
- shallow ? push.apply(output, value) : flatten(value, shallow, output);
445
- } else {
446
- output.push(value);
490
+ var flatten = function(input, shallow, strict, startIndex) {
491
+ var output = [], idx = 0;
492
+ for (var i = startIndex || 0, length = getLength(input); i < length; i++) {
493
+ var value = input[i];
494
+ if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
495
+ //flatten current level of array or arguments object
496
+ if (!shallow) value = flatten(value, shallow, strict);
497
+ var j = 0, len = value.length;
498
+ output.length += len;
499
+ while (j < len) {
500
+ output[idx++] = value[j++];
501
+ }
502
+ } else if (!strict) {
503
+ output[idx++] = value;
447
504
  }
448
- });
505
+ }
449
506
  return output;
450
507
  };
451
508
 
452
509
  // Flatten out an array, either recursively (by default), or just one level.
453
510
  _.flatten = function(array, shallow) {
454
- return flatten(array, shallow, []);
511
+ return flatten(array, shallow, false);
455
512
  };
456
513
 
457
514
  // Return a version of the array that does not contain the specified value(s).
@@ -462,66 +519,88 @@
462
519
  // Produce a duplicate-free version of the array. If the array has already
463
520
  // been sorted, you have the option of using a faster algorithm.
464
521
  // Aliased as `unique`.
465
- _.uniq = _.unique = function(array, isSorted, iterator, context) {
466
- if (_.isFunction(isSorted)) {
467
- context = iterator;
468
- iterator = isSorted;
522
+ _.uniq = _.unique = function(array, isSorted, iteratee, context) {
523
+ if (!_.isBoolean(isSorted)) {
524
+ context = iteratee;
525
+ iteratee = isSorted;
469
526
  isSorted = false;
470
527
  }
471
- var initial = iterator ? _.map(array, iterator, context) : array;
472
- var results = [];
528
+ if (iteratee != null) iteratee = cb(iteratee, context);
529
+ var result = [];
473
530
  var seen = [];
474
- each(initial, function(value, index) {
475
- if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
476
- seen.push(value);
477
- results.push(array[index]);
531
+ for (var i = 0, length = getLength(array); i < length; i++) {
532
+ var value = array[i],
533
+ computed = iteratee ? iteratee(value, i, array) : value;
534
+ if (isSorted) {
535
+ if (!i || seen !== computed) result.push(value);
536
+ seen = computed;
537
+ } else if (iteratee) {
538
+ if (!_.contains(seen, computed)) {
539
+ seen.push(computed);
540
+ result.push(value);
541
+ }
542
+ } else if (!_.contains(result, value)) {
543
+ result.push(value);
478
544
  }
479
- });
480
- return results;
545
+ }
546
+ return result;
481
547
  };
482
548
 
483
549
  // Produce an array that contains the union: each distinct element from all of
484
550
  // the passed-in arrays.
485
551
  _.union = function() {
486
- return _.uniq(_.flatten(arguments, true));
552
+ return _.uniq(flatten(arguments, true, true));
487
553
  };
488
554
 
489
555
  // Produce an array that contains every item shared between all the
490
556
  // passed-in arrays.
491
557
  _.intersection = function(array) {
492
- var rest = slice.call(arguments, 1);
493
- return _.filter(_.uniq(array), function(item) {
494
- return _.every(rest, function(other) {
495
- return _.indexOf(other, item) >= 0;
496
- });
497
- });
558
+ var result = [];
559
+ var argsLength = arguments.length;
560
+ for (var i = 0, length = getLength(array); i < length; i++) {
561
+ var item = array[i];
562
+ if (_.contains(result, item)) continue;
563
+ for (var j = 1; j < argsLength; j++) {
564
+ if (!_.contains(arguments[j], item)) break;
565
+ }
566
+ if (j === argsLength) result.push(item);
567
+ }
568
+ return result;
498
569
  };
499
570
 
500
571
  // Take the difference between one array and a number of other arrays.
501
572
  // Only the elements present in just the first array will remain.
502
573
  _.difference = function(array) {
503
- var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
504
- return _.filter(array, function(value){ return !_.contains(rest, value); });
574
+ var rest = flatten(arguments, true, true, 1);
575
+ return _.filter(array, function(value){
576
+ return !_.contains(rest, value);
577
+ });
505
578
  };
506
579
 
507
580
  // Zip together multiple lists into a single array -- elements that share
508
581
  // an index go together.
509
582
  _.zip = function() {
510
- var length = _.max(_.pluck(arguments, "length").concat(0));
511
- var results = new Array(length);
512
- for (var i = 0; i < length; i++) {
513
- results[i] = _.pluck(arguments, '' + i);
583
+ return _.unzip(arguments);
584
+ };
585
+
586
+ // Complement of _.zip. Unzip accepts an array of arrays and groups
587
+ // each array's elements on shared indices
588
+ _.unzip = function(array) {
589
+ var length = array && _.max(array, getLength).length || 0;
590
+ var result = Array(length);
591
+
592
+ for (var index = 0; index < length; index++) {
593
+ result[index] = _.pluck(array, index);
514
594
  }
515
- return results;
595
+ return result;
516
596
  };
517
597
 
518
598
  // Converts lists into objects. Pass either a single array of `[key, value]`
519
599
  // pairs, or two parallel arrays of the same length -- one of keys, and one of
520
600
  // the corresponding values.
521
601
  _.object = function(list, values) {
522
- if (list == null) return {};
523
602
  var result = {};
524
- for (var i = 0, length = list.length; i < length; i++) {
603
+ for (var i = 0, length = getLength(list); i < length; i++) {
525
604
  if (values) {
526
605
  result[list[i]] = values[i];
527
606
  } else {
@@ -531,57 +610,83 @@
531
610
  return result;
532
611
  };
533
612
 
534
- // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
535
- // we need this function. Return the position of the first occurrence of an
536
- // item in an array, or -1 if the item is not included in the array.
537
- // Delegates to **ECMAScript 5**'s native `indexOf` if available.
538
- // If the array is large and already in sort order, pass `true`
539
- // for **isSorted** to use binary search.
540
- _.indexOf = function(array, item, isSorted) {
541
- if (array == null) return -1;
542
- var i = 0, length = array.length;
543
- if (isSorted) {
544
- if (typeof isSorted == 'number') {
545
- i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
546
- } else {
547
- i = _.sortedIndex(array, item);
548
- return array[i] === item ? i : -1;
613
+ // Generator function to create the findIndex and findLastIndex functions
614
+ function createPredicateIndexFinder(dir) {
615
+ return function(array, predicate, context) {
616
+ predicate = cb(predicate, context);
617
+ var length = getLength(array);
618
+ var index = dir > 0 ? 0 : length - 1;
619
+ for (; index >= 0 && index < length; index += dir) {
620
+ if (predicate(array[index], index, array)) return index;
549
621
  }
550
- }
551
- if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
552
- for (; i < length; i++) if (array[i] === item) return i;
553
- return -1;
554
- };
622
+ return -1;
623
+ };
624
+ }
555
625
 
556
- // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
557
- _.lastIndexOf = function(array, item, from) {
558
- if (array == null) return -1;
559
- var hasIndex = from != null;
560
- if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
561
- return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
626
+ // Returns the first index on an array-like that passes a predicate test
627
+ _.findIndex = createPredicateIndexFinder(1);
628
+ _.findLastIndex = createPredicateIndexFinder(-1);
629
+
630
+ // Use a comparator function to figure out the smallest index at which
631
+ // an object should be inserted so as to maintain order. Uses binary search.
632
+ _.sortedIndex = function(array, obj, iteratee, context) {
633
+ iteratee = cb(iteratee, context, 1);
634
+ var value = iteratee(obj);
635
+ var low = 0, high = getLength(array);
636
+ while (low < high) {
637
+ var mid = Math.floor((low + high) / 2);
638
+ if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
562
639
  }
563
- var i = (hasIndex ? from : array.length);
564
- while (i--) if (array[i] === item) return i;
565
- return -1;
640
+ return low;
566
641
  };
567
642
 
643
+ // Generator function to create the indexOf and lastIndexOf functions
644
+ function createIndexFinder(dir, predicateFind, sortedIndex) {
645
+ return function(array, item, idx) {
646
+ var i = 0, length = getLength(array);
647
+ if (typeof idx == 'number') {
648
+ if (dir > 0) {
649
+ i = idx >= 0 ? idx : Math.max(idx + length, i);
650
+ } else {
651
+ length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
652
+ }
653
+ } else if (sortedIndex && idx && length) {
654
+ idx = sortedIndex(array, item);
655
+ return array[idx] === item ? idx : -1;
656
+ }
657
+ if (item !== item) {
658
+ idx = predicateFind(slice.call(array, i, length), _.isNaN);
659
+ return idx >= 0 ? idx + i : -1;
660
+ }
661
+ for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
662
+ if (array[idx] === item) return idx;
663
+ }
664
+ return -1;
665
+ };
666
+ }
667
+
668
+ // Return the position of the first occurrence of an item in an array,
669
+ // or -1 if the item is not included in the array.
670
+ // If the array is large and already in sort order, pass `true`
671
+ // for **isSorted** to use binary search.
672
+ _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
673
+ _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
674
+
568
675
  // Generate an integer Array containing an arithmetic progression. A port of
569
676
  // the native Python `range()` function. See
570
677
  // [the Python documentation](http://docs.python.org/library/functions.html#range).
571
678
  _.range = function(start, stop, step) {
572
- if (arguments.length <= 1) {
679
+ if (stop == null) {
573
680
  stop = start || 0;
574
681
  start = 0;
575
682
  }
576
- step = arguments[2] || 1;
683
+ step = step || 1;
577
684
 
578
685
  var length = Math.max(Math.ceil((stop - start) / step), 0);
579
- var idx = 0;
580
- var range = new Array(length);
686
+ var range = Array(length);
581
687
 
582
- while(idx < length) {
583
- range[idx++] = start;
584
- start += step;
688
+ for (var idx = 0; idx < length; idx++, start += step) {
689
+ range[idx] = start;
585
690
  }
586
691
 
587
692
  return range;
@@ -590,68 +695,83 @@
590
695
  // Function (ahem) Functions
591
696
  // ------------------
592
697
 
593
- // Reusable constructor function for prototype setting.
594
- var ctor = function(){};
698
+ // Determines whether to execute a function as a constructor
699
+ // or a normal function with the provided arguments
700
+ var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
701
+ if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
702
+ var self = baseCreate(sourceFunc.prototype);
703
+ var result = sourceFunc.apply(self, args);
704
+ if (_.isObject(result)) return result;
705
+ return self;
706
+ };
595
707
 
596
708
  // Create a function bound to a given object (assigning `this`, and arguments,
597
709
  // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
598
710
  // available.
599
711
  _.bind = function(func, context) {
600
- var args, bound;
601
712
  if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
602
- if (!_.isFunction(func)) throw new TypeError;
603
- args = slice.call(arguments, 2);
604
- return bound = function() {
605
- if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
606
- ctor.prototype = func.prototype;
607
- var self = new ctor;
608
- ctor.prototype = null;
609
- var result = func.apply(self, args.concat(slice.call(arguments)));
610
- if (Object(result) === result) return result;
611
- return self;
713
+ if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
714
+ var args = slice.call(arguments, 2);
715
+ var bound = function() {
716
+ return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));
612
717
  };
718
+ return bound;
613
719
  };
614
720
 
615
721
  // Partially apply a function by creating a version that has had some of its
616
- // arguments pre-filled, without changing its dynamic `this` context.
722
+ // arguments pre-filled, without changing its dynamic `this` context. _ acts
723
+ // as a placeholder, allowing any combination of arguments to be pre-filled.
617
724
  _.partial = function(func) {
618
- var args = slice.call(arguments, 1);
619
- return function() {
620
- return func.apply(this, args.concat(slice.call(arguments)));
725
+ var boundArgs = slice.call(arguments, 1);
726
+ var bound = function() {
727
+ var position = 0, length = boundArgs.length;
728
+ var args = Array(length);
729
+ for (var i = 0; i < length; i++) {
730
+ args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i];
731
+ }
732
+ while (position < arguments.length) args.push(arguments[position++]);
733
+ return executeBound(func, bound, this, this, args);
621
734
  };
735
+ return bound;
622
736
  };
623
737
 
624
- // Bind all of an object's methods to that object. Useful for ensuring that
625
- // all callbacks defined on an object belong to it.
738
+ // Bind a number of an object's methods to that object. Remaining arguments
739
+ // are the method names to be bound. Useful for ensuring that all callbacks
740
+ // defined on an object belong to it.
626
741
  _.bindAll = function(obj) {
627
- var funcs = slice.call(arguments, 1);
628
- if (funcs.length === 0) throw new Error("bindAll must be passed function names");
629
- each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
742
+ var i, length = arguments.length, key;
743
+ if (length <= 1) throw new Error('bindAll must be passed function names');
744
+ for (i = 1; i < length; i++) {
745
+ key = arguments[i];
746
+ obj[key] = _.bind(obj[key], obj);
747
+ }
630
748
  return obj;
631
749
  };
632
750
 
633
751
  // Memoize an expensive function by storing its results.
634
752
  _.memoize = function(func, hasher) {
635
- var memo = {};
636
- hasher || (hasher = _.identity);
637
- return function() {
638
- var key = hasher.apply(this, arguments);
639
- return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
753
+ var memoize = function(key) {
754
+ var cache = memoize.cache;
755
+ var address = '' + (hasher ? hasher.apply(this, arguments) : key);
756
+ if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
757
+ return cache[address];
640
758
  };
759
+ memoize.cache = {};
760
+ return memoize;
641
761
  };
642
762
 
643
763
  // Delays a function for the given number of milliseconds, and then calls
644
764
  // it with the arguments supplied.
645
765
  _.delay = function(func, wait) {
646
766
  var args = slice.call(arguments, 2);
647
- return setTimeout(function(){ return func.apply(null, args); }, wait);
767
+ return setTimeout(function(){
768
+ return func.apply(null, args);
769
+ }, wait);
648
770
  };
649
771
 
650
772
  // Defers a function, scheduling it to run after the current call stack has
651
773
  // cleared.
652
- _.defer = function(func) {
653
- return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
654
- };
774
+ _.defer = _.partial(_.delay, _, 1);
655
775
 
656
776
  // Returns a function, that, when invoked, will only be triggered at most once
657
777
  // during a given window of time. Normally, the throttled function will run
@@ -662,23 +782,27 @@
662
782
  var context, args, result;
663
783
  var timeout = null;
664
784
  var previous = 0;
665
- options || (options = {});
785
+ if (!options) options = {};
666
786
  var later = function() {
667
- previous = options.leading === false ? 0 : new Date;
787
+ previous = options.leading === false ? 0 : _.now();
668
788
  timeout = null;
669
789
  result = func.apply(context, args);
790
+ if (!timeout) context = args = null;
670
791
  };
671
792
  return function() {
672
- var now = new Date;
793
+ var now = _.now();
673
794
  if (!previous && options.leading === false) previous = now;
674
795
  var remaining = wait - (now - previous);
675
796
  context = this;
676
797
  args = arguments;
677
- if (remaining <= 0) {
678
- clearTimeout(timeout);
679
- timeout = null;
798
+ if (remaining <= 0 || remaining > wait) {
799
+ if (timeout) {
800
+ clearTimeout(timeout);
801
+ timeout = null;
802
+ }
680
803
  previous = now;
681
804
  result = func.apply(context, args);
805
+ if (!timeout) context = args = null;
682
806
  } else if (!timeout && options.trailing !== false) {
683
807
  timeout = setTimeout(later, remaining);
684
808
  }
@@ -692,38 +816,33 @@
692
816
  // leading edge, instead of the trailing.
693
817
  _.debounce = function(func, wait, immediate) {
694
818
  var timeout, args, context, timestamp, result;
819
+
820
+ var later = function() {
821
+ var last = _.now() - timestamp;
822
+
823
+ if (last < wait && last >= 0) {
824
+ timeout = setTimeout(later, wait - last);
825
+ } else {
826
+ timeout = null;
827
+ if (!immediate) {
828
+ result = func.apply(context, args);
829
+ if (!timeout) context = args = null;
830
+ }
831
+ }
832
+ };
833
+
695
834
  return function() {
696
835
  context = this;
697
836
  args = arguments;
698
- timestamp = new Date();
699
- var later = function() {
700
- var last = (new Date()) - timestamp;
701
- if (last < wait) {
702
- timeout = setTimeout(later, wait - last);
703
- } else {
704
- timeout = null;
705
- if (!immediate) result = func.apply(context, args);
706
- }
707
- };
837
+ timestamp = _.now();
708
838
  var callNow = immediate && !timeout;
709
- if (!timeout) {
710
- timeout = setTimeout(later, wait);
839
+ if (!timeout) timeout = setTimeout(later, wait);
840
+ if (callNow) {
841
+ result = func.apply(context, args);
842
+ context = args = null;
711
843
  }
712
- if (callNow) result = func.apply(context, args);
713
- return result;
714
- };
715
- };
716
844
 
717
- // Returns a function that will be executed at most one time, no matter how
718
- // often you call it. Useful for lazy initialization.
719
- _.once = function(func) {
720
- var ran = false, memo;
721
- return function() {
722
- if (ran) return memo;
723
- ran = true;
724
- memo = func.apply(this, arguments);
725
- func = null;
726
- return memo;
845
+ return result;
727
846
  };
728
847
  };
729
848
 
@@ -731,27 +850,30 @@
731
850
  // allowing you to adjust arguments, run code before and after, and
732
851
  // conditionally execute the original function.
733
852
  _.wrap = function(func, wrapper) {
853
+ return _.partial(wrapper, func);
854
+ };
855
+
856
+ // Returns a negated version of the passed-in predicate.
857
+ _.negate = function(predicate) {
734
858
  return function() {
735
- var args = [func];
736
- push.apply(args, arguments);
737
- return wrapper.apply(this, args);
859
+ return !predicate.apply(this, arguments);
738
860
  };
739
861
  };
740
862
 
741
863
  // Returns a function that is the composition of a list of functions, each
742
864
  // consuming the return value of the function that follows.
743
865
  _.compose = function() {
744
- var funcs = arguments;
866
+ var args = arguments;
867
+ var start = args.length - 1;
745
868
  return function() {
746
- var args = arguments;
747
- for (var i = funcs.length - 1; i >= 0; i--) {
748
- args = [funcs[i].apply(this, args)];
749
- }
750
- return args[0];
869
+ var i = start;
870
+ var result = args[start].apply(this, arguments);
871
+ while (i--) result = args[i].call(this, result);
872
+ return result;
751
873
  };
752
874
  };
753
875
 
754
- // Returns a function that will only be executed after being called N times.
876
+ // Returns a function that will only be executed on and after the Nth call.
755
877
  _.after = function(times, func) {
756
878
  return function() {
757
879
  if (--times < 1) {
@@ -760,15 +882,66 @@
760
882
  };
761
883
  };
762
884
 
885
+ // Returns a function that will only be executed up to (but not including) the Nth call.
886
+ _.before = function(times, func) {
887
+ var memo;
888
+ return function() {
889
+ if (--times > 0) {
890
+ memo = func.apply(this, arguments);
891
+ }
892
+ if (times <= 1) func = null;
893
+ return memo;
894
+ };
895
+ };
896
+
897
+ // Returns a function that will be executed at most one time, no matter how
898
+ // often you call it. Useful for lazy initialization.
899
+ _.once = _.partial(_.before, 2);
900
+
763
901
  // Object Functions
764
902
  // ----------------
765
903
 
766
- // Retrieve the names of an object's properties.
904
+ // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
905
+ var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');
906
+ var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
907
+ 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
908
+
909
+ function collectNonEnumProps(obj, keys) {
910
+ var nonEnumIdx = nonEnumerableProps.length;
911
+ var constructor = obj.constructor;
912
+ var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto;
913
+
914
+ // Constructor is a special case.
915
+ var prop = 'constructor';
916
+ if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);
917
+
918
+ while (nonEnumIdx--) {
919
+ prop = nonEnumerableProps[nonEnumIdx];
920
+ if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
921
+ keys.push(prop);
922
+ }
923
+ }
924
+ }
925
+
926
+ // Retrieve the names of an object's own properties.
767
927
  // Delegates to **ECMAScript 5**'s native `Object.keys`
768
- _.keys = nativeKeys || function(obj) {
769
- if (obj !== Object(obj)) throw new TypeError('Invalid object');
928
+ _.keys = function(obj) {
929
+ if (!_.isObject(obj)) return [];
930
+ if (nativeKeys) return nativeKeys(obj);
770
931
  var keys = [];
771
932
  for (var key in obj) if (_.has(obj, key)) keys.push(key);
933
+ // Ahem, IE < 9.
934
+ if (hasEnumBug) collectNonEnumProps(obj, keys);
935
+ return keys;
936
+ };
937
+
938
+ // Retrieve all the property names of an object.
939
+ _.allKeys = function(obj) {
940
+ if (!_.isObject(obj)) return [];
941
+ var keys = [];
942
+ for (var key in obj) keys.push(key);
943
+ // Ahem, IE < 9.
944
+ if (hasEnumBug) collectNonEnumProps(obj, keys);
772
945
  return keys;
773
946
  };
774
947
 
@@ -776,18 +949,33 @@
776
949
  _.values = function(obj) {
777
950
  var keys = _.keys(obj);
778
951
  var length = keys.length;
779
- var values = new Array(length);
952
+ var values = Array(length);
780
953
  for (var i = 0; i < length; i++) {
781
954
  values[i] = obj[keys[i]];
782
955
  }
783
956
  return values;
784
957
  };
785
958
 
959
+ // Returns the results of applying the iteratee to each element of the object
960
+ // In contrast to _.map it returns an object
961
+ _.mapObject = function(obj, iteratee, context) {
962
+ iteratee = cb(iteratee, context);
963
+ var keys = _.keys(obj),
964
+ length = keys.length,
965
+ results = {},
966
+ currentKey;
967
+ for (var index = 0; index < length; index++) {
968
+ currentKey = keys[index];
969
+ results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
970
+ }
971
+ return results;
972
+ };
973
+
786
974
  // Convert an object into a list of `[key, value]` pairs.
787
975
  _.pairs = function(obj) {
788
976
  var keys = _.keys(obj);
789
977
  var length = keys.length;
790
- var pairs = new Array(length);
978
+ var pairs = Array(length);
791
979
  for (var i = 0; i < length; i++) {
792
980
  pairs[i] = [keys[i], obj[keys[i]]];
793
981
  }
@@ -815,47 +1003,65 @@
815
1003
  };
816
1004
 
817
1005
  // Extend a given object with all the properties in passed-in object(s).
818
- _.extend = function(obj) {
819
- each(slice.call(arguments, 1), function(source) {
820
- if (source) {
821
- for (var prop in source) {
822
- obj[prop] = source[prop];
823
- }
824
- }
825
- });
826
- return obj;
1006
+ _.extend = createAssigner(_.allKeys);
1007
+
1008
+ // Assigns a given object with all the own properties in the passed-in object(s)
1009
+ // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
1010
+ _.extendOwn = _.assign = createAssigner(_.keys);
1011
+
1012
+ // Returns the first key on an object that passes a predicate test
1013
+ _.findKey = function(obj, predicate, context) {
1014
+ predicate = cb(predicate, context);
1015
+ var keys = _.keys(obj), key;
1016
+ for (var i = 0, length = keys.length; i < length; i++) {
1017
+ key = keys[i];
1018
+ if (predicate(obj[key], key, obj)) return key;
1019
+ }
827
1020
  };
828
1021
 
829
1022
  // Return a copy of the object only containing the whitelisted properties.
830
- _.pick = function(obj) {
831
- var copy = {};
832
- var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
833
- each(keys, function(key) {
834
- if (key in obj) copy[key] = obj[key];
835
- });
836
- return copy;
1023
+ _.pick = function(object, oiteratee, context) {
1024
+ var result = {}, obj = object, iteratee, keys;
1025
+ if (obj == null) return result;
1026
+ if (_.isFunction(oiteratee)) {
1027
+ keys = _.allKeys(obj);
1028
+ iteratee = optimizeCb(oiteratee, context);
1029
+ } else {
1030
+ keys = flatten(arguments, false, false, 1);
1031
+ iteratee = function(value, key, obj) { return key in obj; };
1032
+ obj = Object(obj);
1033
+ }
1034
+ for (var i = 0, length = keys.length; i < length; i++) {
1035
+ var key = keys[i];
1036
+ var value = obj[key];
1037
+ if (iteratee(value, key, obj)) result[key] = value;
1038
+ }
1039
+ return result;
837
1040
  };
838
1041
 
839
1042
  // Return a copy of the object without the blacklisted properties.
840
- _.omit = function(obj) {
841
- var copy = {};
842
- var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
843
- for (var key in obj) {
844
- if (!_.contains(keys, key)) copy[key] = obj[key];
1043
+ _.omit = function(obj, iteratee, context) {
1044
+ if (_.isFunction(iteratee)) {
1045
+ iteratee = _.negate(iteratee);
1046
+ } else {
1047
+ var keys = _.map(flatten(arguments, false, false, 1), String);
1048
+ iteratee = function(value, key) {
1049
+ return !_.contains(keys, key);
1050
+ };
845
1051
  }
846
- return copy;
1052
+ return _.pick(obj, iteratee, context);
847
1053
  };
848
1054
 
849
1055
  // Fill in a given object with default properties.
850
- _.defaults = function(obj) {
851
- each(slice.call(arguments, 1), function(source) {
852
- if (source) {
853
- for (var prop in source) {
854
- if (obj[prop] === void 0) obj[prop] = source[prop];
855
- }
856
- }
857
- });
858
- return obj;
1056
+ _.defaults = createAssigner(_.allKeys, true);
1057
+
1058
+ // Creates an object that inherits from the given prototype object.
1059
+ // If additional properties are provided then they will be added to the
1060
+ // created object.
1061
+ _.create = function(prototype, props) {
1062
+ var result = baseCreate(prototype);
1063
+ if (props) _.extendOwn(result, props);
1064
+ return result;
859
1065
  };
860
1066
 
861
1067
  // Create a (shallow-cloned) duplicate of an object.
@@ -872,11 +1078,24 @@
872
1078
  return obj;
873
1079
  };
874
1080
 
1081
+ // Returns whether an object has a given set of `key:value` pairs.
1082
+ _.isMatch = function(object, attrs) {
1083
+ var keys = _.keys(attrs), length = keys.length;
1084
+ if (object == null) return !length;
1085
+ var obj = Object(object);
1086
+ for (var i = 0; i < length; i++) {
1087
+ var key = keys[i];
1088
+ if (attrs[key] !== obj[key] || !(key in obj)) return false;
1089
+ }
1090
+ return true;
1091
+ };
1092
+
1093
+
875
1094
  // Internal recursive comparison function for `isEqual`.
876
1095
  var eq = function(a, b, aStack, bStack) {
877
1096
  // Identical objects are equal. `0 === -0`, but they aren't identical.
878
1097
  // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
879
- if (a === b) return a !== 0 || 1 / a == 1 / b;
1098
+ if (a === b) return a !== 0 || 1 / a === 1 / b;
880
1099
  // A strict comparison is necessary because `null == undefined`.
881
1100
  if (a == null || b == null) return a === b;
882
1101
  // Unwrap any wrapped objects.
@@ -884,97 +1103,98 @@
884
1103
  if (b instanceof _) b = b._wrapped;
885
1104
  // Compare `[[Class]]` names.
886
1105
  var className = toString.call(a);
887
- if (className != toString.call(b)) return false;
1106
+ if (className !== toString.call(b)) return false;
888
1107
  switch (className) {
889
- // Strings, numbers, dates, and booleans are compared by value.
1108
+ // Strings, numbers, regular expressions, dates, and booleans are compared by value.
1109
+ case '[object RegExp]':
1110
+ // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
890
1111
  case '[object String]':
891
1112
  // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
892
1113
  // equivalent to `new String("5")`.
893
- return a == String(b);
1114
+ return '' + a === '' + b;
894
1115
  case '[object Number]':
895
- // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
896
- // other numeric values.
897
- return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
1116
+ // `NaN`s are equivalent, but non-reflexive.
1117
+ // Object(NaN) is equivalent to NaN
1118
+ if (+a !== +a) return +b !== +b;
1119
+ // An `egal` comparison is performed for other numeric values.
1120
+ return +a === 0 ? 1 / +a === 1 / b : +a === +b;
898
1121
  case '[object Date]':
899
1122
  case '[object Boolean]':
900
1123
  // Coerce dates and booleans to numeric primitive values. Dates are compared by their
901
1124
  // millisecond representations. Note that invalid dates with millisecond representations
902
1125
  // of `NaN` are not equivalent.
903
- return +a == +b;
904
- // RegExps are compared by their source patterns and flags.
905
- case '[object RegExp]':
906
- return a.source == b.source &&
907
- a.global == b.global &&
908
- a.multiline == b.multiline &&
909
- a.ignoreCase == b.ignoreCase;
1126
+ return +a === +b;
1127
+ }
1128
+
1129
+ var areArrays = className === '[object Array]';
1130
+ if (!areArrays) {
1131
+ if (typeof a != 'object' || typeof b != 'object') return false;
1132
+
1133
+ // Objects with different constructors are not equivalent, but `Object`s or `Array`s
1134
+ // from different frames are.
1135
+ var aCtor = a.constructor, bCtor = b.constructor;
1136
+ if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
1137
+ _.isFunction(bCtor) && bCtor instanceof bCtor)
1138
+ && ('constructor' in a && 'constructor' in b)) {
1139
+ return false;
1140
+ }
910
1141
  }
911
- if (typeof a != 'object' || typeof b != 'object') return false;
912
1142
  // Assume equality for cyclic structures. The algorithm for detecting cyclic
913
1143
  // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
1144
+
1145
+ // Initializing stack of traversed objects.
1146
+ // It's done here since we only need them for objects and arrays comparison.
1147
+ aStack = aStack || [];
1148
+ bStack = bStack || [];
914
1149
  var length = aStack.length;
915
1150
  while (length--) {
916
1151
  // Linear search. Performance is inversely proportional to the number of
917
1152
  // unique nested structures.
918
- if (aStack[length] == a) return bStack[length] == b;
919
- }
920
- // Objects with different constructors are not equivalent, but `Object`s
921
- // from different frames are.
922
- var aCtor = a.constructor, bCtor = b.constructor;
923
- if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
924
- _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
925
- return false;
1153
+ if (aStack[length] === a) return bStack[length] === b;
926
1154
  }
1155
+
927
1156
  // Add the first object to the stack of traversed objects.
928
1157
  aStack.push(a);
929
1158
  bStack.push(b);
930
- var size = 0, result = true;
1159
+
931
1160
  // Recursively compare objects and arrays.
932
- if (className == '[object Array]') {
1161
+ if (areArrays) {
933
1162
  // Compare array lengths to determine if a deep comparison is necessary.
934
- size = a.length;
935
- result = size == b.length;
936
- if (result) {
937
- // Deep compare the contents, ignoring non-numeric properties.
938
- while (size--) {
939
- if (!(result = eq(a[size], b[size], aStack, bStack))) break;
940
- }
1163
+ length = a.length;
1164
+ if (length !== b.length) return false;
1165
+ // Deep compare the contents, ignoring non-numeric properties.
1166
+ while (length--) {
1167
+ if (!eq(a[length], b[length], aStack, bStack)) return false;
941
1168
  }
942
1169
  } else {
943
1170
  // Deep compare objects.
944
- for (var key in a) {
945
- if (_.has(a, key)) {
946
- // Count the expected number of properties.
947
- size++;
948
- // Deep compare each member.
949
- if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
950
- }
951
- }
952
- // Ensure that both objects contain the same number of properties.
953
- if (result) {
954
- for (key in b) {
955
- if (_.has(b, key) && !(size--)) break;
956
- }
957
- result = !size;
1171
+ var keys = _.keys(a), key;
1172
+ length = keys.length;
1173
+ // Ensure that both objects contain the same number of properties before comparing deep equality.
1174
+ if (_.keys(b).length !== length) return false;
1175
+ while (length--) {
1176
+ // Deep compare each member
1177
+ key = keys[length];
1178
+ if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
958
1179
  }
959
1180
  }
960
1181
  // Remove the first object from the stack of traversed objects.
961
1182
  aStack.pop();
962
1183
  bStack.pop();
963
- return result;
1184
+ return true;
964
1185
  };
965
1186
 
966
1187
  // Perform a deep comparison to check if two objects are equal.
967
1188
  _.isEqual = function(a, b) {
968
- return eq(a, b, [], []);
1189
+ return eq(a, b);
969
1190
  };
970
1191
 
971
1192
  // Is a given array, string, or object empty?
972
1193
  // An "empty" object has no enumerable own-properties.
973
1194
  _.isEmpty = function(obj) {
974
1195
  if (obj == null) return true;
975
- if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
976
- for (var key in obj) if (_.has(obj, key)) return false;
977
- return true;
1196
+ if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
1197
+ return _.keys(obj).length === 0;
978
1198
  };
979
1199
 
980
1200
  // Is a given value a DOM element?
@@ -985,33 +1205,35 @@
985
1205
  // Is a given value an array?
986
1206
  // Delegates to ECMA5's native Array.isArray
987
1207
  _.isArray = nativeIsArray || function(obj) {
988
- return toString.call(obj) == '[object Array]';
1208
+ return toString.call(obj) === '[object Array]';
989
1209
  };
990
1210
 
991
1211
  // Is a given variable an object?
992
1212
  _.isObject = function(obj) {
993
- return obj === Object(obj);
1213
+ var type = typeof obj;
1214
+ return type === 'function' || type === 'object' && !!obj;
994
1215
  };
995
1216
 
996
- // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
997
- each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
1217
+ // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError.
1218
+ _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) {
998
1219
  _['is' + name] = function(obj) {
999
- return toString.call(obj) == '[object ' + name + ']';
1220
+ return toString.call(obj) === '[object ' + name + ']';
1000
1221
  };
1001
1222
  });
1002
1223
 
1003
- // Define a fallback version of the method in browsers (ahem, IE), where
1224
+ // Define a fallback version of the method in browsers (ahem, IE < 9), where
1004
1225
  // there isn't any inspectable "Arguments" type.
1005
1226
  if (!_.isArguments(arguments)) {
1006
1227
  _.isArguments = function(obj) {
1007
- return !!(obj && _.has(obj, 'callee'));
1228
+ return _.has(obj, 'callee');
1008
1229
  };
1009
1230
  }
1010
1231
 
1011
- // Optimize `isFunction` if appropriate.
1012
- if (typeof (/./) !== 'function') {
1232
+ // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,
1233
+ // IE 11 (#1621), and in Safari 8 (#1929).
1234
+ if (typeof /./ != 'function' && typeof Int8Array != 'object') {
1013
1235
  _.isFunction = function(obj) {
1014
- return typeof obj === 'function';
1236
+ return typeof obj == 'function' || false;
1015
1237
  };
1016
1238
  }
1017
1239
 
@@ -1022,12 +1244,12 @@
1022
1244
 
1023
1245
  // Is the given value `NaN`? (NaN is the only number which does not equal itself).
1024
1246
  _.isNaN = function(obj) {
1025
- return _.isNumber(obj) && obj != +obj;
1247
+ return _.isNumber(obj) && obj !== +obj;
1026
1248
  };
1027
1249
 
1028
1250
  // Is a given value a boolean?
1029
1251
  _.isBoolean = function(obj) {
1030
- return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
1252
+ return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
1031
1253
  };
1032
1254
 
1033
1255
  // Is a given value equal to null?
@@ -1043,7 +1265,7 @@
1043
1265
  // Shortcut function for checking if an object has a given property directly
1044
1266
  // on itself (in other words, not on a prototype).
1045
1267
  _.has = function(obj, key) {
1046
- return hasOwnProperty.call(obj, key);
1268
+ return obj != null && hasOwnProperty.call(obj, key);
1047
1269
  };
1048
1270
 
1049
1271
  // Utility Functions
@@ -1056,15 +1278,43 @@
1056
1278
  return this;
1057
1279
  };
1058
1280
 
1059
- // Keep the identity function around for default iterators.
1281
+ // Keep the identity function around for default iteratees.
1060
1282
  _.identity = function(value) {
1061
1283
  return value;
1062
1284
  };
1063
1285
 
1286
+ // Predicate-generating functions. Often useful outside of Underscore.
1287
+ _.constant = function(value) {
1288
+ return function() {
1289
+ return value;
1290
+ };
1291
+ };
1292
+
1293
+ _.noop = function(){};
1294
+
1295
+ _.property = property;
1296
+
1297
+ // Generates a function for a given object that returns a given property.
1298
+ _.propertyOf = function(obj) {
1299
+ return obj == null ? function(){} : function(key) {
1300
+ return obj[key];
1301
+ };
1302
+ };
1303
+
1304
+ // Returns a predicate for checking whether an object has a given set of
1305
+ // `key:value` pairs.
1306
+ _.matcher = _.matches = function(attrs) {
1307
+ attrs = _.extendOwn({}, attrs);
1308
+ return function(obj) {
1309
+ return _.isMatch(obj, attrs);
1310
+ };
1311
+ };
1312
+
1064
1313
  // Run a function **n** times.
1065
- _.times = function(n, iterator, context) {
1314
+ _.times = function(n, iteratee, context) {
1066
1315
  var accum = Array(Math.max(0, n));
1067
- for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
1316
+ iteratee = optimizeCb(iteratee, context, 1);
1317
+ for (var i = 0; i < n; i++) accum[i] = iteratee(i);
1068
1318
  return accum;
1069
1319
  };
1070
1320
 
@@ -1077,54 +1327,49 @@
1077
1327
  return min + Math.floor(Math.random() * (max - min + 1));
1078
1328
  };
1079
1329
 
1080
- // List of HTML entities for escaping.
1081
- var entityMap = {
1082
- escape: {
1083
- '&': '&amp;',
1084
- '<': '&lt;',
1085
- '>': '&gt;',
1086
- '"': '&quot;',
1087
- "'": '&#x27;'
1088
- }
1330
+ // A (possibly faster) way to get the current timestamp as an integer.
1331
+ _.now = Date.now || function() {
1332
+ return new Date().getTime();
1089
1333
  };
1090
- entityMap.unescape = _.invert(entityMap.escape);
1091
1334
 
1092
- // Regexes containing the keys and values listed immediately above.
1093
- var entityRegexes = {
1094
- escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
1095
- unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
1335
+ // List of HTML entities for escaping.
1336
+ var escapeMap = {
1337
+ '&': '&amp;',
1338
+ '<': '&lt;',
1339
+ '>': '&gt;',
1340
+ '"': '&quot;',
1341
+ "'": '&#x27;',
1342
+ '`': '&#x60;'
1096
1343
  };
1344
+ var unescapeMap = _.invert(escapeMap);
1097
1345
 
1098
1346
  // Functions for escaping and unescaping strings to/from HTML interpolation.
1099
- _.each(['escape', 'unescape'], function(method) {
1100
- _[method] = function(string) {
1101
- if (string == null) return '';
1102
- return ('' + string).replace(entityRegexes[method], function(match) {
1103
- return entityMap[method][match];
1104
- });
1347
+ var createEscaper = function(map) {
1348
+ var escaper = function(match) {
1349
+ return map[match];
1105
1350
  };
1106
- });
1351
+ // Regexes for identifying a key that needs to be escaped
1352
+ var source = '(?:' + _.keys(map).join('|') + ')';
1353
+ var testRegexp = RegExp(source);
1354
+ var replaceRegexp = RegExp(source, 'g');
1355
+ return function(string) {
1356
+ string = string == null ? '' : '' + string;
1357
+ return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
1358
+ };
1359
+ };
1360
+ _.escape = createEscaper(escapeMap);
1361
+ _.unescape = createEscaper(unescapeMap);
1107
1362
 
1108
1363
  // If the value of the named `property` is a function then invoke it with the
1109
1364
  // `object` as context; otherwise, return it.
1110
- _.result = function(object, property) {
1111
- if (object == null) return void 0;
1112
- var value = object[property];
1365
+ _.result = function(object, property, fallback) {
1366
+ var value = object == null ? void 0 : object[property];
1367
+ if (value === void 0) {
1368
+ value = fallback;
1369
+ }
1113
1370
  return _.isFunction(value) ? value.call(object) : value;
1114
1371
  };
1115
1372
 
1116
- // Add your own custom functions to the Underscore object.
1117
- _.mixin = function(obj) {
1118
- each(_.functions(obj), function(name) {
1119
- var func = _[name] = obj[name];
1120
- _.prototype[name] = function() {
1121
- var args = [this._wrapped];
1122
- push.apply(args, arguments);
1123
- return result.call(this, func.apply(_, args));
1124
- };
1125
- });
1126
- };
1127
-
1128
1373
  // Generate a unique integer id (unique within the entire client session).
1129
1374
  // Useful for temporary DOM ids.
1130
1375
  var idCounter = 0;
@@ -1153,22 +1398,26 @@
1153
1398
  '\\': '\\',
1154
1399
  '\r': 'r',
1155
1400
  '\n': 'n',
1156
- '\t': 't',
1157
1401
  '\u2028': 'u2028',
1158
1402
  '\u2029': 'u2029'
1159
1403
  };
1160
1404
 
1161
- var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
1405
+ var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
1406
+
1407
+ var escapeChar = function(match) {
1408
+ return '\\' + escapes[match];
1409
+ };
1162
1410
 
1163
1411
  // JavaScript micro-templating, similar to John Resig's implementation.
1164
1412
  // Underscore templating handles arbitrary delimiters, preserves whitespace,
1165
1413
  // and correctly escapes quotes within interpolated code.
1166
- _.template = function(text, data, settings) {
1167
- var render;
1414
+ // NB: `oldSettings` only exists for backwards compatibility.
1415
+ _.template = function(text, settings, oldSettings) {
1416
+ if (!settings && oldSettings) settings = oldSettings;
1168
1417
  settings = _.defaults({}, settings, _.templateSettings);
1169
1418
 
1170
1419
  // Combine delimiters into one regular expression via alternation.
1171
- var matcher = new RegExp([
1420
+ var matcher = RegExp([
1172
1421
  (settings.escape || noMatch).source,
1173
1422
  (settings.interpolate || noMatch).source,
1174
1423
  (settings.evaluate || noMatch).source
@@ -1178,19 +1427,18 @@
1178
1427
  var index = 0;
1179
1428
  var source = "__p+='";
1180
1429
  text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
1181
- source += text.slice(index, offset)
1182
- .replace(escaper, function(match) { return '\\' + escapes[match]; });
1430
+ source += text.slice(index, offset).replace(escaper, escapeChar);
1431
+ index = offset + match.length;
1183
1432
 
1184
1433
  if (escape) {
1185
1434
  source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
1186
- }
1187
- if (interpolate) {
1435
+ } else if (interpolate) {
1188
1436
  source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
1189
- }
1190
- if (evaluate) {
1437
+ } else if (evaluate) {
1191
1438
  source += "';\n" + evaluate + "\n__p+='";
1192
1439
  }
1193
- index = offset + match.length;
1440
+
1441
+ // Adobe VMs need the match returned to produce the correct offest.
1194
1442
  return match;
1195
1443
  });
1196
1444
  source += "';\n";
@@ -1200,29 +1448,31 @@
1200
1448
 
1201
1449
  source = "var __t,__p='',__j=Array.prototype.join," +
1202
1450
  "print=function(){__p+=__j.call(arguments,'');};\n" +
1203
- source + "return __p;\n";
1451
+ source + 'return __p;\n';
1204
1452
 
1205
1453
  try {
1206
- render = new Function(settings.variable || 'obj', '_', source);
1454
+ var render = new Function(settings.variable || 'obj', '_', source);
1207
1455
  } catch (e) {
1208
1456
  e.source = source;
1209
1457
  throw e;
1210
1458
  }
1211
1459
 
1212
- if (data) return render(data, _);
1213
1460
  var template = function(data) {
1214
1461
  return render.call(this, data, _);
1215
1462
  };
1216
1463
 
1217
- // Provide the compiled function source as a convenience for precompilation.
1218
- template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
1464
+ // Provide the compiled source as a convenience for precompilation.
1465
+ var argument = settings.variable || 'obj';
1466
+ template.source = 'function(' + argument + '){\n' + source + '}';
1219
1467
 
1220
1468
  return template;
1221
1469
  };
1222
1470
 
1223
- // Add a "chain" function, which will delegate to the wrapper.
1471
+ // Add a "chain" function. Start chaining a wrapped Underscore object.
1224
1472
  _.chain = function(obj) {
1225
- return _(obj).chain();
1473
+ var instance = _(obj);
1474
+ instance._chain = true;
1475
+ return instance;
1226
1476
  };
1227
1477
 
1228
1478
  // OOP
@@ -1232,45 +1482,67 @@
1232
1482
  // underscore functions. Wrapped objects may be chained.
1233
1483
 
1234
1484
  // Helper function to continue chaining intermediate results.
1235
- var result = function(obj) {
1236
- return this._chain ? _(obj).chain() : obj;
1485
+ var result = function(instance, obj) {
1486
+ return instance._chain ? _(obj).chain() : obj;
1487
+ };
1488
+
1489
+ // Add your own custom functions to the Underscore object.
1490
+ _.mixin = function(obj) {
1491
+ _.each(_.functions(obj), function(name) {
1492
+ var func = _[name] = obj[name];
1493
+ _.prototype[name] = function() {
1494
+ var args = [this._wrapped];
1495
+ push.apply(args, arguments);
1496
+ return result(this, func.apply(_, args));
1497
+ };
1498
+ });
1237
1499
  };
1238
1500
 
1239
1501
  // Add all of the Underscore functions to the wrapper object.
1240
1502
  _.mixin(_);
1241
1503
 
1242
1504
  // Add all mutator Array functions to the wrapper.
1243
- each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
1505
+ _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
1244
1506
  var method = ArrayProto[name];
1245
1507
  _.prototype[name] = function() {
1246
1508
  var obj = this._wrapped;
1247
1509
  method.apply(obj, arguments);
1248
- if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
1249
- return result.call(this, obj);
1510
+ if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
1511
+ return result(this, obj);
1250
1512
  };
1251
1513
  });
1252
1514
 
1253
1515
  // Add all accessor Array functions to the wrapper.
1254
- each(['concat', 'join', 'slice'], function(name) {
1516
+ _.each(['concat', 'join', 'slice'], function(name) {
1255
1517
  var method = ArrayProto[name];
1256
1518
  _.prototype[name] = function() {
1257
- return result.call(this, method.apply(this._wrapped, arguments));
1519
+ return result(this, method.apply(this._wrapped, arguments));
1258
1520
  };
1259
1521
  });
1260
1522
 
1261
- _.extend(_.prototype, {
1262
-
1263
- // Start chaining a wrapped Underscore object.
1264
- chain: function() {
1265
- this._chain = true;
1266
- return this;
1267
- },
1523
+ // Extracts the result from a wrapped and chained object.
1524
+ _.prototype.value = function() {
1525
+ return this._wrapped;
1526
+ };
1268
1527
 
1269
- // Extracts the result from a wrapped and chained object.
1270
- value: function() {
1271
- return this._wrapped;
1272
- }
1528
+ // Provide unwrapping proxy for some methods used in engine operations
1529
+ // such as arithmetic and JSON stringification.
1530
+ _.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
1273
1531
 
1274
- });
1532
+ _.prototype.toString = function() {
1533
+ return '' + this._wrapped;
1534
+ };
1275
1535
 
1276
- }).call(this);
1536
+ // AMD registration happens at the end for compatibility with AMD loaders
1537
+ // that may not enforce next-turn semantics on modules. Even though general
1538
+ // practice for AMD registration is to be anonymous, underscore registers
1539
+ // as a named module because, like jQuery, it is a base library that is
1540
+ // popular enough to be bundled in a third party lib, but not be part of
1541
+ // an AMD load request. Those cases could generate an error when an
1542
+ // anonymous define() is called outside of a loader request.
1543
+ if (typeof define === 'function' && define.amd) {
1544
+ define('underscore', [], function() {
1545
+ return _;
1546
+ });
1547
+ }
1548
+ }.call(this));