1 //     (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
  2 //     Underscore is freely distributable under the MIT license.
  3 //     Portions of Underscore are inspired or borrowed from Prototype,
  4 //     Oliver Steele's Functional, and John Resig's Micro-Templating.
  5 //     For all details and documentation:
  6 //     http://documentcloud.github.com/underscore
  7 
  8 (function() {
  9 
 10   // Baseline setup
 11   // --------------
 12 
 13   // Establish the root object, `window` in the browser, or `global` on the server.
 14   var root = this;
 15 
 16   // Save the previous value of the `_` variable.
 17   var previousUnderscore = root._;
 18 
 19   // Establish the object that gets thrown to break out of a loop iteration.
 20   var breaker = typeof StopIteration !== 'undefined' ? StopIteration : '__break__';
 21 
 22   // Save bytes in the minified (but not gzipped) version:
 23   var ArrayProto = Array.prototype, ObjProto = Object.prototype;
 24 
 25   // Create quick reference variables for speed access to core prototypes.
 26   var slice            = ArrayProto.slice,
 27       unshift          = ArrayProto.unshift,
 28       toString         = ObjProto.toString,
 29       hasOwnProperty   = ObjProto.hasOwnProperty;
 30 
 31   // All **ECMAScript 5** native function implementations that we hope to use
 32   // are declared here.
 33   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     nativeIsArray      = Array.isArray,
 44     nativeKeys         = Object.keys;
 45 
 46   // Create a safe reference to the Underscore object for use below.
 47   var _ = function(obj) { return new wrapper(obj); };
 48 
 49   // Export the Underscore object for **CommonJS**.
 50   if (typeof exports !== 'undefined') exports._ = _;
 51 
 52   // Export Underscore to the global scope.
 53   root._ = _;
 54 
 55   // Current version.
 56   _.VERSION = '1.1.2';
 57 
 58   // Collection Functions
 59   // --------------------
 60 
 61   // The cornerstone, an `each` implementation, aka `forEach`.
 62   // Handles objects implementing `forEach`, arrays, and raw objects.
 63   // Delegates to **ECMAScript 5**'s native `forEach` if available.
 64   var each = _.each = _.forEach = function(obj, iterator, context) {
 65     try {
 66       if (nativeForEach && obj.forEach === nativeForEach) {
 67         obj.forEach(iterator, context);
 68       } else if (_.isNumber(obj.length)) {
 69         for (var i = 0, l = obj.length; i < l; i++) iterator.call(context, obj[i], i, obj);
 70       } else {
 71         for (var key in obj) {
 72           if (hasOwnProperty.call(obj, key)) iterator.call(context, obj[key], key, obj);
 73         }
 74       }
 75     } catch(e) {
 76       if (e != breaker) throw e;
 77     }
 78     return obj;
 79   };
 80 
 81   // Return the results of applying the iterator to each element.
 82   // Delegates to **ECMAScript 5**'s native `map` if available.
 83   _.map = function(obj, iterator, context) {
 84     if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
 85     var results = [];
 86     each(obj, function(value, index, list) {
 87       results[results.length] = iterator.call(context, value, index, list);
 88     });
 89     return results;
 90   };
 91 
 92   // **Reduce** builds up a single result from a list of values, aka `inject`,
 93   // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
 94   _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
 95     var initial = memo !== void 0;
 96     if (nativeReduce && obj.reduce === nativeReduce) {
 97       if (context) iterator = _.bind(iterator, context);
 98       return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
 99     }
100     each(obj, function(value, index, list) {
101       if (!initial && index === 0) {
102         memo = value;
103       } else {
104         memo = iterator.call(context, memo, value, index, list);
105       }
106     });
107     return memo;
108   };
109 
110   // The right-associative version of reduce, also known as `foldr`.
111   // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
112   _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
113     if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
114       if (context) iterator = _.bind(iterator, context);
115       return memo !== void 0 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
116     }
117     var reversed = (_.isArray(obj) ? obj.slice() : _.toArray(obj)).reverse();
118     return _.reduce(reversed, iterator, memo, context);
119   };
120 
121   // Return the first value which passes a truth test. Aliased as `detect`.
122   _.find = _.detect = function(obj, iterator, context) {
123     var result;
124     each(obj, function(value, index, list) {
125       if (iterator.call(context, value, index, list)) {
126         result = value;
127         _.breakLoop();
128       }
129     });
130     return result;
131   };
132 
133   // Return all the elements that pass a truth test.
134   // Delegates to **ECMAScript 5**'s native `filter` if available.
135   // Aliased as `select`.
136   _.filter = _.select = function(obj, iterator, context) {
137     if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
138     var results = [];
139     each(obj, function(value, index, list) {
140       if (iterator.call(context, value, index, list)) results[results.length] = value;
141     });
142     return results;
143   };
144 
145   // Return all the elements for which a truth test fails.
146   _.reject = function(obj, iterator, context) {
147     var results = [];
148     each(obj, function(value, index, list) {
149       if (!iterator.call(context, value, index, list)) results[results.length] = value;
150     });
151     return results;
152   };
153 
154   // Determine whether all of the elements match a truth test.
155   // Delegates to **ECMAScript 5**'s native `every` if available.
156   // Aliased as `all`.
157   _.every = _.all = function(obj, iterator, context) {
158     iterator = iterator || _.identity;
159     if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
160     var result = true;
161     each(obj, function(value, index, list) {
162       if (!(result = result && iterator.call(context, value, index, list))) _.breakLoop();
163     });
164     return result;
165   };
166 
167   // Determine if at least one element in the object matches a truth test.
168   // Delegates to **ECMAScript 5**'s native `some` if available.
169   // Aliased as `any`.
170   _.some = _.any = function(obj, iterator, context) {
171     iterator = iterator || _.identity;
172     if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
173     var result = false;
174     each(obj, function(value, index, list) {
175       if (result = iterator.call(context, value, index, list)) _.breakLoop();
176     });
177     return result;
178   };
179 
180   // Determine if a given value is included in the array or object using `===`.
181   // Aliased as `contains`.
182   _.include = _.contains = function(obj, target) {
183     if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
184     var found = false;
185     each(obj, function(value) {
186       if (found = value === target) _.breakLoop();
187     });
188     return found;
189   };
190 
191   // Invoke a method (with arguments) on every item in a collection.
192   _.invoke = function(obj, method) {
193     var args = slice.call(arguments, 2);
194     return _.map(obj, function(value) {
195       return (method ? value[method] : value).apply(value, args);
196     });
197   };
198 
199   // Convenience version of a common use case of `map`: fetching a property.
200   _.pluck = function(obj, key) {
201     return _.map(obj, function(value){ return value[key]; });
202   };
203 
204   // Return the maximum element or (element-based computation).
205   _.max = function(obj, iterator, context) {
206     if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
207     var result = {computed : -Infinity};
208     each(obj, function(value, index, list) {
209       var computed = iterator ? iterator.call(context, value, index, list) : value;
210       computed >= result.computed && (result = {value : value, computed : computed});
211     });
212     return result.value;
213   };
214 
215   // Return the minimum element (or element-based computation).
216   _.min = function(obj, iterator, context) {
217     if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
218     var result = {computed : Infinity};
219     each(obj, function(value, index, list) {
220       var computed = iterator ? iterator.call(context, value, index, list) : value;
221       computed < result.computed && (result = {value : value, computed : computed});
222     });
223     return result.value;
224   };
225 
226   // Sort the object's values by a criterion produced by an iterator.
227   _.sortBy = function(obj, iterator, context) {
228     return _.pluck(_.map(obj, function(value, index, list) {
229       return {
230         value : value,
231         criteria : iterator.call(context, value, index, list)
232       };
233     }).sort(function(left, right) {
234       var a = left.criteria, b = right.criteria;
235       return a < b ? -1 : a > b ? 1 : 0;
236     }), 'value');
237   };
238 
239   // Use a comparator function to figure out at what index an object should
240   // be inserted so as to maintain order. Uses binary search.
241   _.sortedIndex = function(array, obj, iterator) {
242     iterator = iterator || _.identity;
243     var low = 0, high = array.length;
244     while (low < high) {
245       var mid = (low + high) >> 1;
246       iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
247     }
248     return low;
249   };
250 
251   // Safely convert anything iterable into a real, live array.
252   _.toArray = function(iterable) {
253     if (!iterable)                return [];
254     if (iterable.toArray)         return iterable.toArray();
255     if (_.isArray(iterable))      return iterable;
256     if (_.isArguments(iterable))  return slice.call(iterable);
257     return _.values(iterable);
258   };
259 
260   // Return the number of elements in an object.
261   _.size = function(obj) {
262     return _.toArray(obj).length;
263   };
264 
265   // Array Functions
266   // ---------------
267 
268   // Get the first element of an array. Passing **n** will return the first N
269   // values in the array. Aliased as `head`. The **guard** check allows it to work
270   // with `_.map`.
271   _.first = _.head = function(array, n, guard) {
272     return n && !guard ? slice.call(array, 0, n) : array[0];
273   };
274 
275   // Returns everything but the first entry of the array. Aliased as `tail`.
276   // Especially useful on the arguments object. Passing an **index** will return
277   // the rest of the values in the array from that index onward. The **guard**
278   // check allows it to work with `_.map`.
279   _.rest = _.tail = function(array, index, guard) {
280     return slice.call(array, _.isUndefined(index) || guard ? 1 : index);
281   };
282 
283   // Get the last element of an array.
284   _.last = function(array) {
285     return array[array.length - 1];
286   };
287 
288   // Trim out all falsy values from an array.
289   _.compact = function(array) {
290     return _.filter(array, function(value){ return !!value; });
291   };
292 
293   // Return a completely flattened version of an array.
294   _.flatten = function(array) {
295     return _.reduce(array, function(memo, value) {
296       if (_.isArray(value)) return memo.concat(_.flatten(value));
297       memo[memo.length] = value;
298       return memo;
299     }, []);
300   };
301 
302   // Return a version of the array that does not contain the specified value(s).
303   _.without = function(array) {
304     var values = slice.call(arguments, 1);
305     return _.filter(array, function(value){ return !_.include(values, value); });
306   };
307 
308   // Produce a duplicate-free version of the array. If the array has already
309   // been sorted, you have the option of using a faster algorithm.
310   // Aliased as `unique`.
311   _.uniq = _.unique = function(array, isSorted) {
312     return _.reduce(array, function(memo, el, i) {
313       if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo[memo.length] = el;
314       return memo;
315     }, []);
316   };
317 
318   // Produce an array that contains every item shared between all the
319   // passed-in arrays.
320   _.intersect = function(array) {
321     var rest = slice.call(arguments, 1);
322     return _.filter(_.uniq(array), function(item) {
323       return _.every(rest, function(other) {
324         return _.indexOf(other, item) >= 0;
325       });
326     });
327   };
328 
329   // Zip together multiple lists into a single array -- elements that share
330   // an index go together.
331   _.zip = function() {
332     var args = slice.call(arguments);
333     var length = _.max(_.pluck(args, 'length'));
334     var results = new Array(length);
335     for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i);
336     return results;
337   };
338 
339   // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
340   // we need this function. Return the position of the first occurence of an
341   // item in an array, or -1 if the item is not included in the array.
342   // Delegates to **ECMAScript 5**'s native `indexOf` if available.
343   _.indexOf = function(array, item) {
344     if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
345     for (var i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
346     return -1;
347   };
348 
349 
350   // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
351   _.lastIndexOf = function(array, item) {
352     if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
353     var i = array.length;
354     while (i--) if (array[i] === item) return i;
355     return -1;
356   };
357 
358   // Generate an integer Array containing an arithmetic progression. A port of
359   // the native Python `range()` function. See
360   // [the Python documentation](http://docs.python.org/library/functions.html#range).
361   _.range = function(start, stop, step) {
362     var args  = slice.call(arguments),
363         solo  = args.length <= 1,
364         start = solo ? 0 : args[0],
365         stop  = solo ? args[0] : args[1],
366         step  = args[2] || 1,
367         len   = Math.max(Math.ceil((stop - start) / step), 0),
368         idx   = 0,
369         range = new Array(len);
370     while (idx < len) {
371       range[idx++] = start;
372       start += step;
373     }
374     return range;
375   };
376 
377   // Function (ahem) Functions
378   // ------------------
379 
380   // Create a function bound to a given object (assigning `this`, and arguments,
381   // optionally). Binding with arguments is also known as `curry`.
382   _.bind = function(func, obj) {
383     var args = slice.call(arguments, 2);
384     return function() {
385       return func.apply(obj || {}, args.concat(slice.call(arguments)));
386     };
387   };
388 
389   // Bind all of an object's methods to that object. Useful for ensuring that
390   // all callbacks defined on an object belong to it.
391   _.bindAll = function(obj) {
392     var funcs = slice.call(arguments, 1);
393     if (funcs.length == 0) funcs = _.functions(obj);
394     each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
395     return obj;
396   };
397 
398   // Memoize an expensive function by storing its results.
399   _.memoize = function(func, hasher) {
400     var memo = {};
401     hasher = hasher || _.identity;
402     return function() {
403       var key = hasher.apply(this, arguments);
404       return key in memo ? memo[key] : (memo[key] = func.apply(this, arguments));
405     };
406   };
407 
408   // Delays a function for the given number of milliseconds, and then calls
409   // it with the arguments supplied.
410   _.delay = function(func, wait) {
411     var args = slice.call(arguments, 2);
412     return setTimeout(function(){ return func.apply(func, args); }, wait);
413   };
414 
415   // Defers a function, scheduling it to run after the current call stack has
416   // cleared.
417   _.defer = function(func) {
418     return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
419   };
420 
421   // Returns the first function passed as an argument to the second,
422   // allowing you to adjust arguments, run code before and after, and
423   // conditionally execute the original function.
424   _.wrap = function(func, wrapper) {
425     return function() {
426       var args = [func].concat(slice.call(arguments));
427       return wrapper.apply(wrapper, args);
428     };
429   };
430 
431   // Returns a function that is the composition of a list of functions, each
432   // consuming the return value of the function that follows.
433   _.compose = function() {
434     var funcs = slice.call(arguments);
435     return function() {
436       var args = slice.call(arguments);
437       for (var i=funcs.length-1; i >= 0; i--) {
438         args = [funcs[i].apply(this, args)];
439       }
440       return args[0];
441     };
442   };
443 
444   // Object Functions
445   // ----------------
446 
447   // Retrieve the names of an object's properties.
448   // Delegates to **ECMAScript 5**'s native `Object.keys`
449   _.keys = nativeKeys || function(obj) {
450     if (_.isArray(obj)) return _.range(0, obj.length);
451     var keys = [];
452     for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key;
453     return keys;
454   };
455 
456   // Retrieve the values of an object's properties.
457   _.values = function(obj) {
458     return _.map(obj, _.identity);
459   };
460 
461   // Return a sorted list of the function names available on the object.
462   // Aliased as `methods`
463   _.functions = _.methods = function(obj) {
464     return _.filter(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort();
465   };
466 
467   // Extend a given object with all the properties in passed-in object(s).
468   _.extend = function(obj) {
469     each(slice.call(arguments, 1), function(source) {
470       for (var prop in source) obj[prop] = source[prop];
471     });
472     return obj;
473   };
474 
475   // Create a (shallow-cloned) duplicate of an object.
476   _.clone = function(obj) {
477     return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
478   };
479 
480   // Invokes interceptor with the obj, and then returns obj.
481   // The primary purpose of this method is to "tap into" a method chain, in
482   // order to perform operations on intermediate results within the chain.
483   _.tap = function(obj, interceptor) {
484     interceptor(obj);
485     return obj;
486   };
487 
488   // Perform a deep comparison to check if two objects are equal.
489   _.isEqual = function(a, b) {
490     // Check object identity.
491     if (a === b) return true;
492     // Different types?
493     var atype = typeof(a), btype = typeof(b);
494     if (atype != btype) return false;
495     // Basic equality test (watch out for coercions).
496     if (a == b) return true;
497     // One is falsy and the other truthy.
498     if ((!a && b) || (a && !b)) return false;
499     // One of them implements an isEqual()?
500     if (a.isEqual) return a.isEqual(b);
501     // Check dates' integer values.
502     if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();
503     // Both are NaN?
504     if (_.isNaN(a) && _.isNaN(b)) return false;
505     // Compare regular expressions.
506     if (_.isRegExp(a) && _.isRegExp(b))
507       return a.source     === b.source &&
508              a.global     === b.global &&
509              a.ignoreCase === b.ignoreCase &&
510              a.multiline  === b.multiline;
511     // If a is not an object by this point, we can't handle it.
512     if (atype !== 'object') return false;
513     // Check for different array lengths before comparing contents.
514     if (a.length && (a.length !== b.length)) return false;
515     // Nothing else worked, deep compare the contents.
516     var aKeys = _.keys(a), bKeys = _.keys(b);
517     // Different object sizes?
518     if (aKeys.length != bKeys.length) return false;
519     // Recursive comparison of contents.
520     for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false;
521     return true;
522   };
523 
524   // Is a given array or object empty?
525   _.isEmpty = function(obj) {
526     if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
527     for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;
528     return true;
529   };
530 
531   // Is a given value a DOM element?
532   _.isElement = function(obj) {
533     return !!(obj && obj.nodeType == 1);
534   };
535 
536   // Is a given value an array?
537   // Delegates to ECMA5's native Array.isArray
538   _.isArray = nativeIsArray || function(obj) {
539     return !!(obj && obj.concat && obj.unshift && !obj.callee);
540   };
541 
542   // Is a given variable an arguments object?
543   _.isArguments = function(obj) {
544     return !!(obj && obj.callee);
545   };
546 
547   // Is a given value a function?
548   _.isFunction = function(obj) {
549     return !!(obj && obj.constructor && obj.call && obj.apply);
550   };
551 
552   // Is a given value a string?
553   _.isString = function(obj) {
554     return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));
555   };
556 
557   // Is a given value a number?
558   _.isNumber = function(obj) {
559     return (obj === +obj) || (toString.call(obj) === '[object Number]');
560   };
561 
562   // Is a given value a boolean?
563   _.isBoolean = function(obj) {
564     return obj === true || obj === false;
565   };
566 
567   // Is a given value a date?
568   _.isDate = function(obj) {
569     return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);
570   };
571 
572   // Is the given value a regular expression?
573   _.isRegExp = function(obj) {
574     return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));
575   };
576 
577   // Is the given value NaN -- this one is interesting. NaN != NaN, and
578   // isNaN(undefined) == true, so we make sure it's a number first.
579   _.isNaN = function(obj) {
580     return _.isNumber(obj) && isNaN(obj);
581   };
582 
583   // Is a given value equal to null?
584   _.isNull = function(obj) {
585     return obj === null;
586   };
587 
588   // Is a given variable undefined?
589   _.isUndefined = function(obj) {
590     return typeof obj == 'undefined';
591   };
592 
593   // Utility Functions
594   // -----------------
595 
596   // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
597   // previous owner. Returns a reference to the Underscore object.
598   _.noConflict = function() {
599     root._ = previousUnderscore;
600     return this;
601   };
602 
603   // Keep the identity function around for default iterators.
604   _.identity = function(value) {
605     return value;
606   };
607 
608   // Run a function **n** times.
609   _.times = function (n, iterator, context) {
610     for (var i = 0; i < n; i++) iterator.call(context, i);
611   };
612 
613   // Break out of the middle of an iteration.
614   _.breakLoop = function() {
615     throw breaker;
616   };
617 
618   // Add your own custom functions to the Underscore object, ensuring that
619   // they're correctly added to the OOP wrapper as well.
620   _.mixin = function(obj) {
621     each(_.functions(obj), function(name){
622       addToWrapper(name, _[name] = obj[name]);
623     });
624   };
625 
626   // Generate a unique integer id (unique within the entire client session).
627   // Useful for temporary DOM ids.
628   var idCounter = 0;
629   _.uniqueId = function(prefix) {
630     var id = idCounter++;
631     return prefix ? prefix + id : id;
632   };
633 
634   // By default, Underscore uses ERB-style template delimiters, change the
635   // following template settings to use alternative delimiters.
636   _.templateSettings = {
637     evaluate    : /<%([\s\S]+?)%>/g,
638     interpolate : /<%=([\s\S]+?)%>/g
639   };
640 
641   // JavaScript micro-templating, similar to John Resig's implementation.
642   // Underscore templating handles arbitrary delimiters, preserves whitespace,
643   // and correctly escapes quotes within interpolated code.
644   _.template = function(str, data) {
645     var c  = _.templateSettings;
646     var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
647       'with(obj||{}){__p.push(\'' +
648       str.replace(/'/g, "\\'")
649          .replace(c.interpolate, function(match, code) {
650            return "'," + code.replace(/\\'/g, "'") + ",'";
651          })
652          .replace(c.evaluate || null, function(match, code) {
653            return "');" + code.replace(/\\'/g, "'")
654                               .replace(/[\r\n\t]/g, ' ') + "__p.push('";
655          })
656          .replace(/\r/g, '\\r')
657          .replace(/\n/g, '\\n')
658          .replace(/\t/g, '\\t')
659          + "');}return __p.join('');";
660     var func = new Function('obj', tmpl);
661     return data ? func(data) : func;
662   };
663 
664   // The OOP Wrapper
665   // ---------------
666 
667   // If Underscore is called as a function, it returns a wrapped object that
668   // can be used OO-style. This wrapper holds altered versions of all the
669   // underscore functions. Wrapped objects may be chained.
670   var wrapper = function(obj) { this._wrapped = obj; };
671 
672   // Expose `wrapper.prototype` as `_.prototype`
673   _.prototype = wrapper.prototype;
674 
675   // Helper function to continue chaining intermediate results.
676   var result = function(obj, chain) {
677     return chain ? _(obj).chain() : obj;
678   };
679 
680   // A method to easily add functions to the OOP wrapper.
681   var addToWrapper = function(name, func) {
682     wrapper.prototype[name] = function() {
683       var args = slice.call(arguments);
684       unshift.call(args, this._wrapped);
685       return result(func.apply(_, args), this._chain);
686     };
687   };
688 
689   // Add all of the Underscore functions to the wrapper object.
690   _.mixin(_);
691 
692   // Add all mutator Array functions to the wrapper.
693   each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
694     var method = ArrayProto[name];
695     wrapper.prototype[name] = function() {
696       method.apply(this._wrapped, arguments);
697       return result(this._wrapped, this._chain);
698     };
699   });
700 
701   // Add all accessor Array functions to the wrapper.
702   each(['concat', 'join', 'slice'], function(name) {
703     var method = ArrayProto[name];
704     wrapper.prototype[name] = function() {
705       return result(method.apply(this._wrapped, arguments), this._chain);
706     };
707   });
708 
709   // Start chaining a wrapped Underscore object.
710   wrapper.prototype.chain = function() {
711     this._chain = true;
712     return this;
713   };
714 
715   // Extracts the result from a wrapped and chained object.
716   wrapper.prototype.value = function() {
717     return this._wrapped;
718   };
719 
720 })();
721