underscore-rails 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
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));