backbone-rails 1.1.2 → 1.2.3

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