      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