overlay_me 0.12.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
- // Underscore.js 1.1.6
2
- // (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.
1
+ // Underscore.js 1.3.3
2
+ // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
3
3
  // Underscore is freely distributable under the MIT license.
4
4
  // Portions of Underscore are inspired or borrowed from Prototype,
5
5
  // Oliver Steele's Functional, and John Resig's Micro-Templating.
@@ -48,36 +48,39 @@
48
48
  // Create a safe reference to the Underscore object for use below.
49
49
  var _ = function(obj) { return new wrapper(obj); };
50
50
 
51
- // Export the Underscore object for **CommonJS**, with backwards-compatibility
52
- // for the old `require()` API. If we're not in CommonJS, add `_` to the
53
- // global object.
54
- if (typeof module !== 'undefined' && module.exports) {
55
- module.exports = _;
56
- _._ = _;
51
+ // Export the Underscore object for **Node.js**, with
52
+ // backwards-compatibility for the old `require()` API. If we're in
53
+ // the browser, add `_` as a global object via a string identifier,
54
+ // for Closure Compiler "advanced" mode.
55
+ if (typeof exports !== 'undefined') {
56
+ if (typeof module !== 'undefined' && module.exports) {
57
+ exports = module.exports = _;
58
+ }
59
+ exports._ = _;
57
60
  } else {
58
- root._ = _;
61
+ root['_'] = _;
59
62
  }
60
63
 
61
64
  // Current version.
62
- _.VERSION = '1.1.6';
65
+ _.VERSION = '1.3.3';
63
66
 
64
67
  // Collection Functions
65
68
  // --------------------
66
69
 
67
70
  // The cornerstone, an `each` implementation, aka `forEach`.
68
- // Handles objects implementing `forEach`, arrays, and raw objects.
71
+ // Handles objects with the built-in `forEach`, arrays, and raw objects.
69
72
  // Delegates to **ECMAScript 5**'s native `forEach` if available.
70
73
  var each = _.each = _.forEach = function(obj, iterator, context) {
71
74
  if (obj == null) return;
72
75
  if (nativeForEach && obj.forEach === nativeForEach) {
73
76
  obj.forEach(iterator, context);
74
- } else if (_.isNumber(obj.length)) {
77
+ } else if (obj.length === +obj.length) {
75
78
  for (var i = 0, l = obj.length; i < l; i++) {
76
- if (iterator.call(context, obj[i], i, obj) === breaker) return;
79
+ if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
77
80
  }
78
81
  } else {
79
82
  for (var key in obj) {
80
- if (hasOwnProperty.call(obj, key)) {
83
+ if (_.has(obj, key)) {
81
84
  if (iterator.call(context, obj[key], key, obj) === breaker) return;
82
85
  }
83
86
  }
@@ -86,47 +89,50 @@
86
89
 
87
90
  // Return the results of applying the iterator to each element.
88
91
  // Delegates to **ECMAScript 5**'s native `map` if available.
89
- _.map = function(obj, iterator, context) {
92
+ _.map = _.collect = function(obj, iterator, context) {
90
93
  var results = [];
91
94
  if (obj == null) return results;
92
95
  if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
93
96
  each(obj, function(value, index, list) {
94
97
  results[results.length] = iterator.call(context, value, index, list);
95
98
  });
99
+ if (obj.length === +obj.length) results.length = obj.length;
96
100
  return results;
97
101
  };
98
102
 
99
103
  // **Reduce** builds up a single result from a list of values, aka `inject`,
100
104
  // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
101
105
  _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
102
- var initial = memo !== void 0;
106
+ var initial = arguments.length > 2;
103
107
  if (obj == null) obj = [];
104
108
  if (nativeReduce && obj.reduce === nativeReduce) {
105
109
  if (context) iterator = _.bind(iterator, context);
106
110
  return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
107
111
  }
108
112
  each(obj, function(value, index, list) {
109
- if (!initial && index === 0) {
113
+ if (!initial) {
110
114
  memo = value;
111
115
  initial = true;
112
116
  } else {
113
117
  memo = iterator.call(context, memo, value, index, list);
114
118
  }
115
119
  });
116
- if (!initial) throw new TypeError("Reduce of empty array with no initial value");
120
+ if (!initial) throw new TypeError('Reduce of empty array with no initial value');
117
121
  return memo;
118
122
  };
119
123
 
120
124
  // The right-associative version of reduce, also known as `foldr`.
121
125
  // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
122
126
  _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
127
+ var initial = arguments.length > 2;
123
128
  if (obj == null) obj = [];
124
129
  if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
125
130
  if (context) iterator = _.bind(iterator, context);
126
- return memo !== void 0 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
131
+ return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
127
132
  }
128
- var reversed = (_.isArray(obj) ? obj.slice() : _.toArray(obj)).reverse();
129
- return _.reduce(reversed, iterator, memo, context);
133
+ var reversed = _.toArray(obj).reverse();
134
+ if (context && !initial) iterator = _.bind(iterator, context);
135
+ return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator);
130
136
  };
131
137
 
132
138
  // Return the first value which passes a truth test. Aliased as `detect`.
@@ -174,7 +180,7 @@
174
180
  each(obj, function(value, index, list) {
175
181
  if (!(result = result && iterator.call(context, value, index, list))) return breaker;
176
182
  });
177
- return result;
183
+ return !!result;
178
184
  };
179
185
 
180
186
  // Determine if at least one element in the object matches a truth test.
@@ -186,9 +192,9 @@
186
192
  if (obj == null) return result;
187
193
  if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
188
194
  each(obj, function(value, index, list) {
189
- if (result = iterator.call(context, value, index, list)) return breaker;
195
+ if (result || (result = iterator.call(context, value, index, list))) return breaker;
190
196
  });
191
- return result;
197
+ return !!result;
192
198
  };
193
199
 
194
200
  // Determine if a given value is included in the array or object using `===`.
@@ -197,8 +203,8 @@
197
203
  var found = false;
198
204
  if (obj == null) return found;
199
205
  if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
200
- any(obj, function(value) {
201
- if (found = value === target) return true;
206
+ found = any(obj, function(value) {
207
+ return value === target;
202
208
  });
203
209
  return found;
204
210
  };
@@ -207,7 +213,7 @@
207
213
  _.invoke = function(obj, method) {
208
214
  var args = slice.call(arguments, 2);
209
215
  return _.map(obj, function(value) {
210
- return (method.call ? method || value : value[method]).apply(value, args);
216
+ return (_.isFunction(method) ? method || value : value[method]).apply(value, args);
211
217
  });
212
218
  };
213
219
 
@@ -218,7 +224,8 @@
218
224
 
219
225
  // Return the maximum element or (element-based computation).
220
226
  _.max = function(obj, iterator, context) {
221
- if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
227
+ if (!iterator && _.isArray(obj) && obj[0] === +obj[0]) return Math.max.apply(Math, obj);
228
+ if (!iterator && _.isEmpty(obj)) return -Infinity;
222
229
  var result = {computed : -Infinity};
223
230
  each(obj, function(value, index, list) {
224
231
  var computed = iterator ? iterator.call(context, value, index, list) : value;
@@ -229,7 +236,8 @@
229
236
 
230
237
  // Return the minimum element (or element-based computation).
231
238
  _.min = function(obj, iterator, context) {
232
- if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
239
+ if (!iterator && _.isArray(obj) && obj[0] === +obj[0]) return Math.min.apply(Math, obj);
240
+ if (!iterator && _.isEmpty(obj)) return Infinity;
233
241
  var result = {computed : Infinity};
234
242
  each(obj, function(value, index, list) {
235
243
  var computed = iterator ? iterator.call(context, value, index, list) : value;
@@ -238,8 +246,20 @@
238
246
  return result.value;
239
247
  };
240
248
 
249
+ // Shuffle an array.
250
+ _.shuffle = function(obj) {
251
+ var shuffled = [], rand;
252
+ each(obj, function(value, index, list) {
253
+ rand = Math.floor(Math.random() * (index + 1));
254
+ shuffled[index] = shuffled[rand];
255
+ shuffled[rand] = value;
256
+ });
257
+ return shuffled;
258
+ };
259
+
241
260
  // Sort the object's values by a criterion produced by an iterator.
242
- _.sortBy = function(obj, iterator, context) {
261
+ _.sortBy = function(obj, val, context) {
262
+ var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };
243
263
  return _.pluck(_.map(obj, function(value, index, list) {
244
264
  return {
245
265
  value : value,
@@ -247,10 +267,24 @@
247
267
  };
248
268
  }).sort(function(left, right) {
249
269
  var a = left.criteria, b = right.criteria;
270
+ if (a === void 0) return 1;
271
+ if (b === void 0) return -1;
250
272
  return a < b ? -1 : a > b ? 1 : 0;
251
273
  }), 'value');
252
274
  };
253
275
 
276
+ // Groups the object's values by a criterion. Pass either a string attribute
277
+ // to group by, or a function that returns the criterion.
278
+ _.groupBy = function(obj, val) {
279
+ var result = {};
280
+ var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };
281
+ each(obj, function(value, index) {
282
+ var key = iterator(value, index);
283
+ (result[key] || (result[key] = [])).push(value);
284
+ });
285
+ return result;
286
+ };
287
+
254
288
  // Use a comparator function to figure out at what index an object should
255
289
  // be inserted so as to maintain order. Uses binary search.
256
290
  _.sortedIndex = function(array, obj, iterator) {
@@ -264,29 +298,47 @@
264
298
  };
265
299
 
266
300
  // Safely convert anything iterable into a real, live array.
267
- _.toArray = function(iterable) {
268
- if (!iterable) return [];
269
- if (iterable.toArray) return iterable.toArray();
270
- if (_.isArray(iterable)) return iterable;
271
- if (_.isArguments(iterable)) return slice.call(iterable);
272
- return _.values(iterable);
301
+ _.toArray = function(obj) {
302
+ if (!obj) return [];
303
+ if (_.isArray(obj)) return slice.call(obj);
304
+ if (_.isArguments(obj)) return slice.call(obj);
305
+ if (obj.toArray && _.isFunction(obj.toArray)) return obj.toArray();
306
+ return _.values(obj);
273
307
  };
274
308
 
275
309
  // Return the number of elements in an object.
276
310
  _.size = function(obj) {
277
- return _.toArray(obj).length;
311
+ return _.isArray(obj) ? obj.length : _.keys(obj).length;
278
312
  };
279
313
 
280
314
  // Array Functions
281
315
  // ---------------
282
316
 
283
317
  // Get the first element of an array. Passing **n** will return the first N
284
- // values in the array. Aliased as `head`. The **guard** check allows it to work
285
- // with `_.map`.
286
- _.first = _.head = function(array, n, guard) {
318
+ // values in the array. Aliased as `head` and `take`. The **guard** check
319
+ // allows it to work with `_.map`.
320
+ _.first = _.head = _.take = function(array, n, guard) {
287
321
  return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
288
322
  };
289
323
 
324
+ // Returns everything but the last entry of the array. Especcialy useful on
325
+ // the arguments object. Passing **n** will return all the values in
326
+ // the array, excluding the last N. The **guard** check allows it to work with
327
+ // `_.map`.
328
+ _.initial = function(array, n, guard) {
329
+ return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
330
+ };
331
+
332
+ // Get the last element of an array. Passing **n** will return the last N
333
+ // values in the array. The **guard** check allows it to work with `_.map`.
334
+ _.last = function(array, n, guard) {
335
+ if ((n != null) && !guard) {
336
+ return slice.call(array, Math.max(array.length - n, 0));
337
+ } else {
338
+ return array[array.length - 1];
339
+ }
340
+ };
341
+
290
342
  // Returns everything but the first entry of the array. Aliased as `tail`.
291
343
  // Especially useful on the arguments object. Passing an **index** will return
292
344
  // the rest of the values in the array from that index onward. The **guard**
@@ -295,20 +347,15 @@
295
347
  return slice.call(array, (index == null) || guard ? 1 : index);
296
348
  };
297
349
 
298
- // Get the last element of an array.
299
- _.last = function(array) {
300
- return array[array.length - 1];
301
- };
302
-
303
350
  // Trim out all falsy values from an array.
304
351
  _.compact = function(array) {
305
352
  return _.filter(array, function(value){ return !!value; });
306
353
  };
307
354
 
308
355
  // Return a completely flattened version of an array.
309
- _.flatten = function(array) {
356
+ _.flatten = function(array, shallow) {
310
357
  return _.reduce(array, function(memo, value) {
311
- if (_.isArray(value)) return memo.concat(_.flatten(value));
358
+ if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value));
312
359
  memo[memo.length] = value;
313
360
  return memo;
314
361
  }, []);
@@ -316,23 +363,36 @@
316
363
 
317
364
  // Return a version of the array that does not contain the specified value(s).
318
365
  _.without = function(array) {
319
- var values = slice.call(arguments, 1);
320
- return _.filter(array, function(value){ return !_.include(values, value); });
366
+ return _.difference(array, slice.call(arguments, 1));
321
367
  };
322
368
 
323
369
  // Produce a duplicate-free version of the array. If the array has already
324
370
  // been sorted, you have the option of using a faster algorithm.
325
371
  // Aliased as `unique`.
326
- _.uniq = _.unique = function(array, isSorted) {
327
- return _.reduce(array, function(memo, el, i) {
328
- if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo[memo.length] = el;
372
+ _.uniq = _.unique = function(array, isSorted, iterator) {
373
+ var initial = iterator ? _.map(array, iterator) : array;
374
+ var results = [];
375
+ // The `isSorted` flag is irrelevant if the array only contains two elements.
376
+ if (array.length < 3) isSorted = true;
377
+ _.reduce(initial, function (memo, value, index) {
378
+ if (isSorted ? _.last(memo) !== value || !memo.length : !_.include(memo, value)) {
379
+ memo.push(value);
380
+ results.push(array[index]);
381
+ }
329
382
  return memo;
330
383
  }, []);
384
+ return results;
385
+ };
386
+
387
+ // Produce an array that contains the union: each distinct element from all of
388
+ // the passed-in arrays.
389
+ _.union = function() {
390
+ return _.uniq(_.flatten(arguments, true));
331
391
  };
332
392
 
333
393
  // Produce an array that contains every item shared between all the
334
- // passed-in arrays.
335
- _.intersect = function(array) {
394
+ // passed-in arrays. (Aliased as "intersect" for back-compat.)
395
+ _.intersection = _.intersect = function(array) {
336
396
  var rest = slice.call(arguments, 1);
337
397
  return _.filter(_.uniq(array), function(item) {
338
398
  return _.every(rest, function(other) {
@@ -341,6 +401,13 @@
341
401
  });
342
402
  };
343
403
 
404
+ // Take the difference between one array and a number of other arrays.
405
+ // Only the elements present in just the first array will remain.
406
+ _.difference = function(array) {
407
+ var rest = _.flatten(slice.call(arguments, 1), true);
408
+ return _.filter(array, function(value){ return !_.include(rest, value); });
409
+ };
410
+
344
411
  // Zip together multiple lists into a single array -- elements that share
345
412
  // an index go together.
346
413
  _.zip = function() {
@@ -365,17 +432,16 @@
365
432
  return array[i] === item ? i : -1;
366
433
  }
367
434
  if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
368
- for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
435
+ for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i;
369
436
  return -1;
370
437
  };
371
438
 
372
-
373
439
  // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
374
440
  _.lastIndexOf = function(array, item) {
375
441
  if (array == null) return -1;
376
442
  if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
377
443
  var i = array.length;
378
- while (i--) if (array[i] === item) return i;
444
+ while (i--) if (i in array && array[i] === item) return i;
379
445
  return -1;
380
446
  };
381
447
 
@@ -404,15 +470,25 @@
404
470
  // Function (ahem) Functions
405
471
  // ------------------
406
472
 
473
+ // Reusable constructor function for prototype setting.
474
+ var ctor = function(){};
475
+
407
476
  // Create a function bound to a given object (assigning `this`, and arguments,
408
477
  // optionally). Binding with arguments is also known as `curry`.
409
478
  // Delegates to **ECMAScript 5**'s native `Function.bind` if available.
410
479
  // We check for `func.bind` first, to fail fast when `func` is undefined.
411
- _.bind = function(func, obj) {
480
+ _.bind = function bind(func, context) {
481
+ var bound, args;
412
482
  if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
413
- var args = slice.call(arguments, 2);
414
- return function() {
415
- return func.apply(obj, args.concat(slice.call(arguments)));
483
+ if (!_.isFunction(func)) throw new TypeError;
484
+ args = slice.call(arguments, 2);
485
+ return bound = function() {
486
+ if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
487
+ ctor.prototype = func.prototype;
488
+ var self = new ctor;
489
+ var result = func.apply(self, args.concat(slice.call(arguments)));
490
+ if (Object(result) === result) return result;
491
+ return self;
416
492
  };
417
493
  };
418
494
 
@@ -431,7 +507,7 @@
431
507
  hasher || (hasher = _.identity);
432
508
  return function() {
433
509
  var key = hasher.apply(this, arguments);
434
- return hasOwnProperty.call(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
510
+ return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
435
511
  };
436
512
  };
437
513
 
@@ -439,7 +515,7 @@
439
515
  // it with the arguments supplied.
440
516
  _.delay = function(func, wait) {
441
517
  var args = slice.call(arguments, 2);
442
- return setTimeout(function(){ return func.apply(func, args); }, wait);
518
+ return setTimeout(function(){ return func.apply(null, args); }, wait);
443
519
  };
444
520
 
445
521
  // Defers a function, scheduling it to run after the current call stack has
@@ -448,31 +524,46 @@
448
524
  return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
449
525
  };
450
526
 
451
- // Internal function used to implement `_.throttle` and `_.debounce`.
452
- var limit = function(func, wait, debounce) {
453
- var timeout;
527
+ // Returns a function, that, when invoked, will only be triggered at most once
528
+ // during a given window of time.
529
+ _.throttle = function(func, wait) {
530
+ var context, args, timeout, throttling, more, result;
531
+ var whenDone = _.debounce(function(){ more = throttling = false; }, wait);
454
532
  return function() {
455
- var context = this, args = arguments;
456
- var throttler = function() {
533
+ context = this; args = arguments;
534
+ var later = function() {
457
535
  timeout = null;
458
- func.apply(context, args);
536
+ if (more) func.apply(context, args);
537
+ whenDone();
459
538
  };
460
- if (debounce) clearTimeout(timeout);
461
- if (debounce || !timeout) timeout = setTimeout(throttler, wait);
539
+ if (!timeout) timeout = setTimeout(later, wait);
540
+ if (throttling) {
541
+ more = true;
542
+ } else {
543
+ result = func.apply(context, args);
544
+ }
545
+ whenDone();
546
+ throttling = true;
547
+ return result;
462
548
  };
463
549
  };
464
550
 
465
- // Returns a function, that, when invoked, will only be triggered at most once
466
- // during a given window of time.
467
- _.throttle = function(func, wait) {
468
- return limit(func, wait, false);
469
- };
470
-
471
551
  // Returns a function, that, as long as it continues to be invoked, will not
472
552
  // be triggered. The function will be called after it stops being called for
473
- // N milliseconds.
474
- _.debounce = function(func, wait) {
475
- return limit(func, wait, true);
553
+ // N milliseconds. If `immediate` is passed, trigger the function on the
554
+ // leading edge, instead of the trailing.
555
+ _.debounce = function(func, wait, immediate) {
556
+ var timeout;
557
+ return function() {
558
+ var context = this, args = arguments;
559
+ var later = function() {
560
+ timeout = null;
561
+ if (!immediate) func.apply(context, args);
562
+ };
563
+ if (immediate && !timeout) func.apply(context, args);
564
+ clearTimeout(timeout);
565
+ timeout = setTimeout(later, wait);
566
+ };
476
567
  };
477
568
 
478
569
  // Returns a function that will be executed at most one time, no matter how
@@ -491,7 +582,7 @@
491
582
  // conditionally execute the original function.
492
583
  _.wrap = function(func, wrapper) {
493
584
  return function() {
494
- var args = [func].concat(slice.call(arguments));
585
+ var args = [func].concat(slice.call(arguments, 0));
495
586
  return wrapper.apply(this, args);
496
587
  };
497
588
  };
@@ -499,10 +590,10 @@
499
590
  // Returns a function that is the composition of a list of functions, each
500
591
  // consuming the return value of the function that follows.
501
592
  _.compose = function() {
502
- var funcs = slice.call(arguments);
593
+ var funcs = arguments;
503
594
  return function() {
504
- var args = slice.call(arguments);
505
- for (var i=funcs.length-1; i >= 0; i--) {
595
+ var args = arguments;
596
+ for (var i = funcs.length - 1; i >= 0; i--) {
506
597
  args = [funcs[i].apply(this, args)];
507
598
  }
508
599
  return args[0];
@@ -511,12 +602,12 @@
511
602
 
512
603
  // Returns a function that will only be executed after being called N times.
513
604
  _.after = function(times, func) {
605
+ if (times <= 0) return func();
514
606
  return function() {
515
607
  if (--times < 1) { return func.apply(this, arguments); }
516
608
  };
517
609
  };
518
610
 
519
-
520
611
  // Object Functions
521
612
  // ----------------
522
613
 
@@ -525,7 +616,7 @@
525
616
  _.keys = nativeKeys || function(obj) {
526
617
  if (obj !== Object(obj)) throw new TypeError('Invalid object');
527
618
  var keys = [];
528
- for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key;
619
+ for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;
529
620
  return keys;
530
621
  };
531
622
 
@@ -537,19 +628,32 @@
537
628
  // Return a sorted list of the function names available on the object.
538
629
  // Aliased as `methods`
539
630
  _.functions = _.methods = function(obj) {
540
- return _.filter(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort();
631
+ var names = [];
632
+ for (var key in obj) {
633
+ if (_.isFunction(obj[key])) names.push(key);
634
+ }
635
+ return names.sort();
541
636
  };
542
637
 
543
638
  // Extend a given object with all the properties in passed-in object(s).
544
639
  _.extend = function(obj) {
545
640
  each(slice.call(arguments, 1), function(source) {
546
641
  for (var prop in source) {
547
- if (source[prop] !== void 0) obj[prop] = source[prop];
642
+ obj[prop] = source[prop];
548
643
  }
549
644
  });
550
645
  return obj;
551
646
  };
552
647
 
648
+ // Return a copy of the object only containing the whitelisted properties.
649
+ _.pick = function(obj) {
650
+ var result = {};
651
+ each(_.flatten(slice.call(arguments, 1)), function(key) {
652
+ if (key in obj) result[key] = obj[key];
653
+ });
654
+ return result;
655
+ };
656
+
553
657
  // Fill in a given object with default properties.
554
658
  _.defaults = function(obj) {
555
659
  each(slice.call(arguments, 1), function(source) {
@@ -562,6 +666,7 @@
562
666
 
563
667
  // Create a (shallow-cloned) duplicate of an object.
564
668
  _.clone = function(obj) {
669
+ if (!_.isObject(obj)) return obj;
565
670
  return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
566
671
  };
567
672
 
@@ -573,49 +678,105 @@
573
678
  return obj;
574
679
  };
575
680
 
576
- // Perform a deep comparison to check if two objects are equal.
577
- _.isEqual = function(a, b) {
578
- // Check object identity.
579
- if (a === b) return true;
580
- // Different types?
581
- var atype = typeof(a), btype = typeof(b);
582
- if (atype != btype) return false;
583
- // Basic equality test (watch out for coercions).
584
- if (a == b) return true;
585
- // One is falsy and the other truthy.
586
- if ((!a && b) || (a && !b)) return false;
681
+ // Internal recursive comparison function.
682
+ function eq(a, b, stack) {
683
+ // Identical objects are equal. `0 === -0`, but they aren't identical.
684
+ // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
685
+ if (a === b) return a !== 0 || 1 / a == 1 / b;
686
+ // A strict comparison is necessary because `null == undefined`.
687
+ if (a == null || b == null) return a === b;
587
688
  // Unwrap any wrapped objects.
588
689
  if (a._chain) a = a._wrapped;
589
690
  if (b._chain) b = b._wrapped;
590
- // One of them implements an isEqual()?
591
- if (a.isEqual) return a.isEqual(b);
592
- // Check dates' integer values.
593
- if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();
594
- // Both are NaN?
595
- if (_.isNaN(a) && _.isNaN(b)) return false;
596
- // Compare regular expressions.
597
- if (_.isRegExp(a) && _.isRegExp(b))
598
- return a.source === b.source &&
599
- a.global === b.global &&
600
- a.ignoreCase === b.ignoreCase &&
601
- a.multiline === b.multiline;
602
- // If a is not an object by this point, we can't handle it.
603
- if (atype !== 'object') return false;
604
- // Check for different array lengths before comparing contents.
605
- if (a.length && (a.length !== b.length)) return false;
606
- // Nothing else worked, deep compare the contents.
607
- var aKeys = _.keys(a), bKeys = _.keys(b);
608
- // Different object sizes?
609
- if (aKeys.length != bKeys.length) return false;
610
- // Recursive comparison of contents.
611
- for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false;
612
- return true;
691
+ // Invoke a custom `isEqual` method if one is provided.
692
+ if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b);
693
+ if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a);
694
+ // Compare `[[Class]]` names.
695
+ var className = toString.call(a);
696
+ if (className != toString.call(b)) return false;
697
+ switch (className) {
698
+ // Strings, numbers, dates, and booleans are compared by value.
699
+ case '[object String]':
700
+ // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
701
+ // equivalent to `new String("5")`.
702
+ return a == String(b);
703
+ case '[object Number]':
704
+ // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
705
+ // other numeric values.
706
+ return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
707
+ case '[object Date]':
708
+ case '[object Boolean]':
709
+ // Coerce dates and booleans to numeric primitive values. Dates are compared by their
710
+ // millisecond representations. Note that invalid dates with millisecond representations
711
+ // of `NaN` are not equivalent.
712
+ return +a == +b;
713
+ // RegExps are compared by their source patterns and flags.
714
+ case '[object RegExp]':
715
+ return a.source == b.source &&
716
+ a.global == b.global &&
717
+ a.multiline == b.multiline &&
718
+ a.ignoreCase == b.ignoreCase;
719
+ }
720
+ if (typeof a != 'object' || typeof b != 'object') return false;
721
+ // Assume equality for cyclic structures. The algorithm for detecting cyclic
722
+ // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
723
+ var length = stack.length;
724
+ while (length--) {
725
+ // Linear search. Performance is inversely proportional to the number of
726
+ // unique nested structures.
727
+ if (stack[length] == a) return true;
728
+ }
729
+ // Add the first object to the stack of traversed objects.
730
+ stack.push(a);
731
+ var size = 0, result = true;
732
+ // Recursively compare objects and arrays.
733
+ if (className == '[object Array]') {
734
+ // Compare array lengths to determine if a deep comparison is necessary.
735
+ size = a.length;
736
+ result = size == b.length;
737
+ if (result) {
738
+ // Deep compare the contents, ignoring non-numeric properties.
739
+ while (size--) {
740
+ // Ensure commutative equality for sparse arrays.
741
+ if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break;
742
+ }
743
+ }
744
+ } else {
745
+ // Objects with different constructors are not equivalent.
746
+ if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false;
747
+ // Deep compare objects.
748
+ for (var key in a) {
749
+ if (_.has(a, key)) {
750
+ // Count the expected number of properties.
751
+ size++;
752
+ // Deep compare each member.
753
+ if (!(result = _.has(b, key) && eq(a[key], b[key], stack))) break;
754
+ }
755
+ }
756
+ // Ensure that both objects contain the same number of properties.
757
+ if (result) {
758
+ for (key in b) {
759
+ if (_.has(b, key) && !(size--)) break;
760
+ }
761
+ result = !size;
762
+ }
763
+ }
764
+ // Remove the first object from the stack of traversed objects.
765
+ stack.pop();
766
+ return result;
767
+ }
768
+
769
+ // Perform a deep comparison to check if two objects are equal.
770
+ _.isEqual = function(a, b) {
771
+ return eq(a, b, []);
613
772
  };
614
773
 
615
- // Is a given array or object empty?
774
+ // Is a given array, string, or object empty?
775
+ // An "empty" object has no enumerable own-properties.
616
776
  _.isEmpty = function(obj) {
777
+ if (obj == null) return true;
617
778
  if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
618
- for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;
779
+ for (var key in obj) if (_.has(obj, key)) return false;
619
780
  return true;
620
781
  };
621
782
 
@@ -627,48 +788,63 @@
627
788
  // Is a given value an array?
628
789
  // Delegates to ECMA5's native Array.isArray
629
790
  _.isArray = nativeIsArray || function(obj) {
630
- return toString.call(obj) === '[object Array]';
791
+ return toString.call(obj) == '[object Array]';
792
+ };
793
+
794
+ // Is a given variable an object?
795
+ _.isObject = function(obj) {
796
+ return obj === Object(obj);
631
797
  };
632
798
 
633
799
  // Is a given variable an arguments object?
634
800
  _.isArguments = function(obj) {
635
- return !!(obj && hasOwnProperty.call(obj, 'callee'));
801
+ return toString.call(obj) == '[object Arguments]';
636
802
  };
803
+ if (!_.isArguments(arguments)) {
804
+ _.isArguments = function(obj) {
805
+ return !!(obj && _.has(obj, 'callee'));
806
+ };
807
+ }
637
808
 
638
809
  // Is a given value a function?
639
810
  _.isFunction = function(obj) {
640
- return !!(obj && obj.constructor && obj.call && obj.apply);
811
+ return toString.call(obj) == '[object Function]';
641
812
  };
642
813
 
643
814
  // Is a given value a string?
644
815
  _.isString = function(obj) {
645
- return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));
816
+ return toString.call(obj) == '[object String]';
646
817
  };
647
818
 
648
819
  // Is a given value a number?
649
820
  _.isNumber = function(obj) {
650
- return !!(obj === 0 || (obj && obj.toExponential && obj.toFixed));
821
+ return toString.call(obj) == '[object Number]';
651
822
  };
652
823
 
653
- // Is the given value `NaN`? `NaN` happens to be the only value in JavaScript
654
- // that does not equal itself.
824
+ // Is a given object a finite number?
825
+ _.isFinite = function(obj) {
826
+ return _.isNumber(obj) && isFinite(obj);
827
+ };
828
+
829
+ // Is the given value `NaN`?
655
830
  _.isNaN = function(obj) {
831
+ // `NaN` is the only value for which `===` is not reflexive.
656
832
  return obj !== obj;
657
833
  };
658
834
 
659
835
  // Is a given value a boolean?
660
836
  _.isBoolean = function(obj) {
661
- return obj === true || obj === false;
837
+ return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
662
838
  };
663
839
 
664
840
  // Is a given value a date?
665
841
  _.isDate = function(obj) {
666
- return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);
842
+ return toString.call(obj) == '[object Date]';
667
843
  };
668
844
 
669
845
  // Is the given value a regular expression?
670
846
  _.isRegExp = function(obj) {
671
- return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));
847
+ return toString.call(obj) == '[object RegExp]';
672
848
  };
673
849
 
674
850
  // Is a given value equal to null?
@@ -681,6 +857,11 @@
681
857
  return obj === void 0;
682
858
  };
683
859
 
860
+ // Has own property?
861
+ _.has = function(obj, key) {
862
+ return hasOwnProperty.call(obj, key);
863
+ };
864
+
684
865
  // Utility Functions
685
866
  // -----------------
686
867
 
@@ -701,6 +882,19 @@
701
882
  for (var i = 0; i < n; i++) iterator.call(context, i);
702
883
  };
703
884
 
885
+ // Escape a string for HTML interpolation.
886
+ _.escape = function(string) {
887
+ return (''+string).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g,'&#x2F;');
888
+ };
889
+
890
+ // If the value of the named property is a function then invoke it;
891
+ // otherwise, return it.
892
+ _.result = function(object, property) {
893
+ if (object == null) return null;
894
+ var value = object[property];
895
+ return _.isFunction(value) ? value.call(object) : value;
896
+ };
897
+
704
898
  // Add your own custom functions to the Underscore object, ensuring that
705
899
  // they're correctly added to the OOP wrapper as well.
706
900
  _.mixin = function(obj) {
@@ -721,31 +915,86 @@
721
915
  // following template settings to use alternative delimiters.
722
916
  _.templateSettings = {
723
917
  evaluate : /<%([\s\S]+?)%>/g,
724
- interpolate : /<%=([\s\S]+?)%>/g
918
+ interpolate : /<%=([\s\S]+?)%>/g,
919
+ escape : /<%-([\s\S]+?)%>/g
920
+ };
921
+
922
+ // When customizing `templateSettings`, if you don't want to define an
923
+ // interpolation, evaluation or escaping regex, we need one that is
924
+ // guaranteed not to match.
925
+ var noMatch = /.^/;
926
+
927
+ // Certain characters need to be escaped so that they can be put into a
928
+ // string literal.
929
+ var escapes = {
930
+ '\\': '\\',
931
+ "'": "'",
932
+ 'r': '\r',
933
+ 'n': '\n',
934
+ 't': '\t',
935
+ 'u2028': '\u2028',
936
+ 'u2029': '\u2029'
937
+ };
938
+
939
+ for (var p in escapes) escapes[escapes[p]] = p;
940
+ var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
941
+ var unescaper = /\\(\\|'|r|n|t|u2028|u2029)/g;
942
+
943
+ // Within an interpolation, evaluation, or escaping, remove HTML escaping
944
+ // that had been previously added.
945
+ var unescape = function(code) {
946
+ return code.replace(unescaper, function(match, escape) {
947
+ return escapes[escape];
948
+ });
725
949
  };
726
950
 
727
951
  // JavaScript micro-templating, similar to John Resig's implementation.
728
952
  // Underscore templating handles arbitrary delimiters, preserves whitespace,
729
953
  // and correctly escapes quotes within interpolated code.
730
- _.template = function(str, data) {
731
- var c = _.templateSettings;
732
- var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
733
- 'with(obj||{}){__p.push(\'' +
734
- str.replace(/\\/g, '\\\\')
735
- .replace(/'/g, "\\'")
736
- .replace(c.interpolate, function(match, code) {
737
- return "'," + code.replace(/\\'/g, "'") + ",'";
738
- })
739
- .replace(c.evaluate || null, function(match, code) {
740
- return "');" + code.replace(/\\'/g, "'")
741
- .replace(/[\r\n\t]/g, ' ') + "__p.push('";
742
- })
743
- .replace(/\r/g, '\\r')
744
- .replace(/\n/g, '\\n')
745
- .replace(/\t/g, '\\t')
746
- + "');}return __p.join('');";
747
- var func = new Function('obj', tmpl);
748
- return data ? func(data) : func;
954
+ _.template = function(text, data, settings) {
955
+ settings = _.defaults(settings || {}, _.templateSettings);
956
+
957
+ // Compile the template source, taking care to escape characters that
958
+ // cannot be included in a string literal and then unescape them in code
959
+ // blocks.
960
+ var source = "__p+='" + text
961
+ .replace(escaper, function(match) {
962
+ return '\\' + escapes[match];
963
+ })
964
+ .replace(settings.escape || noMatch, function(match, code) {
965
+ return "'+\n_.escape(" + unescape(code) + ")+\n'";
966
+ })
967
+ .replace(settings.interpolate || noMatch, function(match, code) {
968
+ return "'+\n(" + unescape(code) + ")+\n'";
969
+ })
970
+ .replace(settings.evaluate || noMatch, function(match, code) {
971
+ return "';\n" + unescape(code) + "\n;__p+='";
972
+ }) + "';\n";
973
+
974
+ // If a variable is not specified, place data values in local scope.
975
+ if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
976
+
977
+ source = "var __p='';" +
978
+ "var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n" +
979
+ source + "return __p;\n";
980
+
981
+ var render = new Function(settings.variable || 'obj', '_', source);
982
+ if (data) return render(data, _);
983
+ var template = function(data) {
984
+ return render.call(this, data, _);
985
+ };
986
+
987
+ // Provide the compiled function source as a convenience for build time
988
+ // precompilation.
989
+ template.source = 'function(' + (settings.variable || 'obj') + '){\n' +
990
+ source + '}';
991
+
992
+ return template;
993
+ };
994
+
995
+ // Add a "chain" function, which will delegate to the wrapper.
996
+ _.chain = function(obj) {
997
+ return _(obj).chain();
749
998
  };
750
999
 
751
1000
  // The OOP Wrapper
@@ -780,8 +1029,11 @@
780
1029
  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
781
1030
  var method = ArrayProto[name];
782
1031
  wrapper.prototype[name] = function() {
783
- method.apply(this._wrapped, arguments);
784
- return result(this._wrapped, this._chain);
1032
+ var wrapped = this._wrapped;
1033
+ method.apply(wrapped, arguments);
1034
+ var length = wrapped.length;
1035
+ if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0];
1036
+ return result(wrapped, this._chain);
785
1037
  };
786
1038
  });
787
1039
 
@@ -804,4 +1056,4 @@
804
1056
  return this._wrapped;
805
1057
  };
806
1058
 
807
- })();
1059
+ }).call(this);