underscore-rails 1.6.0 → 1.7.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f08947a5b7d61a65c0dedc3e83c378102ac3ba38
4
- data.tar.gz: f8ecfea15083768f5ebb388aaefdfaf96931f58a
3
+ metadata.gz: 5576b859213b27f6b5e4d9dda4cf59e7be14d389
4
+ data.tar.gz: 773709d74cc092353d7ef8ba8ac1e292e3136cce
5
5
  SHA512:
6
- metadata.gz: 2fff345ea535304206346082950a729e918c567e2cddb917f38d4ea448f426a953c34d0df67528dce878313fa8bc0a1716e3eb3ca04a8aa6343671a16bbd78f6
7
- data.tar.gz: 23dd626e89ec0831a9a84b8fd7a4949816420a2e0c0cb978949f26efe7e0c611c72515ca599056b476f7a09f171bc10a49635858f5ac255dbcf1abc954c88c7e
6
+ metadata.gz: 19b35afc5770a487bcb3ee1ae373df73d76b4167c2178248681df3a07efb7a86c6ae0c6b36f1fadb951343254a36f3e208fb8165b8c41da224025ed1d93215b6
7
+ data.tar.gz: f0bb8b1354a3fabe86a0387098b512f123b1f66aecd2d583cdb15c0b94160777a7c5629fc5dc664b73e4c2f393295e29d914fdde69757fc1a66014f74d122c9a
@@ -1,5 +1,5 @@
1
1
  module Underscore
2
2
  module Rails
3
- VERSION = "1.6.0"
3
+ VERSION = "1.7.0"
4
4
  end
5
5
  end
@@ -1,4 +1,4 @@
1
- // Underscore.js 1.6.0
1
+ // Underscore.js 1.7.0
2
2
  // http://underscorejs.org
3
3
  // (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
4
4
  // Underscore may be freely distributed under the MIT license.
@@ -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
 
@@ -31,15 +28,6 @@
31
28
  // All **ECMAScript 5** native function implementations that we hope to use
32
29
  // are declared here.
33
30
  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
31
  nativeIsArray = Array.isArray,
44
32
  nativeKeys = Object.keys,
45
33
  nativeBind = FuncProto.bind;
@@ -53,8 +41,7 @@
53
41
 
54
42
  // Export the Underscore object for **Node.js**, with
55
43
  // 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.
44
+ // the browser, add `_` as a global object.
58
45
  if (typeof exports !== 'undefined') {
59
46
  if (typeof module !== 'undefined' && module.exports) {
60
47
  exports = module.exports = _;
@@ -65,98 +52,125 @@
65
52
  }
66
53
 
67
54
  // Current version.
68
- _.VERSION = '1.6.0';
55
+ _.VERSION = '1.7.0';
56
+
57
+ // Internal function that returns an efficient (for current engines) version
58
+ // of the passed-in callback, to be repeatedly applied in other Underscore
59
+ // functions.
60
+ var createCallback = function(func, context, argCount) {
61
+ if (context === void 0) return func;
62
+ switch (argCount == null ? 3 : argCount) {
63
+ case 1: return function(value) {
64
+ return func.call(context, value);
65
+ };
66
+ case 2: return function(value, other) {
67
+ return func.call(context, value, other);
68
+ };
69
+ case 3: return function(value, index, collection) {
70
+ return func.call(context, value, index, collection);
71
+ };
72
+ case 4: return function(accumulator, value, index, collection) {
73
+ return func.call(context, accumulator, value, index, collection);
74
+ };
75
+ }
76
+ return function() {
77
+ return func.apply(context, arguments);
78
+ };
79
+ };
80
+
81
+ // A mostly-internal function to generate callbacks that can be applied
82
+ // to each element in a collection, returning the desired result — either
83
+ // identity, an arbitrary callback, a property matcher, or a property accessor.
84
+ _.iteratee = function(value, context, argCount) {
85
+ if (value == null) return _.identity;
86
+ if (_.isFunction(value)) return createCallback(value, context, argCount);
87
+ if (_.isObject(value)) return _.matches(value);
88
+ return _.property(value);
89
+ };
69
90
 
70
91
  // Collection Functions
71
92
  // --------------------
72
93
 
73
94
  // 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) {
95
+ // Handles raw objects in addition to array-likes. Treats all
96
+ // sparse array-likes as if they were dense.
97
+ _.each = _.forEach = function(obj, iteratee, context) {
77
98
  if (obj == null) return obj;
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;
99
+ iteratee = createCallback(iteratee, context);
100
+ var i, length = obj.length;
101
+ if (length === +length) {
102
+ for (i = 0; i < length; i++) {
103
+ iteratee(obj[i], i, obj);
83
104
  }
84
105
  } else {
85
106
  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;
107
+ for (i = 0, length = keys.length; i < length; i++) {
108
+ iteratee(obj[keys[i]], keys[i], obj);
88
109
  }
89
110
  }
90
111
  return obj;
91
112
  };
92
113
 
93
- // Return the results of applying the iterator to each element.
94
- // Delegates to **ECMAScript 5**'s native `map` if available.
95
- _.map = _.collect = function(obj, iterator, context) {
96
- var results = [];
97
- if (obj == null) return results;
98
- if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
99
- each(obj, function(value, index, list) {
100
- results.push(iterator.call(context, value, index, list));
101
- });
114
+ // Return the results of applying the iteratee to each element.
115
+ _.map = _.collect = function(obj, iteratee, context) {
116
+ if (obj == null) return [];
117
+ iteratee = _.iteratee(iteratee, context);
118
+ var keys = obj.length !== +obj.length && _.keys(obj),
119
+ length = (keys || obj).length,
120
+ results = Array(length),
121
+ currentKey;
122
+ for (var index = 0; index < length; index++) {
123
+ currentKey = keys ? keys[index] : index;
124
+ results[index] = iteratee(obj[currentKey], currentKey, obj);
125
+ }
102
126
  return results;
103
127
  };
104
128
 
105
129
  var reduceError = 'Reduce of empty array with no initial value';
106
130
 
107
131
  // **Reduce** builds up a single result from a list of values, aka `inject`,
108
- // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
109
- _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
110
- var initial = arguments.length > 2;
132
+ // or `foldl`.
133
+ _.reduce = _.foldl = _.inject = function(obj, iteratee, memo, context) {
111
134
  if (obj == null) obj = [];
112
- if (nativeReduce && obj.reduce === nativeReduce) {
113
- if (context) iterator = _.bind(iterator, context);
114
- return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
135
+ iteratee = createCallback(iteratee, context, 4);
136
+ var keys = obj.length !== +obj.length && _.keys(obj),
137
+ length = (keys || obj).length,
138
+ index = 0, currentKey;
139
+ if (arguments.length < 3) {
140
+ if (!length) throw new TypeError(reduceError);
141
+ memo = obj[keys ? keys[index++] : index++];
142
+ }
143
+ for (; index < length; index++) {
144
+ currentKey = keys ? keys[index] : index;
145
+ memo = iteratee(memo, obj[currentKey], currentKey, obj);
115
146
  }
116
- each(obj, function(value, index, list) {
117
- if (!initial) {
118
- memo = value;
119
- initial = true;
120
- } else {
121
- memo = iterator.call(context, memo, value, index, list);
122
- }
123
- });
124
- if (!initial) throw new TypeError(reduceError);
125
147
  return memo;
126
148
  };
127
149
 
128
150
  // The right-associative version of reduce, also known as `foldr`.
129
- // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
130
- _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
131
- var initial = arguments.length > 2;
151
+ _.reduceRight = _.foldr = function(obj, iteratee, memo, context) {
132
152
  if (obj == null) obj = [];
133
- if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
134
- if (context) iterator = _.bind(iterator, context);
135
- return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
153
+ iteratee = createCallback(iteratee, context, 4);
154
+ var keys = obj.length !== + obj.length && _.keys(obj),
155
+ index = (keys || obj).length,
156
+ currentKey;
157
+ if (arguments.length < 3) {
158
+ if (!index) throw new TypeError(reduceError);
159
+ memo = obj[keys ? keys[--index] : --index];
136
160
  }
137
- var length = obj.length;
138
- if (length !== +length) {
139
- var keys = _.keys(obj);
140
- length = keys.length;
161
+ while (index--) {
162
+ currentKey = keys ? keys[index] : index;
163
+ memo = iteratee(memo, obj[currentKey], currentKey, obj);
141
164
  }
142
- each(obj, function(value, index, list) {
143
- index = keys ? keys[--length] : --length;
144
- if (!initial) {
145
- memo = obj[index];
146
- initial = true;
147
- } else {
148
- memo = iterator.call(context, memo, obj[index], index, list);
149
- }
150
- });
151
- if (!initial) throw new TypeError(reduceError);
152
165
  return memo;
153
166
  };
154
167
 
155
168
  // Return the first value which passes a truth test. Aliased as `detect`.
156
169
  _.find = _.detect = function(obj, predicate, context) {
157
170
  var result;
158
- any(obj, function(value, index, list) {
159
- if (predicate.call(context, value, index, list)) {
171
+ predicate = _.iteratee(predicate, context);
172
+ _.some(obj, function(value, index, list) {
173
+ if (predicate(value, index, list)) {
160
174
  result = value;
161
175
  return true;
162
176
  }
@@ -165,61 +179,58 @@
165
179
  };
166
180
 
167
181
  // Return all the elements that pass a truth test.
168
- // Delegates to **ECMAScript 5**'s native `filter` if available.
169
182
  // Aliased as `select`.
170
183
  _.filter = _.select = function(obj, predicate, context) {
171
184
  var results = [];
172
185
  if (obj == null) return results;
173
- if (nativeFilter && obj.filter === nativeFilter) return obj.filter(predicate, context);
174
- each(obj, function(value, index, list) {
175
- if (predicate.call(context, value, index, list)) results.push(value);
186
+ predicate = _.iteratee(predicate, context);
187
+ _.each(obj, function(value, index, list) {
188
+ if (predicate(value, index, list)) results.push(value);
176
189
  });
177
190
  return results;
178
191
  };
179
192
 
180
193
  // Return all the elements for which a truth test fails.
181
194
  _.reject = function(obj, predicate, context) {
182
- return _.filter(obj, function(value, index, list) {
183
- return !predicate.call(context, value, index, list);
184
- }, context);
195
+ return _.filter(obj, _.negate(_.iteratee(predicate)), context);
185
196
  };
186
197
 
187
198
  // Determine whether all of the elements match a truth test.
188
- // Delegates to **ECMAScript 5**'s native `every` if available.
189
199
  // Aliased as `all`.
190
200
  _.every = _.all = function(obj, predicate, context) {
191
- predicate || (predicate = _.identity);
192
- var result = true;
193
- if (obj == null) return result;
194
- if (nativeEvery && obj.every === nativeEvery) return obj.every(predicate, context);
195
- each(obj, function(value, index, list) {
196
- if (!(result = result && predicate.call(context, value, index, list))) return breaker;
197
- });
198
- return !!result;
201
+ if (obj == null) return true;
202
+ predicate = _.iteratee(predicate, context);
203
+ var keys = obj.length !== +obj.length && _.keys(obj),
204
+ length = (keys || obj).length,
205
+ index, currentKey;
206
+ for (index = 0; index < length; index++) {
207
+ currentKey = keys ? keys[index] : index;
208
+ if (!predicate(obj[currentKey], currentKey, obj)) return false;
209
+ }
210
+ return true;
199
211
  };
200
212
 
201
213
  // Determine if at least one element in the object matches a truth test.
202
- // Delegates to **ECMAScript 5**'s native `some` if available.
203
214
  // Aliased as `any`.
204
- var any = _.some = _.any = function(obj, predicate, context) {
205
- predicate || (predicate = _.identity);
206
- var result = false;
207
- if (obj == null) return result;
208
- if (nativeSome && obj.some === nativeSome) return obj.some(predicate, context);
209
- each(obj, function(value, index, list) {
210
- if (result || (result = predicate.call(context, value, index, list))) return breaker;
211
- });
212
- return !!result;
215
+ _.some = _.any = function(obj, predicate, context) {
216
+ if (obj == null) return false;
217
+ predicate = _.iteratee(predicate, context);
218
+ var keys = obj.length !== +obj.length && _.keys(obj),
219
+ length = (keys || obj).length,
220
+ index, currentKey;
221
+ for (index = 0; index < length; index++) {
222
+ currentKey = keys ? keys[index] : index;
223
+ if (predicate(obj[currentKey], currentKey, obj)) return true;
224
+ }
225
+ return false;
213
226
  };
214
227
 
215
228
  // Determine if the array or object contains a given value (using `===`).
216
229
  // Aliased as `include`.
217
230
  _.contains = _.include = function(obj, target) {
218
231
  if (obj == null) return false;
219
- if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
220
- return any(obj, function(value) {
221
- return value === target;
222
- });
232
+ if (obj.length !== +obj.length) obj = _.values(obj);
233
+ return _.indexOf(obj, target) >= 0;
223
234
  };
224
235
 
225
236
  // Invoke a method (with arguments) on every item in a collection.
@@ -248,51 +259,67 @@
248
259
  return _.find(obj, _.matches(attrs));
249
260
  };
250
261
 
251
- // Return the maximum element or (element-based computation).
252
- // Can't optimize arrays of integers longer than 65,535 elements.
253
- // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)
254
- _.max = function(obj, iterator, context) {
255
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
256
- return Math.max.apply(Math, obj);
257
- }
258
- var result = -Infinity, lastComputed = -Infinity;
259
- each(obj, function(value, index, list) {
260
- var computed = iterator ? iterator.call(context, value, index, list) : value;
261
- if (computed > lastComputed) {
262
- result = value;
263
- lastComputed = computed;
262
+ // Return the maximum element (or element-based computation).
263
+ _.max = function(obj, iteratee, context) {
264
+ var result = -Infinity, lastComputed = -Infinity,
265
+ value, computed;
266
+ if (iteratee == null && obj != null) {
267
+ obj = obj.length === +obj.length ? obj : _.values(obj);
268
+ for (var i = 0, length = obj.length; i < length; i++) {
269
+ value = obj[i];
270
+ if (value > result) {
271
+ result = value;
272
+ }
264
273
  }
265
- });
274
+ } else {
275
+ iteratee = _.iteratee(iteratee, context);
276
+ _.each(obj, function(value, index, list) {
277
+ computed = iteratee(value, index, list);
278
+ if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
279
+ result = value;
280
+ lastComputed = computed;
281
+ }
282
+ });
283
+ }
266
284
  return result;
267
285
  };
268
286
 
269
287
  // Return the minimum element (or element-based computation).
270
- _.min = function(obj, iterator, context) {
271
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
272
- return Math.min.apply(Math, obj);
273
- }
274
- var result = Infinity, lastComputed = Infinity;
275
- each(obj, function(value, index, list) {
276
- var computed = iterator ? iterator.call(context, value, index, list) : value;
277
- if (computed < lastComputed) {
278
- result = value;
279
- lastComputed = computed;
288
+ _.min = function(obj, iteratee, context) {
289
+ var result = Infinity, lastComputed = Infinity,
290
+ value, computed;
291
+ if (iteratee == null && obj != null) {
292
+ obj = obj.length === +obj.length ? obj : _.values(obj);
293
+ for (var i = 0, length = obj.length; i < length; i++) {
294
+ value = obj[i];
295
+ if (value < result) {
296
+ result = value;
297
+ }
280
298
  }
281
- });
299
+ } else {
300
+ iteratee = _.iteratee(iteratee, context);
301
+ _.each(obj, function(value, index, list) {
302
+ computed = iteratee(value, index, list);
303
+ if (computed < lastComputed || computed === Infinity && result === Infinity) {
304
+ result = value;
305
+ lastComputed = computed;
306
+ }
307
+ });
308
+ }
282
309
  return result;
283
310
  };
284
311
 
285
- // Shuffle an array, using the modern version of the
312
+ // Shuffle a collection, using the modern version of the
286
313
  // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
287
314
  _.shuffle = function(obj) {
288
- var rand;
289
- var index = 0;
290
- var shuffled = [];
291
- each(obj, function(value) {
292
- rand = _.random(index++);
293
- shuffled[index - 1] = shuffled[rand];
294
- shuffled[rand] = value;
295
- });
315
+ var set = obj && obj.length === +obj.length ? obj : _.values(obj);
316
+ var length = set.length;
317
+ var shuffled = Array(length);
318
+ for (var index = 0, rand; index < length; index++) {
319
+ rand = _.random(0, index);
320
+ if (rand !== index) shuffled[index] = shuffled[rand];
321
+ shuffled[rand] = set[index];
322
+ }
296
323
  return shuffled;
297
324
  };
298
325
 
@@ -307,21 +334,14 @@
307
334
  return _.shuffle(obj).slice(0, Math.max(0, n));
308
335
  };
309
336
 
310
- // An internal function to generate lookup iterators.
311
- var lookupIterator = function(value) {
312
- if (value == null) return _.identity;
313
- if (_.isFunction(value)) return value;
314
- return _.property(value);
315
- };
316
-
317
- // Sort the object's values by a criterion produced by an iterator.
318
- _.sortBy = function(obj, iterator, context) {
319
- iterator = lookupIterator(iterator);
337
+ // Sort the object's values by a criterion produced by an iteratee.
338
+ _.sortBy = function(obj, iteratee, context) {
339
+ iteratee = _.iteratee(iteratee, context);
320
340
  return _.pluck(_.map(obj, function(value, index, list) {
321
341
  return {
322
342
  value: value,
323
343
  index: index,
324
- criteria: iterator.call(context, value, index, list)
344
+ criteria: iteratee(value, index, list)
325
345
  };
326
346
  }).sort(function(left, right) {
327
347
  var a = left.criteria;
@@ -336,12 +356,12 @@
336
356
 
337
357
  // An internal function used for aggregate "group by" operations.
338
358
  var group = function(behavior) {
339
- return function(obj, iterator, context) {
359
+ return function(obj, iteratee, context) {
340
360
  var result = {};
341
- iterator = lookupIterator(iterator);
342
- each(obj, function(value, index) {
343
- var key = iterator.call(context, value, index, obj);
344
- behavior(result, key, value);
361
+ iteratee = _.iteratee(iteratee, context);
362
+ _.each(obj, function(value, index) {
363
+ var key = iteratee(value, index, obj);
364
+ behavior(result, value, key);
345
365
  });
346
366
  return result;
347
367
  };
@@ -349,32 +369,32 @@
349
369
 
350
370
  // Groups the object's values by a criterion. Pass either a string attribute
351
371
  // to group by, or a function that returns the criterion.
352
- _.groupBy = group(function(result, key, value) {
353
- _.has(result, key) ? result[key].push(value) : result[key] = [value];
372
+ _.groupBy = group(function(result, value, key) {
373
+ if (_.has(result, key)) result[key].push(value); else result[key] = [value];
354
374
  });
355
375
 
356
376
  // Indexes the object's values by a criterion, similar to `groupBy`, but for
357
377
  // when you know that your index values will be unique.
358
- _.indexBy = group(function(result, key, value) {
378
+ _.indexBy = group(function(result, value, key) {
359
379
  result[key] = value;
360
380
  });
361
381
 
362
382
  // Counts instances of an object that group by a certain criterion. Pass
363
383
  // either a string attribute to count by, or a function that returns the
364
384
  // criterion.
365
- _.countBy = group(function(result, key) {
366
- _.has(result, key) ? result[key]++ : result[key] = 1;
385
+ _.countBy = group(function(result, value, key) {
386
+ if (_.has(result, key)) result[key]++; else result[key] = 1;
367
387
  });
368
388
 
369
389
  // Use a comparator function to figure out the smallest index at which
370
390
  // an object should be inserted so as to maintain order. Uses binary search.
371
- _.sortedIndex = function(array, obj, iterator, context) {
372
- iterator = lookupIterator(iterator);
373
- var value = iterator.call(context, obj);
391
+ _.sortedIndex = function(array, obj, iteratee, context) {
392
+ iteratee = _.iteratee(iteratee, context, 1);
393
+ var value = iteratee(obj);
374
394
  var low = 0, high = array.length;
375
395
  while (low < high) {
376
- var mid = (low + high) >>> 1;
377
- iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
396
+ var mid = low + high >>> 1;
397
+ if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
378
398
  }
379
399
  return low;
380
400
  };
@@ -390,7 +410,18 @@
390
410
  // Return the number of elements in an object.
391
411
  _.size = function(obj) {
392
412
  if (obj == null) return 0;
393
- return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
413
+ return obj.length === +obj.length ? obj.length : _.keys(obj).length;
414
+ };
415
+
416
+ // Split a collection into two arrays: one whose elements all satisfy the given
417
+ // predicate, and one whose elements all do not satisfy the predicate.
418
+ _.partition = function(obj, predicate, context) {
419
+ predicate = _.iteratee(predicate, context);
420
+ var pass = [], fail = [];
421
+ _.each(obj, function(value, key, obj) {
422
+ (predicate(value, key, obj) ? pass : fail).push(value);
423
+ });
424
+ return [pass, fail];
394
425
  };
395
426
 
396
427
  // Array Functions
@@ -401,7 +432,7 @@
401
432
  // allows it to work with `_.map`.
402
433
  _.first = _.head = _.take = function(array, n, guard) {
403
434
  if (array == null) return void 0;
404
- if ((n == null) || guard) return array[0];
435
+ if (n == null || guard) return array[0];
405
436
  if (n < 0) return [];
406
437
  return slice.call(array, 0, n);
407
438
  };
@@ -411,14 +442,14 @@
411
442
  // the array, excluding the last N. The **guard** check allows it to work with
412
443
  // `_.map`.
413
444
  _.initial = function(array, n, guard) {
414
- return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
445
+ return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
415
446
  };
416
447
 
417
448
  // Get the last element of an array. Passing **n** will return the last N
418
449
  // values in the array. The **guard** check allows it to work with `_.map`.
419
450
  _.last = function(array, n, guard) {
420
451
  if (array == null) return void 0;
421
- if ((n == null) || guard) return array[array.length - 1];
452
+ if (n == null || guard) return array[array.length - 1];
422
453
  return slice.call(array, Math.max(array.length - n, 0));
423
454
  };
424
455
 
@@ -427,7 +458,7 @@
427
458
  // the rest N values in the array. The **guard**
428
459
  // check allows it to work with `_.map`.
429
460
  _.rest = _.tail = _.drop = function(array, n, guard) {
430
- return slice.call(array, (n == null) || guard ? 1 : n);
461
+ return slice.call(array, n == null || guard ? 1 : n);
431
462
  };
432
463
 
433
464
  // Trim out all falsy values from an array.
@@ -436,23 +467,26 @@
436
467
  };
437
468
 
438
469
  // Internal implementation of a recursive `flatten` function.
439
- var flatten = function(input, shallow, output) {
470
+ var flatten = function(input, shallow, strict, output) {
440
471
  if (shallow && _.every(input, _.isArray)) {
441
472
  return concat.apply(output, input);
442
473
  }
443
- each(input, function(value) {
444
- if (_.isArray(value) || _.isArguments(value)) {
445
- shallow ? push.apply(output, value) : flatten(value, shallow, output);
474
+ for (var i = 0, length = input.length; i < length; i++) {
475
+ var value = input[i];
476
+ if (!_.isArray(value) && !_.isArguments(value)) {
477
+ if (!strict) output.push(value);
478
+ } else if (shallow) {
479
+ push.apply(output, value);
446
480
  } else {
447
- output.push(value);
481
+ flatten(value, shallow, strict, output);
448
482
  }
449
- });
483
+ }
450
484
  return output;
451
485
  };
452
486
 
453
487
  // Flatten out an array, either recursively (by default), or just one level.
454
488
  _.flatten = function(array, shallow) {
455
- return flatten(array, shallow, []);
489
+ return flatten(array, shallow, false, []);
456
490
  };
457
491
 
458
492
  // Return a version of the array that does not contain the specified value(s).
@@ -460,68 +494,77 @@
460
494
  return _.difference(array, slice.call(arguments, 1));
461
495
  };
462
496
 
463
- // Split an array into two arrays: one whose elements all satisfy the given
464
- // predicate, and one whose elements all do not satisfy the predicate.
465
- _.partition = function(array, predicate) {
466
- var pass = [], fail = [];
467
- each(array, function(elem) {
468
- (predicate(elem) ? pass : fail).push(elem);
469
- });
470
- return [pass, fail];
471
- };
472
-
473
497
  // Produce a duplicate-free version of the array. If the array has already
474
498
  // been sorted, you have the option of using a faster algorithm.
475
499
  // Aliased as `unique`.
476
- _.uniq = _.unique = function(array, isSorted, iterator, context) {
477
- if (_.isFunction(isSorted)) {
478
- context = iterator;
479
- iterator = isSorted;
500
+ _.uniq = _.unique = function(array, isSorted, iteratee, context) {
501
+ if (array == null) return [];
502
+ if (!_.isBoolean(isSorted)) {
503
+ context = iteratee;
504
+ iteratee = isSorted;
480
505
  isSorted = false;
481
506
  }
482
- var initial = iterator ? _.map(array, iterator, context) : array;
483
- var results = [];
507
+ if (iteratee != null) iteratee = _.iteratee(iteratee, context);
508
+ var result = [];
484
509
  var seen = [];
485
- each(initial, function(value, index) {
486
- if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
487
- seen.push(value);
488
- results.push(array[index]);
510
+ for (var i = 0, length = array.length; i < length; i++) {
511
+ var value = array[i];
512
+ if (isSorted) {
513
+ if (!i || seen !== value) result.push(value);
514
+ seen = value;
515
+ } else if (iteratee) {
516
+ var computed = iteratee(value, i, array);
517
+ if (_.indexOf(seen, computed) < 0) {
518
+ seen.push(computed);
519
+ result.push(value);
520
+ }
521
+ } else if (_.indexOf(result, value) < 0) {
522
+ result.push(value);
489
523
  }
490
- });
491
- return results;
524
+ }
525
+ return result;
492
526
  };
493
527
 
494
528
  // Produce an array that contains the union: each distinct element from all of
495
529
  // the passed-in arrays.
496
530
  _.union = function() {
497
- return _.uniq(_.flatten(arguments, true));
531
+ return _.uniq(flatten(arguments, true, true, []));
498
532
  };
499
533
 
500
534
  // Produce an array that contains every item shared between all the
501
535
  // passed-in arrays.
502
536
  _.intersection = function(array) {
503
- var rest = slice.call(arguments, 1);
504
- return _.filter(_.uniq(array), function(item) {
505
- return _.every(rest, function(other) {
506
- return _.contains(other, item);
507
- });
508
- });
537
+ if (array == null) return [];
538
+ var result = [];
539
+ var argsLength = arguments.length;
540
+ for (var i = 0, length = array.length; i < length; i++) {
541
+ var item = array[i];
542
+ if (_.contains(result, item)) continue;
543
+ for (var j = 1; j < argsLength; j++) {
544
+ if (!_.contains(arguments[j], item)) break;
545
+ }
546
+ if (j === argsLength) result.push(item);
547
+ }
548
+ return result;
509
549
  };
510
550
 
511
551
  // Take the difference between one array and a number of other arrays.
512
552
  // Only the elements present in just the first array will remain.
513
553
  _.difference = function(array) {
514
- var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
515
- return _.filter(array, function(value){ return !_.contains(rest, value); });
554
+ var rest = flatten(slice.call(arguments, 1), true, true, []);
555
+ return _.filter(array, function(value){
556
+ return !_.contains(rest, value);
557
+ });
516
558
  };
517
559
 
518
560
  // Zip together multiple lists into a single array -- elements that share
519
561
  // an index go together.
520
- _.zip = function() {
521
- var length = _.max(_.pluck(arguments, 'length').concat(0));
522
- var results = new Array(length);
562
+ _.zip = function(array) {
563
+ if (array == null) return [];
564
+ var length = _.max(arguments, 'length').length;
565
+ var results = Array(length);
523
566
  for (var i = 0; i < length; i++) {
524
- results[i] = _.pluck(arguments, '' + i);
567
+ results[i] = _.pluck(arguments, i);
525
568
  }
526
569
  return results;
527
570
  };
@@ -542,10 +585,8 @@
542
585
  return result;
543
586
  };
544
587
 
545
- // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
546
- // we need this function. Return the position of the first occurrence of an
547
- // item in an array, or -1 if the item is not included in the array.
548
- // Delegates to **ECMAScript 5**'s native `indexOf` if available.
588
+ // Return the position of the first occurrence of an item in an array,
589
+ // or -1 if the item is not included in the array.
549
590
  // If the array is large and already in sort order, pass `true`
550
591
  // for **isSorted** to use binary search.
551
592
  _.indexOf = function(array, item, isSorted) {
@@ -553,26 +594,23 @@
553
594
  var i = 0, length = array.length;
554
595
  if (isSorted) {
555
596
  if (typeof isSorted == 'number') {
556
- i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
597
+ i = isSorted < 0 ? Math.max(0, length + isSorted) : isSorted;
557
598
  } else {
558
599
  i = _.sortedIndex(array, item);
559
600
  return array[i] === item ? i : -1;
560
601
  }
561
602
  }
562
- if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
563
603
  for (; i < length; i++) if (array[i] === item) return i;
564
604
  return -1;
565
605
  };
566
606
 
567
- // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
568
607
  _.lastIndexOf = function(array, item, from) {
569
608
  if (array == null) return -1;
570
- var hasIndex = from != null;
571
- if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
572
- return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
609
+ var idx = array.length;
610
+ if (typeof from == 'number') {
611
+ idx = from < 0 ? idx + from + 1 : Math.min(idx, from + 1);
573
612
  }
574
- var i = (hasIndex ? from : array.length);
575
- while (i--) if (array[i] === item) return i;
613
+ while (--idx >= 0) if (array[idx] === item) return idx;
576
614
  return -1;
577
615
  };
578
616
 
@@ -584,15 +622,13 @@
584
622
  stop = start || 0;
585
623
  start = 0;
586
624
  }
587
- step = arguments[2] || 1;
625
+ step = step || 1;
588
626
 
589
627
  var length = Math.max(Math.ceil((stop - start) / step), 0);
590
- var idx = 0;
591
- var range = new Array(length);
628
+ var range = Array(length);
592
629
 
593
- while(idx < length) {
594
- range[idx++] = start;
595
- start += step;
630
+ for (var idx = 0; idx < length; idx++, start += step) {
631
+ range[idx] = start;
596
632
  }
597
633
 
598
634
  return range;
@@ -602,7 +638,7 @@
602
638
  // ------------------
603
639
 
604
640
  // Reusable constructor function for prototype setting.
605
- var ctor = function(){};
641
+ var Ctor = function(){};
606
642
 
607
643
  // Create a function bound to a given object (assigning `this`, and arguments,
608
644
  // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
@@ -610,17 +646,18 @@
610
646
  _.bind = function(func, context) {
611
647
  var args, bound;
612
648
  if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
613
- if (!_.isFunction(func)) throw new TypeError;
649
+ if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
614
650
  args = slice.call(arguments, 2);
615
- return bound = function() {
651
+ bound = function() {
616
652
  if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
617
- ctor.prototype = func.prototype;
618
- var self = new ctor;
619
- ctor.prototype = null;
653
+ Ctor.prototype = func.prototype;
654
+ var self = new Ctor;
655
+ Ctor.prototype = null;
620
656
  var result = func.apply(self, args.concat(slice.call(arguments)));
621
- if (Object(result) === result) return result;
657
+ if (_.isObject(result)) return result;
622
658
  return self;
623
659
  };
660
+ return bound;
624
661
  };
625
662
 
626
663
  // Partially apply a function by creating a version that has had some of its
@@ -643,27 +680,34 @@
643
680
  // are the method names to be bound. Useful for ensuring that all callbacks
644
681
  // defined on an object belong to it.
645
682
  _.bindAll = function(obj) {
646
- var funcs = slice.call(arguments, 1);
647
- if (funcs.length === 0) throw new Error('bindAll must be passed function names');
648
- each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
683
+ var i, length = arguments.length, key;
684
+ if (length <= 1) throw new Error('bindAll must be passed function names');
685
+ for (i = 1; i < length; i++) {
686
+ key = arguments[i];
687
+ obj[key] = _.bind(obj[key], obj);
688
+ }
649
689
  return obj;
650
690
  };
651
691
 
652
692
  // Memoize an expensive function by storing its results.
653
693
  _.memoize = function(func, hasher) {
654
- var memo = {};
655
- hasher || (hasher = _.identity);
656
- return function() {
657
- var key = hasher.apply(this, arguments);
658
- return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
694
+ var memoize = function(key) {
695
+ var cache = memoize.cache;
696
+ var address = hasher ? hasher.apply(this, arguments) : key;
697
+ if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
698
+ return cache[address];
659
699
  };
700
+ memoize.cache = {};
701
+ return memoize;
660
702
  };
661
703
 
662
704
  // Delays a function for the given number of milliseconds, and then calls
663
705
  // it with the arguments supplied.
664
706
  _.delay = function(func, wait) {
665
707
  var args = slice.call(arguments, 2);
666
- return setTimeout(function(){ return func.apply(null, args); }, wait);
708
+ return setTimeout(function(){
709
+ return func.apply(null, args);
710
+ }, wait);
667
711
  };
668
712
 
669
713
  // Defers a function, scheduling it to run after the current call stack has
@@ -681,12 +725,12 @@
681
725
  var context, args, result;
682
726
  var timeout = null;
683
727
  var previous = 0;
684
- options || (options = {});
728
+ if (!options) options = {};
685
729
  var later = function() {
686
730
  previous = options.leading === false ? 0 : _.now();
687
731
  timeout = null;
688
732
  result = func.apply(context, args);
689
- context = args = null;
733
+ if (!timeout) context = args = null;
690
734
  };
691
735
  return function() {
692
736
  var now = _.now();
@@ -694,12 +738,12 @@
694
738
  var remaining = wait - (now - previous);
695
739
  context = this;
696
740
  args = arguments;
697
- if (remaining <= 0) {
741
+ if (remaining <= 0 || remaining > wait) {
698
742
  clearTimeout(timeout);
699
743
  timeout = null;
700
744
  previous = now;
701
745
  result = func.apply(context, args);
702
- context = args = null;
746
+ if (!timeout) context = args = null;
703
747
  } else if (!timeout && options.trailing !== false) {
704
748
  timeout = setTimeout(later, remaining);
705
749
  }
@@ -716,13 +760,14 @@
716
760
 
717
761
  var later = function() {
718
762
  var last = _.now() - timestamp;
719
- if (last < wait) {
763
+
764
+ if (last < wait && last > 0) {
720
765
  timeout = setTimeout(later, wait - last);
721
766
  } else {
722
767
  timeout = null;
723
768
  if (!immediate) {
724
769
  result = func.apply(context, args);
725
- context = args = null;
770
+ if (!timeout) context = args = null;
726
771
  }
727
772
  }
728
773
  };
@@ -732,9 +777,7 @@
732
777
  args = arguments;
733
778
  timestamp = _.now();
734
779
  var callNow = immediate && !timeout;
735
- if (!timeout) {
736
- timeout = setTimeout(later, wait);
737
- }
780
+ if (!timeout) timeout = setTimeout(later, wait);
738
781
  if (callNow) {
739
782
  result = func.apply(context, args);
740
783
  context = args = null;
@@ -744,19 +787,6 @@
744
787
  };
745
788
  };
746
789
 
747
- // Returns a function that will be executed at most one time, no matter how
748
- // often you call it. Useful for lazy initialization.
749
- _.once = function(func) {
750
- var ran = false, memo;
751
- return function() {
752
- if (ran) return memo;
753
- ran = true;
754
- memo = func.apply(this, arguments);
755
- func = null;
756
- return memo;
757
- };
758
- };
759
-
760
790
  // Returns the first function passed as an argument to the second,
761
791
  // allowing you to adjust arguments, run code before and after, and
762
792
  // conditionally execute the original function.
@@ -764,16 +794,23 @@
764
794
  return _.partial(wrapper, func);
765
795
  };
766
796
 
797
+ // Returns a negated version of the passed-in predicate.
798
+ _.negate = function(predicate) {
799
+ return function() {
800
+ return !predicate.apply(this, arguments);
801
+ };
802
+ };
803
+
767
804
  // Returns a function that is the composition of a list of functions, each
768
805
  // consuming the return value of the function that follows.
769
806
  _.compose = function() {
770
- var funcs = arguments;
807
+ var args = arguments;
808
+ var start = args.length - 1;
771
809
  return function() {
772
- var args = arguments;
773
- for (var i = funcs.length - 1; i >= 0; i--) {
774
- args = [funcs[i].apply(this, args)];
775
- }
776
- return args[0];
810
+ var i = start;
811
+ var result = args[start].apply(this, arguments);
812
+ while (i--) result = args[i].call(this, result);
813
+ return result;
777
814
  };
778
815
  };
779
816
 
@@ -786,6 +823,23 @@
786
823
  };
787
824
  };
788
825
 
826
+ // Returns a function that will only be executed before being called N times.
827
+ _.before = function(times, func) {
828
+ var memo;
829
+ return function() {
830
+ if (--times > 0) {
831
+ memo = func.apply(this, arguments);
832
+ } else {
833
+ func = null;
834
+ }
835
+ return memo;
836
+ };
837
+ };
838
+
839
+ // Returns a function that will be executed at most one time, no matter how
840
+ // often you call it. Useful for lazy initialization.
841
+ _.once = _.partial(_.before, 2);
842
+
789
843
  // Object Functions
790
844
  // ----------------
791
845
 
@@ -803,7 +857,7 @@
803
857
  _.values = function(obj) {
804
858
  var keys = _.keys(obj);
805
859
  var length = keys.length;
806
- var values = new Array(length);
860
+ var values = Array(length);
807
861
  for (var i = 0; i < length; i++) {
808
862
  values[i] = obj[keys[i]];
809
863
  }
@@ -814,7 +868,7 @@
814
868
  _.pairs = function(obj) {
815
869
  var keys = _.keys(obj);
816
870
  var length = keys.length;
817
- var pairs = new Array(length);
871
+ var pairs = Array(length);
818
872
  for (var i = 0; i < length; i++) {
819
873
  pairs[i] = [keys[i], obj[keys[i]]];
820
874
  }
@@ -843,45 +897,62 @@
843
897
 
844
898
  // Extend a given object with all the properties in passed-in object(s).
845
899
  _.extend = function(obj) {
846
- each(slice.call(arguments, 1), function(source) {
847
- if (source) {
848
- for (var prop in source) {
849
- obj[prop] = source[prop];
900
+ if (!_.isObject(obj)) return obj;
901
+ var source, prop;
902
+ for (var i = 1, length = arguments.length; i < length; i++) {
903
+ source = arguments[i];
904
+ for (prop in source) {
905
+ if (hasOwnProperty.call(source, prop)) {
906
+ obj[prop] = source[prop];
850
907
  }
851
908
  }
852
- });
909
+ }
853
910
  return obj;
854
911
  };
855
912
 
856
913
  // Return a copy of the object only containing the whitelisted properties.
857
- _.pick = function(obj) {
858
- var copy = {};
859
- var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
860
- each(keys, function(key) {
861
- if (key in obj) copy[key] = obj[key];
862
- });
863
- return copy;
914
+ _.pick = function(obj, iteratee, context) {
915
+ var result = {}, key;
916
+ if (obj == null) return result;
917
+ if (_.isFunction(iteratee)) {
918
+ iteratee = createCallback(iteratee, context);
919
+ for (key in obj) {
920
+ var value = obj[key];
921
+ if (iteratee(value, key, obj)) result[key] = value;
922
+ }
923
+ } else {
924
+ var keys = concat.apply([], slice.call(arguments, 1));
925
+ obj = new Object(obj);
926
+ for (var i = 0, length = keys.length; i < length; i++) {
927
+ key = keys[i];
928
+ if (key in obj) result[key] = obj[key];
929
+ }
930
+ }
931
+ return result;
864
932
  };
865
933
 
866
934
  // Return a copy of the object without the blacklisted properties.
867
- _.omit = function(obj) {
868
- var copy = {};
869
- var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
870
- for (var key in obj) {
871
- if (!_.contains(keys, key)) copy[key] = obj[key];
935
+ _.omit = function(obj, iteratee, context) {
936
+ if (_.isFunction(iteratee)) {
937
+ iteratee = _.negate(iteratee);
938
+ } else {
939
+ var keys = _.map(concat.apply([], slice.call(arguments, 1)), String);
940
+ iteratee = function(value, key) {
941
+ return !_.contains(keys, key);
942
+ };
872
943
  }
873
- return copy;
944
+ return _.pick(obj, iteratee, context);
874
945
  };
875
946
 
876
947
  // Fill in a given object with default properties.
877
948
  _.defaults = function(obj) {
878
- each(slice.call(arguments, 1), function(source) {
879
- if (source) {
880
- for (var prop in source) {
881
- if (obj[prop] === void 0) obj[prop] = source[prop];
882
- }
949
+ if (!_.isObject(obj)) return obj;
950
+ for (var i = 1, length = arguments.length; i < length; i++) {
951
+ var source = arguments[i];
952
+ for (var prop in source) {
953
+ if (obj[prop] === void 0) obj[prop] = source[prop];
883
954
  }
884
- });
955
+ }
885
956
  return obj;
886
957
  };
887
958
 
@@ -903,7 +974,7 @@
903
974
  var eq = function(a, b, aStack, bStack) {
904
975
  // Identical objects are equal. `0 === -0`, but they aren't identical.
905
976
  // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
906
- if (a === b) return a !== 0 || 1 / a == 1 / b;
977
+ if (a === b) return a !== 0 || 1 / a === 1 / b;
907
978
  // A strict comparison is necessary because `null == undefined`.
908
979
  if (a == null || b == null) return a === b;
909
980
  // Unwrap any wrapped objects.
@@ -911,29 +982,27 @@
911
982
  if (b instanceof _) b = b._wrapped;
912
983
  // Compare `[[Class]]` names.
913
984
  var className = toString.call(a);
914
- if (className != toString.call(b)) return false;
985
+ if (className !== toString.call(b)) return false;
915
986
  switch (className) {
916
- // Strings, numbers, dates, and booleans are compared by value.
987
+ // Strings, numbers, regular expressions, dates, and booleans are compared by value.
988
+ case '[object RegExp]':
989
+ // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
917
990
  case '[object String]':
918
991
  // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
919
992
  // equivalent to `new String("5")`.
920
- return a == String(b);
993
+ return '' + a === '' + b;
921
994
  case '[object Number]':
922
- // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
923
- // other numeric values.
924
- return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
995
+ // `NaN`s are equivalent, but non-reflexive.
996
+ // Object(NaN) is equivalent to NaN
997
+ if (+a !== +a) return +b !== +b;
998
+ // An `egal` comparison is performed for other numeric values.
999
+ return +a === 0 ? 1 / +a === 1 / b : +a === +b;
925
1000
  case '[object Date]':
926
1001
  case '[object Boolean]':
927
1002
  // Coerce dates and booleans to numeric primitive values. Dates are compared by their
928
1003
  // millisecond representations. Note that invalid dates with millisecond representations
929
1004
  // of `NaN` are not equivalent.
930
- return +a == +b;
931
- // RegExps are compared by their source patterns and flags.
932
- case '[object RegExp]':
933
- return a.source == b.source &&
934
- a.global == b.global &&
935
- a.multiline == b.multiline &&
936
- a.ignoreCase == b.ignoreCase;
1005
+ return +a === +b;
937
1006
  }
938
1007
  if (typeof a != 'object' || typeof b != 'object') return false;
939
1008
  // Assume equality for cyclic structures. The algorithm for detecting cyclic
@@ -942,25 +1011,29 @@
942
1011
  while (length--) {
943
1012
  // Linear search. Performance is inversely proportional to the number of
944
1013
  // unique nested structures.
945
- if (aStack[length] == a) return bStack[length] == b;
1014
+ if (aStack[length] === a) return bStack[length] === b;
946
1015
  }
947
1016
  // Objects with different constructors are not equivalent, but `Object`s
948
1017
  // from different frames are.
949
1018
  var aCtor = a.constructor, bCtor = b.constructor;
950
- if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
951
- _.isFunction(bCtor) && (bCtor instanceof bCtor))
952
- && ('constructor' in a && 'constructor' in b)) {
1019
+ if (
1020
+ aCtor !== bCtor &&
1021
+ // Handle Object.create(x) cases
1022
+ 'constructor' in a && 'constructor' in b &&
1023
+ !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
1024
+ _.isFunction(bCtor) && bCtor instanceof bCtor)
1025
+ ) {
953
1026
  return false;
954
1027
  }
955
1028
  // Add the first object to the stack of traversed objects.
956
1029
  aStack.push(a);
957
1030
  bStack.push(b);
958
- var size = 0, result = true;
1031
+ var size, result;
959
1032
  // Recursively compare objects and arrays.
960
- if (className == '[object Array]') {
1033
+ if (className === '[object Array]') {
961
1034
  // Compare array lengths to determine if a deep comparison is necessary.
962
1035
  size = a.length;
963
- result = size == b.length;
1036
+ result = size === b.length;
964
1037
  if (result) {
965
1038
  // Deep compare the contents, ignoring non-numeric properties.
966
1039
  while (size--) {
@@ -969,20 +1042,16 @@
969
1042
  }
970
1043
  } else {
971
1044
  // Deep compare objects.
972
- for (var key in a) {
973
- if (_.has(a, key)) {
974
- // Count the expected number of properties.
975
- size++;
976
- // Deep compare each member.
977
- if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
978
- }
979
- }
980
- // Ensure that both objects contain the same number of properties.
1045
+ var keys = _.keys(a), key;
1046
+ size = keys.length;
1047
+ // Ensure that both objects contain the same number of properties before comparing deep equality.
1048
+ result = _.keys(b).length === size;
981
1049
  if (result) {
982
- for (key in b) {
983
- if (_.has(b, key) && !(size--)) break;
1050
+ while (size--) {
1051
+ // Deep compare each member
1052
+ key = keys[size];
1053
+ if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
984
1054
  }
985
- result = !size;
986
1055
  }
987
1056
  }
988
1057
  // Remove the first object from the stack of traversed objects.
@@ -1000,7 +1069,7 @@
1000
1069
  // An "empty" object has no enumerable own-properties.
1001
1070
  _.isEmpty = function(obj) {
1002
1071
  if (obj == null) return true;
1003
- if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
1072
+ if (_.isArray(obj) || _.isString(obj) || _.isArguments(obj)) return obj.length === 0;
1004
1073
  for (var key in obj) if (_.has(obj, key)) return false;
1005
1074
  return true;
1006
1075
  };
@@ -1013,18 +1082,19 @@
1013
1082
  // Is a given value an array?
1014
1083
  // Delegates to ECMA5's native Array.isArray
1015
1084
  _.isArray = nativeIsArray || function(obj) {
1016
- return toString.call(obj) == '[object Array]';
1085
+ return toString.call(obj) === '[object Array]';
1017
1086
  };
1018
1087
 
1019
1088
  // Is a given variable an object?
1020
1089
  _.isObject = function(obj) {
1021
- return obj === Object(obj);
1090
+ var type = typeof obj;
1091
+ return type === 'function' || type === 'object' && !!obj;
1022
1092
  };
1023
1093
 
1024
1094
  // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
1025
- each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
1095
+ _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
1026
1096
  _['is' + name] = function(obj) {
1027
- return toString.call(obj) == '[object ' + name + ']';
1097
+ return toString.call(obj) === '[object ' + name + ']';
1028
1098
  };
1029
1099
  });
1030
1100
 
@@ -1032,14 +1102,14 @@
1032
1102
  // there isn't any inspectable "Arguments" type.
1033
1103
  if (!_.isArguments(arguments)) {
1034
1104
  _.isArguments = function(obj) {
1035
- return !!(obj && _.has(obj, 'callee'));
1105
+ return _.has(obj, 'callee');
1036
1106
  };
1037
1107
  }
1038
1108
 
1039
- // Optimize `isFunction` if appropriate.
1040
- if (typeof (/./) !== 'function') {
1109
+ // Optimize `isFunction` if appropriate. Work around an IE 11 bug.
1110
+ if (typeof /./ !== 'function') {
1041
1111
  _.isFunction = function(obj) {
1042
- return typeof obj === 'function';
1112
+ return typeof obj == 'function' || false;
1043
1113
  };
1044
1114
  }
1045
1115
 
@@ -1050,12 +1120,12 @@
1050
1120
 
1051
1121
  // Is the given value `NaN`? (NaN is the only number which does not equal itself).
1052
1122
  _.isNaN = function(obj) {
1053
- return _.isNumber(obj) && obj != +obj;
1123
+ return _.isNumber(obj) && obj !== +obj;
1054
1124
  };
1055
1125
 
1056
1126
  // Is a given value a boolean?
1057
1127
  _.isBoolean = function(obj) {
1058
- return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
1128
+ return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
1059
1129
  };
1060
1130
 
1061
1131
  // Is a given value equal to null?
@@ -1071,7 +1141,7 @@
1071
1141
  // Shortcut function for checking if an object has a given property directly
1072
1142
  // on itself (in other words, not on a prototype).
1073
1143
  _.has = function(obj, key) {
1074
- return hasOwnProperty.call(obj, key);
1144
+ return obj != null && hasOwnProperty.call(obj, key);
1075
1145
  };
1076
1146
 
1077
1147
  // Utility Functions
@@ -1084,17 +1154,20 @@
1084
1154
  return this;
1085
1155
  };
1086
1156
 
1087
- // Keep the identity function around for default iterators.
1157
+ // Keep the identity function around for default iteratees.
1088
1158
  _.identity = function(value) {
1089
1159
  return value;
1090
1160
  };
1091
1161
 
1162
+ // Predicate-generating functions. Often useful outside of Underscore.
1092
1163
  _.constant = function(value) {
1093
- return function () {
1164
+ return function() {
1094
1165
  return value;
1095
1166
  };
1096
1167
  };
1097
1168
 
1169
+ _.noop = function(){};
1170
+
1098
1171
  _.property = function(key) {
1099
1172
  return function(obj) {
1100
1173
  return obj[key];
@@ -1103,20 +1176,23 @@
1103
1176
 
1104
1177
  // Returns a predicate for checking whether an object has a given set of `key:value` pairs.
1105
1178
  _.matches = function(attrs) {
1179
+ var pairs = _.pairs(attrs), length = pairs.length;
1106
1180
  return function(obj) {
1107
- if (obj === attrs) return true; //avoid comparing an object to itself.
1108
- for (var key in attrs) {
1109
- if (attrs[key] !== obj[key])
1110
- return false;
1181
+ if (obj == null) return !length;
1182
+ obj = new Object(obj);
1183
+ for (var i = 0; i < length; i++) {
1184
+ var pair = pairs[i], key = pair[0];
1185
+ if (pair[1] !== obj[key] || !(key in obj)) return false;
1111
1186
  }
1112
1187
  return true;
1113
- }
1188
+ };
1114
1189
  };
1115
1190
 
1116
1191
  // Run a function **n** times.
1117
- _.times = function(n, iterator, context) {
1192
+ _.times = function(n, iteratee, context) {
1118
1193
  var accum = Array(Math.max(0, n));
1119
- for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
1194
+ iteratee = createCallback(iteratee, context, 1);
1195
+ for (var i = 0; i < n; i++) accum[i] = iteratee(i);
1120
1196
  return accum;
1121
1197
  };
1122
1198
 
@@ -1130,54 +1206,44 @@
1130
1206
  };
1131
1207
 
1132
1208
  // A (possibly faster) way to get the current timestamp as an integer.
1133
- _.now = Date.now || function() { return new Date().getTime(); };
1134
-
1135
- // List of HTML entities for escaping.
1136
- var entityMap = {
1137
- escape: {
1138
- '&': '&amp;',
1139
- '<': '&lt;',
1140
- '>': '&gt;',
1141
- '"': '&quot;',
1142
- "'": '&#x27;'
1143
- }
1209
+ _.now = Date.now || function() {
1210
+ return new Date().getTime();
1144
1211
  };
1145
- entityMap.unescape = _.invert(entityMap.escape);
1146
1212
 
1147
- // Regexes containing the keys and values listed immediately above.
1148
- var entityRegexes = {
1149
- escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
1150
- unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
1213
+ // List of HTML entities for escaping.
1214
+ var escapeMap = {
1215
+ '&': '&amp;',
1216
+ '<': '&lt;',
1217
+ '>': '&gt;',
1218
+ '"': '&quot;',
1219
+ "'": '&#x27;',
1220
+ '`': '&#x60;'
1151
1221
  };
1222
+ var unescapeMap = _.invert(escapeMap);
1152
1223
 
1153
1224
  // Functions for escaping and unescaping strings to/from HTML interpolation.
1154
- _.each(['escape', 'unescape'], function(method) {
1155
- _[method] = function(string) {
1156
- if (string == null) return '';
1157
- return ('' + string).replace(entityRegexes[method], function(match) {
1158
- return entityMap[method][match];
1159
- });
1225
+ var createEscaper = function(map) {
1226
+ var escaper = function(match) {
1227
+ return map[match];
1160
1228
  };
1161
- });
1229
+ // Regexes for identifying a key that needs to be escaped
1230
+ var source = '(?:' + _.keys(map).join('|') + ')';
1231
+ var testRegexp = RegExp(source);
1232
+ var replaceRegexp = RegExp(source, 'g');
1233
+ return function(string) {
1234
+ string = string == null ? '' : '' + string;
1235
+ return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
1236
+ };
1237
+ };
1238
+ _.escape = createEscaper(escapeMap);
1239
+ _.unescape = createEscaper(unescapeMap);
1162
1240
 
1163
1241
  // If the value of the named `property` is a function then invoke it with the
1164
1242
  // `object` as context; otherwise, return it.
1165
1243
  _.result = function(object, property) {
1166
1244
  if (object == null) return void 0;
1167
1245
  var value = object[property];
1168
- return _.isFunction(value) ? value.call(object) : value;
1169
- };
1170
-
1171
- // Add your own custom functions to the Underscore object.
1172
- _.mixin = function(obj) {
1173
- each(_.functions(obj), function(name) {
1174
- var func = _[name] = obj[name];
1175
- _.prototype[name] = function() {
1176
- var args = [this._wrapped];
1177
- push.apply(args, arguments);
1178
- return result.call(this, func.apply(_, args));
1179
- };
1180
- });
1246
+ return _.isFunction(value) ? object[property]() : value;
1181
1247
  };
1182
1248
 
1183
1249
  // Generate a unique integer id (unique within the entire client session).
@@ -1208,22 +1274,26 @@
1208
1274
  '\\': '\\',
1209
1275
  '\r': 'r',
1210
1276
  '\n': 'n',
1211
- '\t': 't',
1212
1277
  '\u2028': 'u2028',
1213
1278
  '\u2029': 'u2029'
1214
1279
  };
1215
1280
 
1216
- var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
1281
+ var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
1282
+
1283
+ var escapeChar = function(match) {
1284
+ return '\\' + escapes[match];
1285
+ };
1217
1286
 
1218
1287
  // JavaScript micro-templating, similar to John Resig's implementation.
1219
1288
  // Underscore templating handles arbitrary delimiters, preserves whitespace,
1220
1289
  // and correctly escapes quotes within interpolated code.
1221
- _.template = function(text, data, settings) {
1222
- var render;
1290
+ // NB: `oldSettings` only exists for backwards compatibility.
1291
+ _.template = function(text, settings, oldSettings) {
1292
+ if (!settings && oldSettings) settings = oldSettings;
1223
1293
  settings = _.defaults({}, settings, _.templateSettings);
1224
1294
 
1225
1295
  // Combine delimiters into one regular expression via alternation.
1226
- var matcher = new RegExp([
1296
+ var matcher = RegExp([
1227
1297
  (settings.escape || noMatch).source,
1228
1298
  (settings.interpolate || noMatch).source,
1229
1299
  (settings.evaluate || noMatch).source
@@ -1233,19 +1303,18 @@
1233
1303
  var index = 0;
1234
1304
  var source = "__p+='";
1235
1305
  text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
1236
- source += text.slice(index, offset)
1237
- .replace(escaper, function(match) { return '\\' + escapes[match]; });
1306
+ source += text.slice(index, offset).replace(escaper, escapeChar);
1307
+ index = offset + match.length;
1238
1308
 
1239
1309
  if (escape) {
1240
1310
  source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
1241
- }
1242
- if (interpolate) {
1311
+ } else if (interpolate) {
1243
1312
  source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
1244
- }
1245
- if (evaluate) {
1313
+ } else if (evaluate) {
1246
1314
  source += "';\n" + evaluate + "\n__p+='";
1247
1315
  }
1248
- index = offset + match.length;
1316
+
1317
+ // Adobe VMs need the match returned to produce the correct offest.
1249
1318
  return match;
1250
1319
  });
1251
1320
  source += "';\n";
@@ -1255,29 +1324,31 @@
1255
1324
 
1256
1325
  source = "var __t,__p='',__j=Array.prototype.join," +
1257
1326
  "print=function(){__p+=__j.call(arguments,'');};\n" +
1258
- source + "return __p;\n";
1327
+ source + 'return __p;\n';
1259
1328
 
1260
1329
  try {
1261
- render = new Function(settings.variable || 'obj', '_', source);
1330
+ var render = new Function(settings.variable || 'obj', '_', source);
1262
1331
  } catch (e) {
1263
1332
  e.source = source;
1264
1333
  throw e;
1265
1334
  }
1266
1335
 
1267
- if (data) return render(data, _);
1268
1336
  var template = function(data) {
1269
1337
  return render.call(this, data, _);
1270
1338
  };
1271
1339
 
1272
- // Provide the compiled function source as a convenience for precompilation.
1273
- template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
1340
+ // Provide the compiled source as a convenience for precompilation.
1341
+ var argument = settings.variable || 'obj';
1342
+ template.source = 'function(' + argument + '){\n' + source + '}';
1274
1343
 
1275
1344
  return template;
1276
1345
  };
1277
1346
 
1278
- // Add a "chain" function, which will delegate to the wrapper.
1347
+ // Add a "chain" function. Start chaining a wrapped Underscore object.
1279
1348
  _.chain = function(obj) {
1280
- return _(obj).chain();
1349
+ var instance = _(obj);
1350
+ instance._chain = true;
1351
+ return instance;
1281
1352
  };
1282
1353
 
1283
1354
  // OOP
@@ -1291,42 +1362,44 @@
1291
1362
  return this._chain ? _(obj).chain() : obj;
1292
1363
  };
1293
1364
 
1365
+ // Add your own custom functions to the Underscore object.
1366
+ _.mixin = function(obj) {
1367
+ _.each(_.functions(obj), function(name) {
1368
+ var func = _[name] = obj[name];
1369
+ _.prototype[name] = function() {
1370
+ var args = [this._wrapped];
1371
+ push.apply(args, arguments);
1372
+ return result.call(this, func.apply(_, args));
1373
+ };
1374
+ });
1375
+ };
1376
+
1294
1377
  // Add all of the Underscore functions to the wrapper object.
1295
1378
  _.mixin(_);
1296
1379
 
1297
1380
  // Add all mutator Array functions to the wrapper.
1298
- each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
1381
+ _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
1299
1382
  var method = ArrayProto[name];
1300
1383
  _.prototype[name] = function() {
1301
1384
  var obj = this._wrapped;
1302
1385
  method.apply(obj, arguments);
1303
- if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
1386
+ if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
1304
1387
  return result.call(this, obj);
1305
1388
  };
1306
1389
  });
1307
1390
 
1308
1391
  // Add all accessor Array functions to the wrapper.
1309
- each(['concat', 'join', 'slice'], function(name) {
1392
+ _.each(['concat', 'join', 'slice'], function(name) {
1310
1393
  var method = ArrayProto[name];
1311
1394
  _.prototype[name] = function() {
1312
1395
  return result.call(this, method.apply(this._wrapped, arguments));
1313
1396
  };
1314
1397
  });
1315
1398
 
1316
- _.extend(_.prototype, {
1317
-
1318
- // Start chaining a wrapped Underscore object.
1319
- chain: function() {
1320
- this._chain = true;
1321
- return this;
1322
- },
1323
-
1324
- // Extracts the result from a wrapped and chained object.
1325
- value: function() {
1326
- return this._wrapped;
1327
- }
1328
-
1329
- });
1399
+ // Extracts the result from a wrapped and chained object.
1400
+ _.prototype.value = function() {
1401
+ return this._wrapped;
1402
+ };
1330
1403
 
1331
1404
  // AMD registration happens at the end for compatibility with AMD loaders
1332
1405
  // that may not enforce next-turn semantics on modules. Even though general
@@ -1340,4 +1413,4 @@
1340
1413
  return _;
1341
1414
  });
1342
1415
  }
1343
- }).call(this);
1416
+ }.call(this));