// Underscore.js 1.4.12 // http://underscorejs.org3 // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.4 // Underscore may be freely distributed under the MIT license.56 (function() {78 // Baseline setup9 // --------------1011 // Establish the root object, `window` in the browser, or `global` on the server.12 var root = this;1314 // Save the previous value of the `_` variable.15 var previousUnderscore = root._;1617 // Establish the object that gets returned to break out of a loop iteration.18 var breaker = {};1920 // Save bytes in the minified (but not gzipped) version:21 var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;2223 // Create quick reference variables for speed access to core prototypes.24 var push = ArrayProto.push,25 slice = ArrayProto.slice,26 concat = ArrayProto.concat,27 unshift = ArrayProto.unshift,28 toString = ObjProto.toString,29 hasOwnProperty = ObjProto.hasOwnProperty;3031 // All **ECMAScript 5** native function implementations that we hope to use32 // are declared here.33 var34 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 nativeBind = FuncProto.bind;4647 // Create a safe reference to the Underscore object for use below.48 var _ = function(obj) {49 if (obj instanceof _) return obj;50 if (!(this instanceof _)) return new _(obj);51 this._wrapped = obj;52 };5354 // Export the Underscore object for **Node.js**, with55 // backwards-compatibility for the old `require()` API. If we're in56 // the browser, add `_` as a global object via a string identifier,57 // for Closure Compiler "advanced" mode.58 if (typeof exports !== 'undefined') {59 if (typeof module !== 'undefined' && module.exports) {60 exports = module.exports = _;61 }62 exports._ = _;63 } else {64 root['_'] = _;65 }6667 // Current version.68 _.VERSION = '1.4.1';6970 // Collection Functions71 // --------------------7273 // The cornerstone, an `each` implementation, aka `forEach`.74 // Handles objects with the built-in `forEach`, arrays, and raw objects.75 // Delegates to **ECMAScript 5**'s native `forEach` if available.76 var each = _.each = _.forEach = function(obj, iterator, context) {77 if (nativeForEach && obj.forEach === nativeForEach) {78 obj.forEach(iterator, context);79 } else if (obj.length === +obj.length) {80 for (var i = 0, l = obj.length; i < l; i++) {81 if (iterator.call(context, obj[i], i, obj) === breaker) return;82 }83 } else {84 for (var key in obj) {85 if (_.has(obj, key)) {86 if (iterator.call(context, obj[key], key, obj) === breaker) return;87 }88 }89 }90 };9192 // Return the results of applying the iterator to each element.93 // Delegates to **ECMAScript 5**'s native `map` if available.94 _.map = _.collect = function(obj, iterator, context) {95 var results = [];96 if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);97 each(obj, function(value, index, list) {98 results[results.length] = iterator.call(context, value, index, list);99 });100 return results;101 };102103 // **Reduce** builds up a single result from a list of values, aka `inject`,104 // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.105 _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {106 var initial = arguments.length > 2;107 if (nativeReduce && obj.reduce === nativeReduce) {108 if (context) iterator = _.bind(iterator, context);109 return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);110 }111 each(obj, function(value, index, list) {112 if (!initial) {113 memo = value;114 initial = true;115 } else {116 memo = iterator.call(context, memo, value, index, list);117 }118 });119 if (!initial) throw new TypeError('Reduce of empty array with no initial value');120 return memo;121 };122123 // The right-associative version of reduce, also known as `foldr`.124 // Delegates to **ECMAScript 5**'s native `reduceRight` if available.125 _.reduceRight = _.foldr = function(obj, iterator, memo, context) {126 var initial = arguments.length > 2;127 if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {128 if (context) iterator = _.bind(iterator, context);129 return arguments.length > 2 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);130 }131 var length = obj.length;132 if (length !== +length) {133 var keys = _.keys(obj);134 length = keys.length;135 }136 each(obj, function(value, index, list) {137 index = keys ? keys[--length] : --length;138 if (!initial) {139 memo = obj[index];140 initial = true;141 } else {142 memo = iterator.call(context, memo, obj[index], index, list);143 }144 });145 if (!initial) throw new TypeError('Reduce of empty array with no initial value');146 return memo;147 };148149 // Return the first value which passes a truth test. Aliased as `detect`.150 _.find = _.detect = function(obj, iterator, context) {151 var result;152 any(obj, function(value, index, list) {153 if (iterator.call(context, value, index, list)) {154 result = value;155 return true;156 }157 });158 return result;159 };160161 // Return all the elements that pass a truth test.162 // Delegates to **ECMAScript 5**'s native `filter` if available.163 // Aliased as `select`.164 _.filter = _.select = function(obj, iterator, context) {165 var results = [];166 if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);167 each(obj, function(value, index, list) {168 if (iterator.call(context, value, index, list)) results[results.length] = value;169 });170 return results;171 };172173 // Return all the elements for which a truth test fails.174 _.reject = function(obj, iterator, context) {175 var results = [];176 each(obj, function(value, index, list) {177 if (!iterator.call(context, value, index, list)) results[results.length] = value;178 });179 return results;180 };181182 // Determine whether all of the elements match a truth test.183 // Delegates to **ECMAScript 5**'s native `every` if available.184 // Aliased as `all`.185 _.every = _.all = function(obj, iterator, context) {186 iterator || (iterator = _.identity);187 var result = true;188 if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);189 each(obj, function(value, index, list) {190 if (!(result = result && iterator.call(context, value, index, list))) return breaker;191 });192 return !!result;193 };194195 // Determine if at least one element in the object matches a truth test.196 // Delegates to **ECMAScript 5**'s native `some` if available.197 // Aliased as `any`.198 var any = _.some = _.any = function(obj, iterator, context) {199 iterator || (iterator = _.identity);200 var result = false;201 if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);202 each(obj, function(value, index, list) {203 if (result || (result = iterator.call(context, value, index, list))) return breaker;204 });205 return !!result;206 };207208 // Determine if the array or object contains a given value (using `===`).209 // Aliased as `include`.210 _.contains = _.include = function(obj, target) {211 var found = false;212 if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;213 found = any(obj, function(value) {214 return value === target;215 });216 return found;217 };218219 // Invoke a method (with arguments) on every item in a collection.220 _.invoke = function(obj, method) {221 var args = slice.call(arguments, 2);222 return _.map(obj, function(value) {223 return (_.isFunction(method) ? method : value[method]).apply(value, args);224 });225 };226227 // Convenience version of a common use case of `map`: fetching a property.228 _.pluck = function(obj, key) {229 return _.map(obj, function(value){ return value[key]; });230 };231232 // Convenience version of a common use case of `filter`: selecting only objects233 // with specific `key:value` pairs.234 _.where = function(obj, attrs) {235 if (_.isEmpty(attrs)) return [];236 return _.filter(obj, function(value) {237 for (var key in attrs) {238 if (attrs[key] !== value[key]) return false;239 }240 return true;241 });242 };243244 // Return the maximum element or (element-based computation).245 // Can't optimize arrays of integers longer than 65,535 elements.246 // See: https://bugs.webkit.org/show_bug.cgi?id=80797247 _.max = function(obj, iterator, context) {248 if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {249 return Math.max.apply(Math, obj);250 }251 if (!iterator && _.isEmpty(obj)) return -Infinity;252 var result = {computed : -Infinity};253 each(obj, function(value, index, list) {254 var computed = iterator ? iterator.call(context, value, index, list) : value;255 computed >= result.computed && (result = {value : value, computed : computed});256 });257 return result.value;258 };259260 // Return the minimum element (or element-based computation).261 _.min = function(obj, iterator, context) {262 if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {263 return Math.min.apply(Math, obj);264 }265 if (!iterator && _.isEmpty(obj)) return Infinity;266 var result = {computed : Infinity};267 each(obj, function(value, index, list) {268 var computed = iterator ? iterator.call(context, value, index, list) : value;269 computed < result.computed && (result = {value : value, computed : computed});270 });271 return result.value;272 };273274 // Shuffle an array.275 _.shuffle = function(obj) {276 var rand;277 var index = 0;278 var shuffled = [];279 each(obj, function(value) {280 rand = _.random(index++);281 shuffled[index - 1] = shuffled[rand];282 shuffled[rand] = value;283 });284 return shuffled;285 };286287 // An internal function to generate lookup iterators.288 var lookupIterator = function(value) {289 return _.isFunction(value) ? value : function(obj){ return obj[value]; };290 };291292 // Sort the object's values by a criterion produced by an iterator.293 _.sortBy = function(obj, value, context) {294 var iterator = lookupIterator(value);295 return _.pluck(_.map(obj, function(value, index, list) {296 return {297 value : value,298 index : index,299 criteria : iterator.call(context, value, index, list)300 };301 }).sort(function(left, right) {302 var a = left.criteria;303 var b = right.criteria;304 if (a !== b) {305 if (a > b || a === void 0) return 1;306 if (a < b || b === void 0) return -1;307 }308 return left.index < right.index ? -1 : 1;309 }), 'value');310 };311312 // An internal function used for aggregate "group by" operations.313 var group = function(obj, value, context, behavior) {314 var result = {};315 var iterator = lookupIterator(value);316 each(obj, function(value, index) {317 var key = iterator.call(context, value, index, obj);318 behavior(result, key, value);319 });320 return result;321 };322323 // Groups the object's values by a criterion. Pass either a string attribute324 // to group by, or a function that returns the criterion.325 _.groupBy = function(obj, value, context) {326 return group(obj, value, context, function(result, key, value) {327 (_.has(result, key) ? result[key] : (result[key] = [])).push(value);328 });329 };330331 // Counts instances of an object that group by a certain criterion. Pass332 // either a string attribute to count by, or a function that returns the333 // criterion.334 _.countBy = function(obj, value, context) {335 return group(obj, value, context, function(result, key, value) {336 if (!_.has(result, key)) result[key] = 0;337 result[key]++;338 });339 };340341 // Use a comparator function to figure out the smallest index at which342 // an object should be inserted so as to maintain order. Uses binary search.343 _.sortedIndex = function(array, obj, iterator, context) {344 iterator = iterator == null ? _.identity : lookupIterator(iterator);345 var value = iterator.call(context, obj);346 var low = 0, high = array.length;347 while (low < high) {348 var mid = (low + high) >>> 1;349 iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;350 }351 return low;352 };353354 // Safely convert anything iterable into a real, live array.355 _.toArray = function(obj) {356 if (!obj) return [];357 if (obj.length === +obj.length) return slice.call(obj);358 return _.values(obj);359 };360361 // Return the number of elements in an object.362 _.size = function(obj) {363 return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;364 };365366 // Array Functions367 // ---------------368369 // Get the first element of an array. Passing **n** will return the first N370 // values in the array. Aliased as `head` and `take`. The **guard** check371 // allows it to work with `_.map`.372 _.first = _.head = _.take = function(array, n, guard) {373 return (n != null) && !guard ? slice.call(array, 0, n) : array[0];374 };375376 // Returns everything but the last entry of the array. Especially useful on377 // the arguments object. Passing **n** will return all the values in378 // the array, excluding the last N. The **guard** check allows it to work with379 // `_.map`.380 _.initial = function(array, n, guard) {381 return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));382 };383384 // Get the last element of an array. Passing **n** will return the last N385 // values in the array. The **guard** check allows it to work with `_.map`.386 _.last = function(array, n, guard) {387 if ((n != null) && !guard) {388 return slice.call(array, Math.max(array.length - n, 0));389 } else {390 return array[array.length - 1];391 }392 };393394 // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.395 // Especially useful on the arguments object. Passing an **n** will return396 // the rest N values in the array. The **guard**397 // check allows it to work with `_.map`.398 _.rest = _.tail = _.drop = function(array, n, guard) {399 return slice.call(array, (n == null) || guard ? 1 : n);400 };401402 // Trim out all falsy values from an array.403 _.compact = function(array) {404 return _.filter(array, function(value){ return !!value; });405 };406407 // Internal implementation of a recursive `flatten` function.408 var flatten = function(input, shallow, output) {409 each(input, function(value) {410 if (_.isArray(value)) {411 shallow ? push.apply(output, value) : flatten(value, shallow, output);412 } else {413 output.push(value);414 }415 });416 return output;417 };418419 // Return a completely flattened version of an array.420 _.flatten = function(array, shallow) {421 return flatten(array, shallow, []);422 };423424 // Return a version of the array that does not contain the specified value(s).425 _.without = function(array) {426 return _.difference(array, slice.call(arguments, 1));427 };428429 // Produce a duplicate-free version of the array. If the array has already430 // been sorted, you have the option of using a faster algorithm.431 // Aliased as `unique`.432 _.uniq = _.unique = function(array, isSorted, iterator, context) {433 var initial = iterator ? _.map(array, iterator, context) : array;434 var results = [];435 var seen = [];436 each(initial, function(value, index) {437 if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {438 seen.push(value);439 results.push(array[index]);440 }441 });442 return results;443 };444445 // Produce an array that contains the union: each distinct element from all of446 // the passed-in arrays.447 _.union = function() {448 return _.uniq(concat.apply(ArrayProto, arguments));449 };450451 // Produce an array that contains every item shared between all the452 // passed-in arrays.453 _.intersection = function(array) {454 var rest = slice.call(arguments, 1);455 return _.filter(_.uniq(array), function(item) {456 return _.every(rest, function(other) {457 return _.indexOf(other, item) >= 0;458 });459 });460 };461462 // Take the difference between one array and a number of other arrays.463 // Only the elements present in just the first array will remain.464 _.difference = function(array) {465 var rest = concat.apply(ArrayProto, slice.call(arguments, 1));466 return _.filter(array, function(value){ return !_.contains(rest, value); });467 };468469 // Zip together multiple lists into a single array -- elements that share470 // an index go together.471 _.zip = function() {472 var args = slice.call(arguments);473 var length = _.max(_.pluck(args, 'length'));474 var results = new Array(length);475 for (var i = 0; i < length; i++) {476 results[i] = _.pluck(args, "" + i);477 }478 return results;479 };480481 // Converts lists into objects. Pass either a single array of `[key, value]`482 // pairs, or two parallel arrays of the same length -- one of keys, and one of483 // the corresponding values.484 _.object = function(list, values) {485 var result = {};486 for (var i = 0, l = list.length; i < l; i++) {487 if (values) {488 result[list[i]] = values[i];489 } else {490 result[list[i][0]] = list[i][1];491 }492 }493 return result;494 };495496 // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),497 // we need this function. Return the position of the first occurrence of an498 // item in an array, or -1 if the item is not included in the array.499 // Delegates to **ECMAScript 5**'s native `indexOf` if available.500 // If the array is large and already in sort order, pass `true`501 // for **isSorted** to use binary search.502 _.indexOf = function(array, item, isSorted) {503 var i = 0, l = array.length;504 if (isSorted) {505 if (typeof isSorted == 'number') {506 i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);507 } else {508 i = _.sortedIndex(array, item);509 return array[i] === item ? i : -1;510 }511 }512 if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);513 for (; i < l; i++) if (array[i] === item) return i;514 return -1;515 };516517 // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.518 _.lastIndexOf = function(array, item, from) {519 var hasIndex = from != null;520 if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {521 return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);522 }523 var i = (hasIndex ? from : array.length);524 while (i--) if (array[i] === item) return i;525 return -1;526 };527528 // Generate an integer Array containing an arithmetic progression. A port of529 // the native Python `range()` function. See530 // [the Python documentation](http://docs.python.org/library/functions.html#range).531 _.range = function(start, stop, step) {532 if (arguments.length <= 1) {533 stop = start || 0;534 start = 0;535 }536 step = arguments[2] || 1;537538 var len = Math.max(Math.ceil((stop - start) / step), 0);539 var idx = 0;540 var range = new Array(len);541542 while(idx < len) {543 range[idx++] = start;544 start += step;545 }546547 return range;548 };549550 // Function (ahem) Functions551 // ------------------552553 // Reusable constructor function for prototype setting.554 var ctor = function(){};555556 // Create a function bound to a given object (assigning `this`, and arguments,557 // optionally). Binding with arguments is also known as `curry`.558 // Delegates to **ECMAScript 5**'s native `Function.bind` if available.559 // We check for `func.bind` first, to fail fast when `func` is undefined.560 _.bind = function bind(func, context) {561 var bound, args;562 if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));563 if (!_.isFunction(func)) throw new TypeError;564 args = slice.call(arguments, 2);565 return bound = function() {566 if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));567 ctor.prototype = func.prototype;568 var self = new ctor;569 var result = func.apply(self, args.concat(slice.call(arguments)));570 if (Object(result) === result) return result;571 return self;572 };573 };574575 // Bind all of an object's methods to that object. Useful for ensuring that576 // all callbacks defined on an object belong to it.577 _.bindAll = function(obj) {578 var funcs = slice.call(arguments, 1);579 if (funcs.length == 0) funcs = _.functions(obj);580 each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });581 return obj;582 };583584 // Memoize an expensive function by storing its results.585 _.memoize = function(func, hasher) {586 var memo = {};587 hasher || (hasher = _.identity);588 return function() {589 var key = hasher.apply(this, arguments);590 return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));591 };592 };593594 // Delays a function for the given number of milliseconds, and then calls595 // it with the arguments supplied.596 _.delay = function(func, wait) {597 var args = slice.call(arguments, 2);598 return setTimeout(function(){ return func.apply(null, args); }, wait);599 };600601 // Defers a function, scheduling it to run after the current call stack has602 // cleared.603 _.defer = function(func) {604 return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));605 };606607 // Returns a function, that, when invoked, will only be triggered at most once608 // during a given window of time.609 _.throttle = function(func, wait) {610 var context, args, timeout, throttling, more, result;611 var whenDone = _.debounce(function(){ more = throttling = false; }, wait);612 return function() {613 context = this; args = arguments;614 var later = function() {615 timeout = null;616 if (more) {617 result = func.apply(context, args);618 }619 whenDone();620 };621 if (!timeout) timeout = setTimeout(later, wait);622 if (throttling) {623 more = true;624 } else {625 throttling = true;626 result = func.apply(context, args);627 }628 whenDone();629 return result;630 };631 };632633 // Returns a function, that, as long as it continues to be invoked, will not634 // be triggered. The function will be called after it stops being called for635 // N milliseconds. If `immediate` is passed, trigger the function on the636 // leading edge, instead of the trailing.637 _.debounce = function(func, wait, immediate) {638 var timeout, result;639 return function() {640 var context = this, args = arguments;641 var later = function() {642 timeout = null;643 if (!immediate) result = func.apply(context, args);644 };645 var callNow = immediate && !timeout;646 clearTimeout(timeout);647 timeout = setTimeout(later, wait);648 if (callNow) result = func.apply(context, args);649 return result;650 };651 };652653 // Returns a function that will be executed at most one time, no matter how654 // often you call it. Useful for lazy initialization.655 _.once = function(func) {656 var ran = false, memo;657 return function() {658 if (ran) return memo;659 ran = true;660 memo = func.apply(this, arguments);661 func = null;662 return memo;663 };664 };665666 // Returns the first function passed as an argument to the second,667 // allowing you to adjust arguments, run code before and after, and668 // conditionally execute the original function.669 _.wrap = function(func, wrapper) {670 return function() {671 var args = [func];672 push.apply(args, arguments);673 return wrapper.apply(this, args);674 };675 };676677 // Returns a function that is the composition of a list of functions, each678 // consuming the return value of the function that follows.679 _.compose = function() {680 var funcs = arguments;681 return function() {682 var args = arguments;683 for (var i = funcs.length - 1; i >= 0; i--) {684 args = [funcs[i].apply(this, args)];685 }686 return args[0];687 };688 };689690 // Returns a function that will only be executed after being called N times.691 _.after = function(times, func) {692 if (times <= 0) return func();693 return function() {694 if (--times < 1) {695 return func.apply(this, arguments);696 }697 };698 };699700 // Object Functions701 // ----------------702703 // Retrieve the names of an object's properties.704 // Delegates to **ECMAScript 5**'s native `Object.keys`705 _.keys = nativeKeys || function(obj) {706 if (obj !== Object(obj)) throw new TypeError('Invalid object');707 var keys = [];708 for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;709 return keys;710 };711712 // Retrieve the values of an object's properties.713 _.values = function(obj) {714 var values = [];715 for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);716 return values;717 };718719 // Convert an object into a list of `[key, value]` pairs.720 _.pairs = function(obj) {721 var pairs = [];722 for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);723 return pairs;724 };725726 // Invert the keys and values of an object. The values must be serializable.727 _.invert = function(obj) {728 var result = {};729 for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;730 return result;731 };732733 // Return a sorted list of the function names available on the object.734 // Aliased as `methods`735 _.functions = _.methods = function(obj) {736 var names = [];737 for (var key in obj) {738 if (_.isFunction(obj[key])) names.push(key);739 }740 return names.sort();741 };742743 // Extend a given object with all the properties in passed-in object(s).744 _.extend = function(obj) {745 each(slice.call(arguments, 1), function(source) {746 for (var prop in source) {747 obj[prop] = source[prop];748 }749 });750 return obj;751 };752753 // Return a copy of the object only containing the whitelisted properties.754 _.pick = function(obj) {755 var copy = {};756 var keys = concat.apply(ArrayProto, slice.call(arguments, 1));757 each(keys, function(key) {758 if (key in obj) copy[key] = obj[key];759 });760 return copy;761 };762763 // Return a copy of the object without the blacklisted properties.764 _.omit = function(obj) {765 var copy = {};766 var keys = concat.apply(ArrayProto, slice.call(arguments, 1));767 for (var key in obj) {768 if (!_.contains(keys, key)) copy[key] = obj[key];769 }770 return copy;771 };772773 // Fill in a given object with default properties.774 _.defaults = function(obj) {775 each(slice.call(arguments, 1), function(source) {776 for (var prop in source) {777 if (obj[prop] == null) obj[prop] = source[prop];778 }779 });780 return obj;781 };782783 // Create a (shallow-cloned) duplicate of an object.784 _.clone = function(obj) {785 if (!_.isObject(obj)) return obj;786 return _.isArray(obj) ? obj.slice() : _.extend({}, obj);787 };788789 // Invokes interceptor with the obj, and then returns obj.790 // The primary purpose of this method is to "tap into" a method chain, in791 // order to perform operations on intermediate results within the chain.792 _.tap = function(obj, interceptor) {793 interceptor(obj);794 return obj;795 };796797 // Internal recursive comparison function for `isEqual`.798 var eq = function(a, b, aStack, bStack) {799 // Identical objects are equal. `0 === -0`, but they aren't identical.800 // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.801 if (a === b) return a !== 0 || 1 / a == 1 / b;802 // A strict comparison is necessary because `null == undefined`.803 if (a == null || b == null) return a === b;804 // Unwrap any wrapped objects.805 if (a instanceof _) a = a._wrapped;806 if (b instanceof _) b = b._wrapped;807 // Compare `[[Class]]` names.808 var className = toString.call(a);809 if (className != toString.call(b)) return false;810 switch (className) {811 // Strings, numbers, dates, and booleans are compared by value.812 case '[object String]':813 // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is814 // equivalent to `new String("5")`.815 return a == String(b);816 case '[object Number]':817 // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for818 // other numeric values.819 return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);820 case '[object Date]':821 case '[object Boolean]':822 // Coerce dates and booleans to numeric primitive values. Dates are compared by their823 // millisecond representations. Note that invalid dates with millisecond representations824 // of `NaN` are not equivalent.825 return +a == +b;826 // RegExps are compared by their source patterns and flags.827 case '[object RegExp]':828 return a.source == b.source &&829 a.global == b.global &&830 a.multiline == b.multiline &&831 a.ignoreCase == b.ignoreCase;832 }833 if (typeof a != 'object' || typeof b != 'object') return false;834 // Assume equality for cyclic structures. The algorithm for detecting cyclic835 // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.836 var length = aStack.length;837 while (length--) {838 // Linear search. Performance is inversely proportional to the number of839 // unique nested structures.840 if (aStack[length] == a) return bStack[length] == b;841 }842 // Add the first object to the stack of traversed objects.843 aStack.push(a);844 bStack.push(b);845 var size = 0, result = true;846 // Recursively compare objects and arrays.847 if (className == '[object Array]') {848 // Compare array lengths to determine if a deep comparison is necessary.849 size = a.length;850 result = size == b.length;851 if (result) {852 // Deep compare the contents, ignoring non-numeric properties.853 while (size--) {854 if (!(result = eq(a[size], b[size], aStack, bStack))) break;855 }856 }857 } else {858 // Objects with different constructors are not equivalent, but `Object`s859 // from different frames are.860 var aCtor = a.constructor, bCtor = b.constructor;861 if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&862 _.isFunction(bCtor) && (bCtor instanceof bCtor))) {863 return false;864 }865 // Deep compare objects.866 for (var key in a) {867 if (_.has(a, key)) {868 // Count the expected number of properties.869 size++;870 // Deep compare each member.871 if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;872 }873 }874 // Ensure that both objects contain the same number of properties.875 if (result) {876 for (key in b) {877 if (_.has(b, key) && !(size--)) break;878 }879 result = !size;880 }881 }882 // Remove the first object from the stack of traversed objects.883 aStack.pop();884 bStack.pop();885 return result;886 };887888 // Perform a deep comparison to check if two objects are equal.889 _.isEqual = function(a, b) {890 return eq(a, b, [], []);891 };892893 // Is a given array, string, or object empty?894 // An "empty" object has no enumerable own-properties.895 _.isEmpty = function(obj) {896 if (obj == null) return true;897 if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;898 for (var key in obj) if (_.has(obj, key)) return false;899 return true;900 };901902 // Is a given value a DOM element?903 _.isElement = function(obj) {904 return !!(obj && obj.nodeType === 1);905 };906907 // Is a given value an array?908 // Delegates to ECMA5's native Array.isArray909 _.isArray = nativeIsArray || function(obj) {910 return toString.call(obj) == '[object Array]';911 };912913 // Is a given variable an object?914 _.isObject = function(obj) {915 return obj === Object(obj);916 };917918 // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.919 each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {920 _['is' + name] = function(obj) {921 return toString.call(obj) == '[object ' + name + ']';922 };923 });924925 // Define a fallback version of the method in browsers (ahem, IE), where926 // there isn't any inspectable "Arguments" type.927 if (!_.isArguments(arguments)) {928 _.isArguments = function(obj) {929 return !!(obj && _.has(obj, 'callee'));930 };931 }932933 // Optimize `isFunction` if appropriate.934 if (typeof (/./) !== 'function') {935 _.isFunction = function(obj) {936 return typeof obj === 'function';937 };938 }939940 // Is a given object a finite number?941 _.isFinite = function(obj) {942 return _.isNumber(obj) && isFinite(obj);943 };944945 // Is the given value `NaN`? (NaN is the only number which does not equal itself).946 _.isNaN = function(obj) {947 return _.isNumber(obj) && obj != +obj;948 };949950 // Is a given value a boolean?951 _.isBoolean = function(obj) {952 return obj === true || obj === false || toString.call(obj) == '[object Boolean]';953 };954955 // Is a given value equal to null?956 _.isNull = function(obj) {957 return obj === null;958 };959960 // Is a given variable undefined?961 _.isUndefined = function(obj) {962 return obj === void 0;963 };964965 // Shortcut function for checking if an object has a given property directly966 // on itself (in other words, not on a prototype).967 _.has = function(obj, key) {968 return hasOwnProperty.call(obj, key);969 };970971 // Utility Functions972 // -----------------973974 // Run Underscore.js in *noConflict* mode, returning the `_` variable to its975 // previous owner. Returns a reference to the Underscore object.976 _.noConflict = function() {977 root._ = previousUnderscore;978 return this;979 };980981 // Keep the identity function around for default iterators.982 _.identity = function(value) {983 return value;984 };985986 // Run a function **n** times.987 _.times = function(n, iterator, context) {988 for (var i = 0; i < n; i++) iterator.call(context, i);989 };990991 // Return a random integer between min and max (inclusive).992 _.random = function(min, max) {993 if (max == null) {994 max = min;995 min = 0;996 }997 return min + (0 | Math.random() * (max - min + 1));998 };9991000 // List of HTML entities for escaping.1001 var entityMap = {1002 escape: {1003 '&': '&',1004 '<': '<',1005 '>': '>',1006 '"': '"',1007 "'": ''',1008 '/': '/'1009 }1010 };1011 entityMap.unescape = _.invert(entityMap.escape);10121013 // Regexes containing the keys and values listed immediately above.1014 var entityRegexes = {1015 escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),1016 unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')1017 };10181019 // Functions for escaping and unescaping strings to/from HTML interpolation.1020 _.each(['escape', 'unescape'], function(method) {1021 _[method] = function(string) {1022 if (string == null) return '';1023 return ('' + string).replace(entityRegexes[method], function(match) {1024 return entityMap[method][match];1025 });1026 };1027 });10281029 // If the value of the named property is a function then invoke it;1030 // otherwise, return it.1031 _.result = function(object, property) {1032 if (object == null) return null;1033 var value = object[property];1034 return _.isFunction(value) ? value.call(object) : value;1035 };10361037 // Add your own custom functions to the Underscore object.1038 _.mixin = function(obj) {1039 each(_.functions(obj), function(name){1040 var func = _[name] = obj[name];1041 _.prototype[name] = function() {1042 var args = [this._wrapped];1043 push.apply(args, arguments);1044 return result.call(this, func.apply(_, args));1045 };1046 });1047 };10481049 // Generate a unique integer id (unique within the entire client session).1050 // Useful for temporary DOM ids.1051 var idCounter = 0;1052 _.uniqueId = function(prefix) {1053 var id = idCounter++;1054 return prefix ? prefix + id : id;1055 };10561057 // By default, Underscore uses ERB-style template delimiters, change the1058 // following template settings to use alternative delimiters.1059 _.templateSettings = {1060 evaluate : /<%([\s\S]+?)%>/g,1061 interpolate : /<%=([\s\S]+?)%>/g,1062 escape : /<%-([\s\S]+?)%>/g1063 };10641065 // When customizing `templateSettings`, if you don't want to define an1066 // interpolation, evaluation or escaping regex, we need one that is1067 // guaranteed not to match.1068 var noMatch = /(.)^/;10691070 // Certain characters need to be escaped so that they can be put into a1071 // string literal.1072 var escapes = {1073 "'": "'",1074 '\\': '\\',1075 '\r': 'r',1076 '\n': 'n',1077 '\t': 't',1078 '\u2028': 'u2028',1079 '\u2029': 'u2029'1080 };10811082 var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;10831084 // JavaScript micro-templating, similar to John Resig's implementation.1085 // Underscore templating handles arbitrary delimiters, preserves whitespace,1086 // and correctly escapes quotes within interpolated code.1087 _.template = function(text, data, settings) {1088 settings = _.defaults({}, settings, _.templateSettings);10891090 // Combine delimiters into one regular expression via alternation.1091 var matcher = new RegExp([1092 (settings.escape || noMatch).source,1093 (settings.interpolate || noMatch).source,1094 (settings.evaluate || noMatch).source1095 ].join('|') + '|$', 'g');10961097 // Compile the template source, escaping string literals appropriately.1098 var index = 0;1099 var source = "__p+='";1100 text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {1101 source += text.slice(index, offset)1102 .replace(escaper, function(match) { return '\\' + escapes[match]; });1103 source +=1104 escape ? "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'" :1105 interpolate ? "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'" :1106 evaluate ? "';\n" + evaluate + "\n__p+='" : '';1107 index = offset + match.length;1108 });1109 source += "';\n";11101111 // If a variable is not specified, place data values in local scope.1112 if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';11131114 source = "var __t,__p='',__j=Array.prototype.join," +1115 "print=function(){__p+=__j.call(arguments,'');};\n" +1116 source + "return __p;\n";11171118 try {1119 var render = new Function(settings.variable || 'obj', '_', source);1120 } catch (e) {1121 e.source = source;1122 throw e;1123 }11241125 if (data) return render(data, _);1126 var template = function(data) {1127 return render.call(this, data, _);1128 };11291130 // Provide the compiled function source as a convenience for precompilation.1131 template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';11321133 return template;1134 };11351136 // Add a "chain" function, which will delegate to the wrapper.1137 _.chain = function(obj) {1138 return _(obj).chain();1139 };11401141 // OOP1142 // ---------------1143 // If Underscore is called as a function, it returns a wrapped object that1144 // can be used OO-style. This wrapper holds altered versions of all the1145 // underscore functions. Wrapped objects may be chained.11461147 // Helper function to continue chaining intermediate results.1148 var result = function(obj) {1149 return this._chain ? _(obj).chain() : obj;1150 };11511152 // Add all of the Underscore functions to the wrapper object.1153 _.mixin(_);11541155 // Add all mutator Array functions to the wrapper.1156 each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {1157 var method = ArrayProto[name];1158 _.prototype[name] = function() {1159 var obj = this._wrapped;1160 method.apply(obj, arguments);1161 if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];1162 return result.call(this, obj);1163 };1164 });11651166 // Add all accessor Array functions to the wrapper.1167 each(['concat', 'join', 'slice'], function(name) {1168 var method = ArrayProto[name];1169 _.prototype[name] = function() {1170 return result.call(this, method.apply(this._wrapped, arguments));1171 };1172 });11731174 _.extend(_.prototype, {11751176 // Start chaining a wrapped Underscore object.1177 chain: function() {1178 this._chain = true;1179 return this;1180 },11811182 // Extracts the result from a wrapped and chained object.1183 value: function() {1184 return this._wrapped;1185 }11861187 });11881189 }).call(this);// Underscore.js 1.4.1 2 // http://underscorejs.org 3 // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. 4 // Underscore may be freely distributed under the MIT license. 5 6 (function() { 7 8 // Baseline setup 9 // -------------- 10 11 // Establish the root object, `window` in the browser, or `global` on the server. 12 var root = this; 13 14 // Save the previous value of the `_` variable. 15 var previousUnderscore = root._; 16 17 // Establish the object that gets returned to break out of a loop iteration. 18 var breaker = {}; 19 20 // Save bytes in the minified (but not gzipped) version: 21 var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; 22 23 // Create quick reference variables for speed access to core prototypes. 24 var push = ArrayProto.push, 25 slice = ArrayProto.slice, 26 concat = ArrayProto.concat, 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 nativeBind = FuncProto.bind; 46 47 // Create a safe reference to the Underscore object for use below. 48 var _ = function(obj) { 49 if (obj instanceof _) return obj; 50 if (!(this instanceof _)) return new _(obj); 51 this._wrapped = obj; 52 }; 53 54 // Export the Underscore object for **Node.js**, with 55 // backwards-compatibility for the old `require()` API. If we're in 56 // the browser, add `_` as a global object via a string identifier, 57 // for Closure Compiler "advanced" mode. 58 if (typeof exports !== 'undefined') { 59 if (typeof module !== 'undefined' && module.exports) { 60 exports = module.exports = _; 61 } 62 exports._ = _; 63 } else { 64 root['_'] = _; 65 } 66 67 // Current version. 68 _.VERSION = '1.4.1'; 69 70 // Collection Functions 71 // -------------------- 72 73 // The cornerstone, an `each` implementation, aka `forEach`. 74 // Handles objects with the built-in `forEach`, arrays, and raw objects. 75 // Delegates to **ECMAScript 5**'s native `forEach` if available. 76 var each = _.each = _.forEach = function(obj, iterator, context) { 77 if (nativeForEach && obj.forEach === nativeForEach) { 78 obj.forEach(iterator, context); 79 } else if (obj.length === +obj.length) { 80 for (var i = 0, l = obj.length; i < l; i++) { 81 if (iterator.call(context, obj[i], i, obj) === breaker) return; 82 } 83 } else { 84 for (var key in obj) { 85 if (_.has(obj, key)) { 86 if (iterator.call(context, obj[key], key, obj) === breaker) return; 87 } 88 } 89 } 90 }; 91 92 // Return the results of applying the iterator to each element. 93 // Delegates to **ECMAScript 5**'s native `map` if available. 94 _.map = _.collect = function(obj, iterator, context) { 95 var results = []; 96 if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); 97 each(obj, function(value, index, list) { 98 results[results.length] = iterator.call(context, value, index, list); 99 }); 100 return results; 101 }; 102 103 // **Reduce** builds up a single result from a list of values, aka `inject`, 104 // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. 105 _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { 106 var initial = arguments.length > 2; 107 if (nativeReduce && obj.reduce === nativeReduce) { 108 if (context) iterator = _.bind(iterator, context); 109 return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); 110 } 111 each(obj, function(value, index, list) { 112 if (!initial) { 113 memo = value; 114 initial = true; 115 } else { 116 memo = iterator.call(context, memo, value, index, list); 117 } 118 }); 119 if (!initial) throw new TypeError('Reduce of empty array with no initial value'); 120 return memo; 121 }; 122 123 // The right-associative version of reduce, also known as `foldr`. 124 // Delegates to **ECMAScript 5**'s native `reduceRight` if available. 125 _.reduceRight = _.foldr = function(obj, iterator, memo, context) { 126 var initial = arguments.length > 2; 127 if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { 128 if (context) iterator = _.bind(iterator, context); 129 return arguments.length > 2 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); 130 } 131 var length = obj.length; 132 if (length !== +length) { 133 var keys = _.keys(obj); 134 length = keys.length; 135 } 136 each(obj, function(value, index, list) { 137 index = keys ? keys[--length] : --length; 138 if (!initial) { 139 memo = obj[index]; 140 initial = true; 141 } else { 142 memo = iterator.call(context, memo, obj[index], index, list); 143 } 144 }); 145 if (!initial) throw new TypeError('Reduce of empty array with no initial value'); 146 return memo; 147 }; 148 149 // Return the first value which passes a truth test. Aliased as `detect`. 150 _.find = _.detect = function(obj, iterator, context) { 151 var result; 152 any(obj, function(value, index, list) { 153 if (iterator.call(context, value, index, list)) { 154 result = value; 155 return true; 156 } 157 }); 158 return result; 159 }; 160 161 // Return all the elements that pass a truth test. 162 // Delegates to **ECMAScript 5**'s native `filter` if available. 163 // Aliased as `select`. 164 _.filter = _.select = function(obj, iterator, context) { 165 var results = []; 166 if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); 167 each(obj, function(value, index, list) { 168 if (iterator.call(context, value, index, list)) results[results.length] = value; 169 }); 170 return results; 171 }; 172 173 // Return all the elements for which a truth test fails. 174 _.reject = function(obj, iterator, context) { 175 var results = []; 176 each(obj, function(value, index, list) { 177 if (!iterator.call(context, value, index, list)) results[results.length] = value; 178 }); 179 return results; 180 }; 181 182 // Determine whether all of the elements match a truth test. 183 // Delegates to **ECMAScript 5**'s native `every` if available. 184 // Aliased as `all`. 185 _.every = _.all = function(obj, iterator, context) { 186 iterator || (iterator = _.identity); 187 var result = true; 188 if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); 189 each(obj, function(value, index, list) { 190 if (!(result = result && iterator.call(context, value, index, list))) return breaker; 191 }); 192 return !!result; 193 }; 194 195 // Determine if at least one element in the object matches a truth test. 196 // Delegates to **ECMAScript 5**'s native `some` if available. 197 // Aliased as `any`. 198 var any = _.some = _.any = function(obj, iterator, context) { 199 iterator || (iterator = _.identity); 200 var result = false; 201 if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); 202 each(obj, function(value, index, list) { 203 if (result || (result = iterator.call(context, value, index, list))) return breaker; 204 }); 205 return !!result; 206 }; 207 208 // Determine if the array or object contains a given value (using `===`). 209 // Aliased as `include`. 210 _.contains = _.include = function(obj, target) { 211 var found = false; 212 if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; 213 found = any(obj, function(value) { 214 return value === target; 215 }); 216 return found; 217 }; 218 219 // Invoke a method (with arguments) on every item in a collection. 220 _.invoke = function(obj, method) { 221 var args = slice.call(arguments, 2); 222 return _.map(obj, function(value) { 223 return (_.isFunction(method) ? method : value[method]).apply(value, args); 224 }); 225 }; 226 227 // Convenience version of a common use case of `map`: fetching a property. 228 _.pluck = function(obj, key) { 229 return _.map(obj, function(value){ return value[key]; }); 230 }; 231 232 // Convenience version of a common use case of `filter`: selecting only objects 233 // with specific `key:value` pairs. 234 _.where = function(obj, attrs) { 235 if (_.isEmpty(attrs)) return []; 236 return _.filter(obj, function(value) { 237 for (var key in attrs) { 238 if (attrs[key] !== value[key]) return false; 239 } 240 return true; 241 }); 242 }; 243 244 // Return the maximum element or (element-based computation). 245 // Can't optimize arrays of integers longer than 65,535 elements. 246 // See: https://bugs.webkit.org/show_bug.cgi?id=80797 247 _.max = function(obj, iterator, context) { 248 if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { 249 return Math.max.apply(Math, obj); 250 } 251 if (!iterator && _.isEmpty(obj)) return -Infinity; 252 var result = {computed : -Infinity}; 253 each(obj, function(value, index, list) { 254 var computed = iterator ? iterator.call(context, value, index, list) : value; 255 computed >= result.computed && (result = {value : value, computed : computed}); 256 }); 257 return result.value; 258 }; 259 260 // Return the minimum element (or element-based computation). 261 _.min = function(obj, iterator, context) { 262 if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { 263 return Math.min.apply(Math, obj); 264 } 265 if (!iterator && _.isEmpty(obj)) return Infinity; 266 var result = {computed : Infinity}; 267 each(obj, function(value, index, list) { 268 var computed = iterator ? iterator.call(context, value, index, list) : value; 269 computed < result.computed && (result = {value : value, computed : computed}); 270 }); 271 return result.value; 272 }; 273 274 // Shuffle an array. 275 _.shuffle = function(obj) { 276 var rand; 277 var index = 0; 278 var shuffled = []; 279 each(obj, function(value) { 280 rand = _.random(index++); 281 shuffled[index - 1] = shuffled[rand]; 282 shuffled[rand] = value; 283 }); 284 return shuffled; 285 }; 286 287 // An internal function to generate lookup iterators. 288 var lookupIterator = function(value) { 289 return _.isFunction(value) ? value : function(obj){ return obj[value]; }; 290 }; 291 292 // Sort the object's values by a criterion produced by an iterator. 293 _.sortBy = function(obj, value, context) { 294 var iterator = lookupIterator(value); 295 return _.pluck(_.map(obj, function(value, index, list) { 296 return { 297 value : value, 298 index : index, 299 criteria : iterator.call(context, value, index, list) 300 }; 301 }).sort(function(left, right) { 302 var a = left.criteria; 303 var b = right.criteria; 304 if (a !== b) { 305 if (a > b || a === void 0) return 1; 306 if (a < b || b === void 0) return -1; 307 } 308 return left.index < right.index ? -1 : 1; 309 }), 'value'); 310 }; 311 312 // An internal function used for aggregate "group by" operations. 313 var group = function(obj, value, context, behavior) { 314 var result = {}; 315 var iterator = lookupIterator(value); 316 each(obj, function(value, index) { 317 var key = iterator.call(context, value, index, obj); 318 behavior(result, key, value); 319 }); 320 return result; 321 }; 322 323 // Groups the object's values by a criterion. Pass either a string attribute 324 // to group by, or a function that returns the criterion. 325 _.groupBy = function(obj, value, context) { 326 return group(obj, value, context, function(result, key, value) { 327 (_.has(result, key) ? result[key] : (result[key] = [])).push(value); 328 }); 329 }; 330 331 // Counts instances of an object that group by a certain criterion. Pass 332 // either a string attribute to count by, or a function that returns the 333 // criterion. 334 _.countBy = function(obj, value, context) { 335 return group(obj, value, context, function(result, key, value) { 336 if (!_.has(result, key)) result[key] = 0; 337 result[key]++; 338 }); 339 }; 340 341 // Use a comparator function to figure out the smallest index at which 342 // an object should be inserted so as to maintain order. Uses binary search. 343 _.sortedIndex = function(array, obj, iterator, context) { 344 iterator = iterator == null ? _.identity : lookupIterator(iterator); 345 var value = iterator.call(context, obj); 346 var low = 0, high = array.length; 347 while (low < high) { 348 var mid = (low + high) >>> 1; 349 iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid; 350 } 351 return low; 352 }; 353 354 // Safely convert anything iterable into a real, live array. 355 _.toArray = function(obj) { 356 if (!obj) return []; 357 if (obj.length === +obj.length) return slice.call(obj); 358 return _.values(obj); 359 }; 360 361 // Return the number of elements in an object. 362 _.size = function(obj) { 363 return (obj.length === +obj.length) ? obj.length : _.keys(obj).length; 364 }; 365 366 // Array Functions 367 // --------------- 368 369 // Get the first element of an array. Passing **n** will return the first N 370 // values in the array. Aliased as `head` and `take`. The **guard** check 371 // allows it to work with `_.map`. 372 _.first = _.head = _.take = function(array, n, guard) { 373 return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; 374 }; 375 376 // Returns everything but the last entry of the array. Especially useful on 377 // the arguments object. Passing **n** will return all the values in 378 // the array, excluding the last N. The **guard** check allows it to work with 379 // `_.map`. 380 _.initial = function(array, n, guard) { 381 return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); 382 }; 383 384 // Get the last element of an array. Passing **n** will return the last N 385 // values in the array. The **guard** check allows it to work with `_.map`. 386 _.last = function(array, n, guard) { 387 if ((n != null) && !guard) { 388 return slice.call(array, Math.max(array.length - n, 0)); 389 } else { 390 return array[array.length - 1]; 391 } 392 }; 393 394 // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. 395 // Especially useful on the arguments object. Passing an **n** will return 396 // the rest N values in the array. The **guard** 397 // check allows it to work with `_.map`. 398 _.rest = _.tail = _.drop = function(array, n, guard) { 399 return slice.call(array, (n == null) || guard ? 1 : n); 400 }; 401 402 // Trim out all falsy values from an array. 403 _.compact = function(array) { 404 return _.filter(array, function(value){ return !!value; }); 405 }; 406 407 // Internal implementation of a recursive `flatten` function. 408 var flatten = function(input, shallow, output) { 409 each(input, function(value) { 410 if (_.isArray(value)) { 411 shallow ? push.apply(output, value) : flatten(value, shallow, output); 412 } else { 413 output.push(value); 414 } 415 }); 416 return output; 417 }; 418 419 // Return a completely flattened version of an array. 420 _.flatten = function(array, shallow) { 421 return flatten(array, shallow, []); 422 }; 423 424 // Return a version of the array that does not contain the specified value(s). 425 _.without = function(array) { 426 return _.difference(array, slice.call(arguments, 1)); 427 }; 428 429 // Produce a duplicate-free version of the array. If the array has already 430 // been sorted, you have the option of using a faster algorithm. 431 // Aliased as `unique`. 432 _.uniq = _.unique = function(array, isSorted, iterator, context) { 433 var initial = iterator ? _.map(array, iterator, context) : array; 434 var results = []; 435 var seen = []; 436 each(initial, function(value, index) { 437 if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) { 438 seen.push(value); 439 results.push(array[index]); 440 } 441 }); 442 return results; 443 }; 444 445 // Produce an array that contains the union: each distinct element from all of 446 // the passed-in arrays. 447 _.union = function() { 448 return _.uniq(concat.apply(ArrayProto, arguments)); 449 }; 450 451 // Produce an array that contains every item shared between all the 452 // passed-in arrays. 453 _.intersection = function(array) { 454 var rest = slice.call(arguments, 1); 455 return _.filter(_.uniq(array), function(item) { 456 return _.every(rest, function(other) { 457 return _.indexOf(other, item) >= 0; 458 }); 459 }); 460 }; 461 462 // Take the difference between one array and a number of other arrays. 463 // Only the elements present in just the first array will remain. 464 _.difference = function(array) { 465 var rest = concat.apply(ArrayProto, slice.call(arguments, 1)); 466 return _.filter(array, function(value){ return !_.contains(rest, value); }); 467 }; 468 469 // Zip together multiple lists into a single array -- elements that share 470 // an index go together. 471 _.zip = function() { 472 var args = slice.call(arguments); 473 var length = _.max(_.pluck(args, 'length')); 474 var results = new Array(length); 475 for (var i = 0; i < length; i++) { 476 results[i] = _.pluck(args, "" + i); 477 } 478 return results; 479 }; 480 481 // Converts lists into objects. Pass either a single array of `[key, value]` 482 // pairs, or two parallel arrays of the same length -- one of keys, and one of 483 // the corresponding values. 484 _.object = function(list, values) { 485 var result = {}; 486 for (var i = 0, l = list.length; i < l; i++) { 487 if (values) { 488 result[list[i]] = values[i]; 489 } else { 490 result[list[i][0]] = list[i][1]; 491 } 492 } 493 return result; 494 }; 495 496 // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), 497 // we need this function. Return the position of the first occurrence of an 498 // item in an array, or -1 if the item is not included in the array. 499 // Delegates to **ECMAScript 5**'s native `indexOf` if available. 500 // If the array is large and already in sort order, pass `true` 501 // for **isSorted** to use binary search. 502 _.indexOf = function(array, item, isSorted) { 503 var i = 0, l = array.length; 504 if (isSorted) { 505 if (typeof isSorted == 'number') { 506 i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted); 507 } else { 508 i = _.sortedIndex(array, item); 509 return array[i] === item ? i : -1; 510 } 511 } 512 if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted); 513 for (; i < l; i++) if (array[i] === item) return i; 514 return -1; 515 }; 516 517 // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. 518 _.lastIndexOf = function(array, item, from) { 519 var hasIndex = from != null; 520 if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) { 521 return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item); 522 } 523 var i = (hasIndex ? from : array.length); 524 while (i--) if (array[i] === item) return i; 525 return -1; 526 }; 527 528 // Generate an integer Array containing an arithmetic progression. A port of 529 // the native Python `range()` function. See 530 // [the Python documentation](http://docs.python.org/library/functions.html#range). 531 _.range = function(start, stop, step) { 532 if (arguments.length <= 1) { 533 stop = start || 0; 534 start = 0; 535 } 536 step = arguments[2] || 1; 537 538 var len = Math.max(Math.ceil((stop - start) / step), 0); 539 var idx = 0; 540 var range = new Array(len); 541 542 while(idx < len) { 543 range[idx++] = start; 544 start += step; 545 } 546 547 return range; 548 }; 549 550 // Function (ahem) Functions 551 // ------------------ 552 553 // Reusable constructor function for prototype setting. 554 var ctor = function(){}; 555 556 // Create a function bound to a given object (assigning `this`, and arguments, 557 // optionally). Binding with arguments is also known as `curry`. 558 // Delegates to **ECMAScript 5**'s native `Function.bind` if available. 559 // We check for `func.bind` first, to fail fast when `func` is undefined. 560 _.bind = function bind(func, context) { 561 var bound, args; 562 if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); 563 if (!_.isFunction(func)) throw new TypeError; 564 args = slice.call(arguments, 2); 565 return bound = function() { 566 if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); 567 ctor.prototype = func.prototype; 568 var self = new ctor; 569 var result = func.apply(self, args.concat(slice.call(arguments))); 570 if (Object(result) === result) return result; 571 return self; 572 }; 573 }; 574 575 // Bind all of an object's methods to that object. Useful for ensuring that 576 // all callbacks defined on an object belong to it. 577 _.bindAll = function(obj) { 578 var funcs = slice.call(arguments, 1); 579 if (funcs.length == 0) funcs = _.functions(obj); 580 each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); 581 return obj; 582 }; 583 584 // Memoize an expensive function by storing its results. 585 _.memoize = function(func, hasher) { 586 var memo = {}; 587 hasher || (hasher = _.identity); 588 return function() { 589 var key = hasher.apply(this, arguments); 590 return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); 591 }; 592 }; 593 594 // Delays a function for the given number of milliseconds, and then calls 595 // it with the arguments supplied. 596 _.delay = function(func, wait) { 597 var args = slice.call(arguments, 2); 598 return setTimeout(function(){ return func.apply(null, args); }, wait); 599 }; 600 601 // Defers a function, scheduling it to run after the current call stack has 602 // cleared. 603 _.defer = function(func) { 604 return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); 605 }; 606 607 // Returns a function, that, when invoked, will only be triggered at most once 608 // during a given window of time. 609 _.throttle = function(func, wait) { 610 var context, args, timeout, throttling, more, result; 611 var whenDone = _.debounce(function(){ more = throttling = false; }, wait); 612 return function() { 613 context = this; args = arguments; 614 var later = function() { 615 timeout = null; 616 if (more) { 617 result = func.apply(context, args); 618 } 619 whenDone(); 620 }; 621 if (!timeout) timeout = setTimeout(later, wait); 622 if (throttling) { 623 more = true; 624 } else { 625 throttling = true; 626 result = func.apply(context, args); 627 } 628 whenDone(); 629 return result; 630 }; 631 }; 632 633 // Returns a function, that, as long as it continues to be invoked, will not 634 // be triggered. The function will be called after it stops being called for 635 // N milliseconds. If `immediate` is passed, trigger the function on the 636 // leading edge, instead of the trailing. 637 _.debounce = function(func, wait, immediate) { 638 var timeout, result; 639 return function() { 640 var context = this, args = arguments; 641 var later = function() { 642 timeout = null; 643 if (!immediate) result = func.apply(context, args); 644 }; 645 var callNow = immediate && !timeout; 646 clearTimeout(timeout); 647 timeout = setTimeout(later, wait); 648 if (callNow) result = func.apply(context, args); 649 return result; 650 }; 651 }; 652 653 // Returns a function that will be executed at most one time, no matter how 654 // often you call it. Useful for lazy initialization. 655 _.once = function(func) { 656 var ran = false, memo; 657 return function() { 658 if (ran) return memo; 659 ran = true; 660 memo = func.apply(this, arguments); 661 func = null; 662 return memo; 663 }; 664 }; 665 666 // Returns the first function passed as an argument to the second, 667 // allowing you to adjust arguments, run code before and after, and 668 // conditionally execute the original function. 669 _.wrap = function(func, wrapper) { 670 return function() { 671 var args = [func]; 672 push.apply(args, arguments); 673 return wrapper.apply(this, args); 674 }; 675 }; 676 677 // Returns a function that is the composition of a list of functions, each 678 // consuming the return value of the function that follows. 679 _.compose = function() { 680 var funcs = arguments; 681 return function() { 682 var args = arguments; 683 for (var i = funcs.length - 1; i >= 0; i--) { 684 args = [funcs[i].apply(this, args)]; 685 } 686 return args[0]; 687 }; 688 }; 689 690 // Returns a function that will only be executed after being called N times. 691 _.after = function(times, func) { 692 if (times <= 0) return func(); 693 return function() { 694 if (--times < 1) { 695 return func.apply(this, arguments); 696 } 697 }; 698 }; 699 700 // Object Functions 701 // ---------------- 702 703 // Retrieve the names of an object's properties. 704 // Delegates to **ECMAScript 5**'s native `Object.keys` 705 _.keys = nativeKeys || function(obj) { 706 if (obj !== Object(obj)) throw new TypeError('Invalid object'); 707 var keys = []; 708 for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; 709 return keys; 710 }; 711 712 // Retrieve the values of an object's properties. 713 _.values = function(obj) { 714 var values = []; 715 for (var key in obj) if (_.has(obj, key)) values.push(obj[key]); 716 return values; 717 }; 718 719 // Convert an object into a list of `[key, value]` pairs. 720 _.pairs = function(obj) { 721 var pairs = []; 722 for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]); 723 return pairs; 724 }; 725 726 // Invert the keys and values of an object. The values must be serializable. 727 _.invert = function(obj) { 728 var result = {}; 729 for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key; 730 return result; 731 }; 732 733 // Return a sorted list of the function names available on the object. 734 // Aliased as `methods` 735 _.functions = _.methods = function(obj) { 736 var names = []; 737 for (var key in obj) { 738 if (_.isFunction(obj[key])) names.push(key); 739 } 740 return names.sort(); 741 }; 742 743 // Extend a given object with all the properties in passed-in object(s). 744 _.extend = function(obj) { 745 each(slice.call(arguments, 1), function(source) { 746 for (var prop in source) { 747 obj[prop] = source[prop]; 748 } 749 }); 750 return obj; 751 }; 752 753 // Return a copy of the object only containing the whitelisted properties. 754 _.pick = function(obj) { 755 var copy = {}; 756 var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); 757 each(keys, function(key) { 758 if (key in obj) copy[key] = obj[key]; 759 }); 760 return copy; 761 }; 762 763 // Return a copy of the object without the blacklisted properties. 764 _.omit = function(obj) { 765 var copy = {}; 766 var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); 767 for (var key in obj) { 768 if (!_.contains(keys, key)) copy[key] = obj[key]; 769 } 770 return copy; 771 }; 772 773 // Fill in a given object with default properties. 774 _.defaults = function(obj) { 775 each(slice.call(arguments, 1), function(source) { 776 for (var prop in source) { 777 if (obj[prop] == null) obj[prop] = source[prop]; 778 } 779 }); 780 return obj; 781 }; 782 783 // Create a (shallow-cloned) duplicate of an object. 784 _.clone = function(obj) { 785 if (!_.isObject(obj)) return obj; 786 return _.isArray(obj) ? obj.slice() : _.extend({}, obj); 787 }; 788 789 // Invokes interceptor with the obj, and then returns obj. 790 // The primary purpose of this method is to "tap into" a method chain, in 791 // order to perform operations on intermediate results within the chain. 792 _.tap = function(obj, interceptor) { 793 interceptor(obj); 794 return obj; 795 }; 796 797 // Internal recursive comparison function for `isEqual`. 798 var eq = function(a, b, aStack, bStack) { 799 // Identical objects are equal. `0 === -0`, but they aren't identical. 800 // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal. 801 if (a === b) return a !== 0 || 1 / a == 1 / b; 802 // A strict comparison is necessary because `null == undefined`. 803 if (a == null || b == null) return a === b; 804 // Unwrap any wrapped objects. 805 if (a instanceof _) a = a._wrapped; 806 if (b instanceof _) b = b._wrapped; 807 // Compare `[[Class]]` names. 808 var className = toString.call(a); 809 if (className != toString.call(b)) return false; 810 switch (className) { 811 // Strings, numbers, dates, and booleans are compared by value. 812 case '[object String]': 813 // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is 814 // equivalent to `new String("5")`. 815 return a == String(b); 816 case '[object Number]': 817 // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for 818 // other numeric values. 819 return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); 820 case '[object Date]': 821 case '[object Boolean]': 822 // Coerce dates and booleans to numeric primitive values. Dates are compared by their 823 // millisecond representations. Note that invalid dates with millisecond representations 824 // of `NaN` are not equivalent. 825 return +a == +b; 826 // RegExps are compared by their source patterns and flags. 827 case '[object RegExp]': 828 return a.source == b.source && 829 a.global == b.global && 830 a.multiline == b.multiline && 831 a.ignoreCase == b.ignoreCase; 832 } 833 if (typeof a != 'object' || typeof b != 'object') return false; 834 // Assume equality for cyclic structures. The algorithm for detecting cyclic 835 // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. 836 var length = aStack.length; 837 while (length--) { 838 // Linear search. Performance is inversely proportional to the number of 839 // unique nested structures. 840 if (aStack[length] == a) return bStack[length] == b; 841 } 842 // Add the first object to the stack of traversed objects. 843 aStack.push(a); 844 bStack.push(b); 845 var size = 0, result = true; 846 // Recursively compare objects and arrays. 847 if (className == '[object Array]') { 848 // Compare array lengths to determine if a deep comparison is necessary. 849 size = a.length; 850 result = size == b.length; 851 if (result) { 852 // Deep compare the contents, ignoring non-numeric properties. 853 while (size--) { 854 if (!(result = eq(a[size], b[size], aStack, bStack))) break; 855 } 856 } 857 } else { 858 // Objects with different constructors are not equivalent, but `Object`s 859 // from different frames are. 860 var aCtor = a.constructor, bCtor = b.constructor; 861 if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) && 862 _.isFunction(bCtor) && (bCtor instanceof bCtor))) { 863 return false; 864 } 865 // Deep compare objects. 866 for (var key in a) { 867 if (_.has(a, key)) { 868 // Count the expected number of properties. 869 size++; 870 // Deep compare each member. 871 if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break; 872 } 873 } 874 // Ensure that both objects contain the same number of properties. 875 if (result) { 876 for (key in b) { 877 if (_.has(b, key) && !(size--)) break; 878 } 879 result = !size; 880 } 881 } 882 // Remove the first object from the stack of traversed objects. 883 aStack.pop(); 884 bStack.pop(); 885 return result; 886 }; 887 888 // Perform a deep comparison to check if two objects are equal. 889 _.isEqual = function(a, b) { 890 return eq(a, b, [], []); 891 }; 892 893 // Is a given array, string, or object empty? 894 // An "empty" object has no enumerable own-properties. 895 _.isEmpty = function(obj) { 896 if (obj == null) return true; 897 if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; 898 for (var key in obj) if (_.has(obj, key)) return false; 899 return true; 900 }; 901 902 // Is a given value a DOM element? 903 _.isElement = function(obj) { 904 return !!(obj && obj.nodeType === 1); 905 }; 906 907 // Is a given value an array? 908 // Delegates to ECMA5's native Array.isArray 909 _.isArray = nativeIsArray || function(obj) { 910 return toString.call(obj) == '[object Array]'; 911 }; 912 913 // Is a given variable an object? 914 _.isObject = function(obj) { 915 return obj === Object(obj); 916 }; 917 918 // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp. 919 each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) { 920 _['is' + name] = function(obj) { 921 return toString.call(obj) == '[object ' + name + ']'; 922 }; 923 }); 924 925 // Define a fallback version of the method in browsers (ahem, IE), where 926 // there isn't any inspectable "Arguments" type. 927 if (!_.isArguments(arguments)) { 928 _.isArguments = function(obj) { 929 return !!(obj && _.has(obj, 'callee')); 930 }; 931 } 932 933 // Optimize `isFunction` if appropriate. 934 if (typeof (/./) !== 'function') { 935 _.isFunction = function(obj) { 936 return typeof obj === 'function'; 937 }; 938 } 939 940 // Is a given object a finite number? 941 _.isFinite = function(obj) { 942 return _.isNumber(obj) && isFinite(obj); 943 }; 944 945 // Is the given value `NaN`? (NaN is the only number which does not equal itself). 946 _.isNaN = function(obj) { 947 return _.isNumber(obj) && obj != +obj; 948 }; 949 950 // Is a given value a boolean? 951 _.isBoolean = function(obj) { 952 return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; 953 }; 954 955 // Is a given value equal to null? 956 _.isNull = function(obj) { 957 return obj === null; 958 }; 959 960 // Is a given variable undefined? 961 _.isUndefined = function(obj) { 962 return obj === void 0; 963 }; 964 965 // Shortcut function for checking if an object has a given property directly 966 // on itself (in other words, not on a prototype). 967 _.has = function(obj, key) { 968 return hasOwnProperty.call(obj, key); 969 }; 970 971 // Utility Functions 972 // ----------------- 973 974 // Run Underscore.js in *noConflict* mode, returning the `_` variable to its 975 // previous owner. Returns a reference to the Underscore object. 976 _.noConflict = function() { 977 root._ = previousUnderscore; 978 return this; 979 }; 980 981 // Keep the identity function around for default iterators. 982 _.identity = function(value) { 983 return value; 984 }; 985 986 // Run a function **n** times. 987 _.times = function(n, iterator, context) { 988 for (var i = 0; i < n; i++) iterator.call(context, i); 989 }; 990 991 // Return a random integer between min and max (inclusive). 992 _.random = function(min, max) { 993 if (max == null) { 994 max = min; 995 min = 0; 996 } 997 return min + (0 | Math.random() * (max - min + 1)); 998 }; 999 1000 // List of HTML entities for escaping. 1001 var entityMap = { 1002 escape: { 1003 '&': '&', 1004 '<': '<', 1005 '>': '>', 1006 '"': '"', 1007 "'": ''', 1008 '/': '/' 1009 } 1010 }; 1011 entityMap.unescape = _.invert(entityMap.escape); 1012 1013 // Regexes containing the keys and values listed immediately above. 1014 var entityRegexes = { 1015 escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'), 1016 unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g') 1017 }; 1018 1019 // Functions for escaping and unescaping strings to/from HTML interpolation. 1020 _.each(['escape', 'unescape'], function(method) { 1021 _[method] = function(string) { 1022 if (string == null) return ''; 1023 return ('' + string).replace(entityRegexes[method], function(match) { 1024 return entityMap[method][match]; 1025 }); 1026 }; 1027 }); 1028 1029 // If the value of the named property is a function then invoke it; 1030 // otherwise, return it. 1031 _.result = function(object, property) { 1032 if (object == null) return null; 1033 var value = object[property]; 1034 return _.isFunction(value) ? value.call(object) : value; 1035 }; 1036 1037 // Add your own custom functions to the Underscore object. 1038 _.mixin = function(obj) { 1039 each(_.functions(obj), function(name){ 1040 var func = _[name] = obj[name]; 1041 _.prototype[name] = function() { 1042 var args = [this._wrapped]; 1043 push.apply(args, arguments); 1044 return result.call(this, func.apply(_, args)); 1045 }; 1046 }); 1047 }; 1048 1049 // Generate a unique integer id (unique within the entire client session). 1050 // Useful for temporary DOM ids. 1051 var idCounter = 0; 1052 _.uniqueId = function(prefix) { 1053 var id = idCounter++; 1054 return prefix ? prefix + id : id; 1055 }; 1056 1057 // By default, Underscore uses ERB-style template delimiters, change the 1058 // following template settings to use alternative delimiters. 1059 _.templateSettings = { 1060 evaluate : /<%([\s\S]+?)%>/g, 1061 interpolate : /<%=([\s\S]+?)%>/g, 1062 escape : /<%-([\s\S]+?)%>/g 1063 }; 1064 1065 // When customizing `templateSettings`, if you don't want to define an 1066 // interpolation, evaluation or escaping regex, we need one that is 1067 // guaranteed not to match. 1068 var noMatch = /(.)^/; 1069 1070 // Certain characters need to be escaped so that they can be put into a 1071 // string literal. 1072 var escapes = { 1073 "'": "'", 1074 '\\': '\\', 1075 '\r': 'r', 1076 '\n': 'n', 1077 '\t': 't', 1078 '\u2028': 'u2028', 1079 '\u2029': 'u2029' 1080 }; 1081 1082 var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; 1083 1084 // JavaScript micro-templating, similar to John Resig's implementation. 1085 // Underscore templating handles arbitrary delimiters, preserves whitespace, 1086 // and correctly escapes quotes within interpolated code. 1087 _.template = function(text, data, settings) { 1088 settings = _.defaults({}, settings, _.templateSettings); 1089 1090 // Combine delimiters into one regular expression via alternation. 1091 var matcher = new RegExp([ 1092 (settings.escape || noMatch).source, 1093 (settings.interpolate || noMatch).source, 1094 (settings.evaluate || noMatch).source 1095 ].join('|') + '|$', 'g'); 1096 1097 // Compile the template source, escaping string literals appropriately. 1098 var index = 0; 1099 var source = "__p+='"; 1100 text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { 1101 source += text.slice(index, offset) 1102 .replace(escaper, function(match) { return '\\' + escapes[match]; }); 1103 source += 1104 escape ? "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'" : 1105 interpolate ? "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'" : 1106 evaluate ? "';\n" + evaluate + "\n__p+='" : ''; 1107 index = offset + match.length; 1108 }); 1109 source += "';\n"; 1110 1111 // If a variable is not specified, place data values in local scope. 1112 if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; 1113 1114 source = "var __t,__p='',__j=Array.prototype.join," + 1115 "print=function(){__p+=__j.call(arguments,'');};\n" + 1116 source + "return __p;\n"; 1117 1118 try { 1119 var render = new Function(settings.variable || 'obj', '_', source); 1120 } catch (e) { 1121 e.source = source; 1122 throw e; 1123 } 1124 1125 if (data) return render(data, _); 1126 var template = function(data) { 1127 return render.call(this, data, _); 1128 }; 1129 1130 // Provide the compiled function source as a convenience for precompilation. 1131 template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; 1132 1133 return template; 1134 }; 1135 1136 // Add a "chain" function, which will delegate to the wrapper. 1137 _.chain = function(obj) { 1138 return _(obj).chain(); 1139 }; 1140 1141 // OOP 1142 // --------------- 1143 // If Underscore is called as a function, it returns a wrapped object that 1144 // can be used OO-style. This wrapper holds altered versions of all the 1145 // underscore functions. Wrapped objects may be chained. 1146 1147 // Helper function to continue chaining intermediate results. 1148 var result = function(obj) { 1149 return this._chain ? _(obj).chain() : obj; 1150 }; 1151 1152 // Add all of the Underscore functions to the wrapper object. 1153 _.mixin(_); 1154 1155 // Add all mutator Array functions to the wrapper. 1156 each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { 1157 var method = ArrayProto[name]; 1158 _.prototype[name] = function() { 1159 var obj = this._wrapped; 1160 method.apply(obj, arguments); 1161 if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0]; 1162 return result.call(this, obj); 1163 }; 1164 }); 1165 1166 // Add all accessor Array functions to the wrapper. 1167 each(['concat', 'join', 'slice'], function(name) { 1168 var method = ArrayProto[name]; 1169 _.prototype[name] = function() { 1170 return result.call(this, method.apply(this._wrapped, arguments)); 1171 }; 1172 }); 1173 1174 _.extend(_.prototype, { 1175 1176 // Start chaining a wrapped Underscore object. 1177 chain: function() { 1178 this._chain = true; 1179 return this; 1180 }, 1181 1182 // Extracts the result from a wrapped and chained object. 1183 value: function() { 1184 return this._wrapped; 1185 } 1186 1187 }); 1188 1189 }).call(this);// Underscore.js 1.4.1 2 // http://underscorejs.org 3 // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. 4 // Underscore may be freely distributed under the MIT license. 5 6 (function() { 7 8 // Baseline setup 9 // -------------- 10 11 // Establish the root object, `window` in the browser, or `global` on the server. 12 var root = this; 13 14 // Save the previous value of the `_` variable. 15 var previousUnderscore = root._; 16 17 // Establish the object that gets returned to break out of a loop iteration. 18 var breaker = {}; 19 20 // Save bytes in the minified (but not gzipped) version: 21 var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; 22 23 // Create quick reference variables for speed access to core prototypes. 24 var push = ArrayProto.push, 25 slice = ArrayProto.slice, 26 concat = ArrayProto.concat, 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 nativeBind = FuncProto.bind; 46 47 // Create a safe reference to the Underscore object for use below. 48 var _ = function(obj) { 49 if (obj instanceof _) return obj; 50 if (!(this instanceof _)) return new _(obj); 51 this._wrapped = obj; 52 }; 53 54 // Export the Underscore object for **Node.js**, with 55 // backwards-compatibility for the old `require()` API. If we're in 56 // the browser, add `_` as a global object via a string identifier, 57 // for Closure Compiler "advanced" mode. 58 if (typeof exports !== 'undefined') { 59 if (typeof module !== 'undefined' && module.exports) { 60 exports = module.exports = _; 61 } 62 exports._ = _; 63 } else { 64 root['_'] = _; 65 } 66 67 // Current version. 68 _.VERSION = '1.4.1'; 69 70 // Collection Functions 71 // -------------------- 72 73 // The cornerstone, an `each` implementation, aka `forEach`. 74 // Handles objects with the built-in `forEach`, arrays, and raw objects. 75 // Delegates to **ECMAScript 5**'s native `forEach` if available. 76 var each = _.each = _.forEach = function(obj, iterator, context) { 77 if (nativeForEach && obj.forEach === nativeForEach) { 78 obj.forEach(iterator, context); 79 } else if (obj.length === +obj.length) { 80 for (var i = 0, l = obj.length; i < l; i++) { 81 if (iterator.call(context, obj[i], i, obj) === breaker) return; 82 } 83 } else { 84 for (var key in obj) { 85 if (_.has(obj, key)) { 86 if (iterator.call(context, obj[key], key, obj) === breaker) return; 87 } 88 } 89 } 90 }; 91 92 // Return the results of applying the iterator to each element. 93 // Delegates to **ECMAScript 5**'s native `map` if available. 94 _.map = _.collect = function(obj, iterator, context) { 95 var results = []; 96 if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); 97 each(obj, function(value, index, list) { 98 results[results.length] = iterator.call(context, value, index, list); 99 }); 100 return results; 101 }; 102 103 // **Reduce** builds up a single result from a list of values, aka `inject`, 104 // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. 105 _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { 106 var initial = arguments.length > 2; 107 if (nativeReduce && obj.reduce === nativeReduce) { 108 if (context) iterator = _.bind(iterator, context); 109 return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); 110 } 111 each(obj, function(value, index, list) { 112 if (!initial) { 113 memo = value; 114 initial = true; 115 } else { 116 memo = iterator.call(context, memo, value, index, list); 117 } 118 }); 119 if (!initial) throw new TypeError('Reduce of empty array with no initial value'); 120 return memo; 121 }; 122 123 // The right-associative version of reduce, also known as `foldr`. 124 // Delegates to **ECMAScript 5**'s native `reduceRight` if available. 125 _.reduceRight = _.foldr = function(obj, iterator, memo, context) { 126 var initial = arguments.length > 2; 127 if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { 128 if (context) iterator = _.bind(iterator, context); 129 return arguments.length > 2 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); 130 } 131 var length = obj.length; 132 if (length !== +length) { 133 var keys = _.keys(obj); 134 length = keys.length; 135 } 136 each(obj, function(value, index, list) { 137 index = keys ? keys[--length] : --length; 138 if (!initial) { 139 memo = obj[index]; 140 initial = true; 141 } else { 142 memo = iterator.call(context, memo, obj[index], index, list); 143 } 144 }); 145 if (!initial) throw new TypeError('Reduce of empty array with no initial value'); 146 return memo; 147 }; 148 149 // Return the first value which passes a truth test. Aliased as `detect`. 150 _.find = _.detect = function(obj, iterator, context) { 151 var result; 152 any(obj, function(value, index, list) { 153 if (iterator.call(context, value, index, list)) { 154 result = value; 155 return true; 156 } 157 }); 158 return result; 159 }; 160 161 // Return all the elements that pass a truth test. 162 // Delegates to **ECMAScript 5**'s native `filter` if available. 163 // Aliased as `select`. 164 _.filter = _.select = function(obj, iterator, context) { 165 var results = []; 166 if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); 167 each(obj, function(value, index, list) { 168 if (iterator.call(context, value, index, list)) results[results.length] = value; 169 }); 170 return results; 171 }; 172 173 // Return all the elements for which a truth test fails. 174 _.reject = function(obj, iterator, context) { 175 var results = []; 176 each(obj, function(value, index, list) { 177 if (!iterator.call(context, value, index, list)) results[results.length] = value; 178 }); 179 return results; 180 }; 181 182 // Determine whether all of the elements match a truth test. 183 // Delegates to **ECMAScript 5**'s native `every` if available. 184 // Aliased as `all`. 185 _.every = _.all = function(obj, iterator, context) { 186 iterator || (iterator = _.identity); 187 var result = true; 188 if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); 189 each(obj, function(value, index, list) { 190 if (!(result = result && iterator.call(context, value, index, list))) return breaker; 191 }); 192 return !!result; 193 }; 194 195 // Determine if at least one element in the object matches a truth test. 196 // Delegates to **ECMAScript 5**'s native `some` if available. 197 // Aliased as `any`. 198 var any = _.some = _.any = function(obj, iterator, context) { 199 iterator || (iterator = _.identity); 200 var result = false; 201 if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); 202 each(obj, function(value, index, list) { 203 if (result || (result = iterator.call(context, value, index, list))) return breaker; 204 }); 205 return !!result; 206 }; 207 208 // Determine if the array or object contains a given value (using `===`). 209 // Aliased as `include`. 210 _.contains = _.include = function(obj, target) { 211 var found = false; 212 if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; 213 found = any(obj, function(value) { 214 return value === target; 215 }); 216 return found; 217 }; 218 219 // Invoke a method (with arguments) on every item in a collection. 220 _.invoke = function(obj, method) { 221 var args = slice.call(arguments, 2); 222 return _.map(obj, function(value) { 223 return (_.isFunction(method) ? method : value[method]).apply(value, args); 224 }); 225 }; 226 227 // Convenience version of a common use case of `map`: fetching a property. 228 _.pluck = function(obj, key) { 229 return _.map(obj, function(value){ return value[key]; }); 230 }; 231 232 // Convenience version of a common use case of `filter`: selecting only objects 233 // with specific `key:value` pairs. 234 _.where = function(obj, attrs) { 235 if (_.isEmpty(attrs)) return []; 236 return _.filter(obj, function(value) { 237 for (var key in attrs) { 238 if (attrs[key] !== value[key]) return false; 239 } 240 return true; 241 }); 242 }; 243 244 // Return the maximum element or (element-based computation). 245 // Can't optimize arrays of integers longer than 65,535 elements. 246 // See: https://bugs.webkit.org/show_bug.cgi?id=80797 247 _.max = function(obj, iterator, context) { 248 if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { 249 return Math.max.apply(Math, obj); 250 } 251 if (!iterator && _.isEmpty(obj)) return -Infinity; 252 var result = {computed : -Infinity}; 253 each(obj, function(value, index, list) { 254 var computed = iterator ? iterator.call(context, value, index, list) : value; 255 computed >= result.computed && (result = {value : value, computed : computed}); 256 }); 257 return result.value; 258 }; 259 260 // Return the minimum element (or element-based computation). 261 _.min = function(obj, iterator, context) { 262 if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { 263 return Math.min.apply(Math, obj); 264 } 265 if (!iterator && _.isEmpty(obj)) return Infinity; 266 var result = {computed : Infinity}; 267 each(obj, function(value, index, list) { 268 var computed = iterator ? iterator.call(context, value, index, list) : value; 269 computed < result.computed && (result = {value : value, computed : computed}); 270 }); 271 return result.value; 272 }; 273 274 // Shuffle an array. 275 _.shuffle = function(obj) { 276 var rand; 277 var index = 0; 278 var shuffled = []; 279 each(obj, function(value) { 280 rand = _.random(index++); 281 shuffled[index - 1] = shuffled[rand]; 282 shuffled[rand] = value; 283 }); 284 return shuffled; 285 }; 286 287 // An internal function to generate lookup iterators. 288 var lookupIterator = function(value) { 289 return _.isFunction(value) ? value : function(obj){ return obj[value]; }; 290 }; 291 292 // Sort the object's values by a criterion produced by an iterator. 293 _.sortBy = function(obj, value, context) { 294 var iterator = lookupIterator(value); 295 return _.pluck(_.map(obj, function(value, index, list) { 296 return { 297 value : value, 298 index : index, 299 criteria : iterator.call(context, value, index, list) 300 }; 301 }).sort(function(left, right) { 302 var a = left.criteria; 303 var b = right.criteria; 304 if (a !== b) { 305 if (a > b || a === void 0) return 1; 306 if (a < b || b === void 0) return -1; 307 } 308 return left.index < right.index ? -1 : 1; 309 }), 'value'); 310 }; 311 312 // An internal function used for aggregate "group by" operations. 313 var group = function(obj, value, context, behavior) { 314 var result = {}; 315 var iterator = lookupIterator(value); 316 each(obj, function(value, index) { 317 var key = iterator.call(context, value, index, obj); 318 behavior(result, key, value); 319 }); 320 return result; 321 }; 322 323 // Groups the object's values by a criterion. Pass either a string attribute 324 // to group by, or a function that returns the criterion. 325 _.groupBy = function(obj, value, context) { 326 return group(obj, value, context, function(result, key, value) { 327 (_.has(result, key) ? result[key] : (result[key] = [])).push(value); 328 }); 329 }; 330 331 // Counts instances of an object that group by a certain criterion. Pass 332 // either a string attribute to count by, or a function that returns the 333 // criterion. 334 _.countBy = function(obj, value, context) { 335 return group(obj, value, context, function(result, key, value) { 336 if (!_.has(result, key)) result[key] = 0; 337 result[key]++; 338 }); 339 }; 340 341 // Use a comparator function to figure out the smallest index at which 342 // an object should be inserted so as to maintain order. Uses binary search. 343 _.sortedIndex = function(array, obj, iterator, context) { 344 iterator = iterator == null ? _.identity : lookupIterator(iterator); 345 var value = iterator.call(context, obj); 346 var low = 0, high = array.length; 347 while (low < high) { 348 var mid = (low + high) >>> 1; 349 iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid; 350 } 351 return low; 352 }; 353 354 // Safely convert anything iterable into a real, live array. 355 _.toArray = function(obj) { 356 if (!obj) return []; 357 if (obj.length === +obj.length) return slice.call(obj); 358 return _.values(obj); 359 }; 360 361 // Return the number of elements in an object. 362 _.size = function(obj) { 363 return (obj.length === +obj.length) ? obj.length : _.keys(obj).length; 364 }; 365 366 // Array Functions 367 // --------------- 368 369 // Get the first element of an array. Passing **n** will return the first N 370 // values in the array. Aliased as `head` and `take`. The **guard** check 371 // allows it to work with `_.map`. 372 _.first = _.head = _.take = function(array, n, guard) { 373 return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; 374 }; 375 376 // Returns everything but the last entry of the array. Especially useful on 377 // the arguments object. Passing **n** will return all the values in 378 // the array, excluding the last N. The **guard** check allows it to work with 379 // `_.map`. 380 _.initial = function(array, n, guard) { 381 return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); 382 }; 383 384 // Get the last element of an array. Passing **n** will return the last N 385 // values in the array. The **guard** check allows it to work with `_.map`. 386 _.last = function(array, n, guard) { 387 if ((n != null) && !guard) { 388 return slice.call(array, Math.max(array.length - n, 0)); 389 } else { 390 return array[array.length - 1]; 391 } 392 }; 393 394 // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. 395 // Especially useful on the arguments object. Passing an **n** will return 396 // the rest N values in the array. The **guard** 397 // check allows it to work with `_.map`. 398 _.rest = _.tail = _.drop = function(array, n, guard) { 399 return slice.call(array, (n == null) || guard ? 1 : n); 400 }; 401 402 // Trim out all falsy values from an array. 403 _.compact = function(array) { 404 return _.filter(array, function(value){ return !!value; }); 405 }; 406 407 // Internal implementation of a recursive `flatten` function. 408 var flatten = function(input, shallow, output) { 409 each(input, function(value) { 410 if (_.isArray(value)) { 411 shallow ? push.apply(output, value) : flatten(value, shallow, output); 412 } else { 413 output.push(value); 414 } 415 }); 416 return output; 417 }; 418 419 // Return a completely flattened version of an array. 420 _.flatten = function(array, shallow) { 421 return flatten(array, shallow, []); 422 }; 423 424 // Return a version of the array that does not contain the specified value(s). 425 _.without = function(array) { 426 return _.difference(array, slice.call(arguments, 1)); 427 }; 428 429 // Produce a duplicate-free version of the array. If the array has already 430 // been sorted, you have the option of using a faster algorithm. 431 // Aliased as `unique`. 432 _.uniq = _.unique = function(array, isSorted, iterator, context) { 433 var initial = iterator ? _.map(array, iterator, context) : array; 434 var results = []; 435 var seen = []; 436 each(initial, function(value, index) { 437 if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) { 438 seen.push(value); 439 results.push(array[index]); 440 } 441 }); 442 return results; 443 }; 444 445 // Produce an array that contains the union: each distinct element from all of 446 // the passed-in arrays. 447 _.union = function() { 448 return _.uniq(concat.apply(ArrayProto, arguments)); 449 }; 450 451 // Produce an array that contains every item shared between all the 452 // passed-in arrays. 453 _.intersection = function(array) { 454 var rest = slice.call(arguments, 1); 455 return _.filter(_.uniq(array), function(item) { 456 return _.every(rest, function(other) { 457 return _.indexOf(other, item) >= 0; 458 }); 459 }); 460 }; 461 462 // Take the difference between one array and a number of other arrays. 463 // Only the elements present in just the first array will remain. 464 _.difference = function(array) { 465 var rest = concat.apply(ArrayProto, slice.call(arguments, 1)); 466 return _.filter(array, function(value){ return !_.contains(rest, value); }); 467 }; 468 469 // Zip together multiple lists into a single array -- elements that share 470 // an index go together. 471 _.zip = function() { 472 var args = slice.call(arguments); 473 var length = _.max(_.pluck(args, 'length')); 474 var results = new Array(length); 475 for (var i = 0; i < length; i++) { 476 results[i] = _.pluck(args, "" + i); 477 } 478 return results; 479 }; 480 481 // Converts lists into objects. Pass either a single array of `[key, value]` 482 // pairs, or two parallel arrays of the same length -- one of keys, and one of 483 // the corresponding values. 484 _.object = function(list, values) { 485 var result = {}; 486 for (var i = 0, l = list.length; i < l; i++) { 487 if (values) { 488 result[list[i]] = values[i]; 489 } else { 490 result[list[i][0]] = list[i][1]; 491 } 492 } 493 return result; 494 }; 495 496 // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), 497 // we need this function. Return the position of the first occurrence of an 498 // item in an array, or -1 if the item is not included in the array. 499 // Delegates to **ECMAScript 5**'s native `indexOf` if available. 500 // If the array is large and already in sort order, pass `true` 501 // for **isSorted** to use binary search. 502 _.indexOf = function(array, item, isSorted) { 503 var i = 0, l = array.length; 504 if (isSorted) { 505 if (typeof isSorted == 'number') { 506 i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted); 507 } else { 508 i = _.sortedIndex(array, item); 509 return array[i] === item ? i : -1; 510 } 511 } 512 if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted); 513 for (; i < l; i++) if (array[i] === item) return i; 514 return -1; 515 }; 516 517 // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. 518 _.lastIndexOf = function(array, item, from) { 519 var hasIndex = from != null; 520 if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) { 521 return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item); 522 } 523 var i = (hasIndex ? from : array.length); 524 while (i--) if (array[i] === item) return i; 525 return -1; 526 }; 527 528 // Generate an integer Array containing an arithmetic progression. A port of 529 // the native Python `range()` function. See 530 // [the Python documentation](http://docs.python.org/library/functions.html#range). 531 _.range = function(start, stop, step) { 532 if (arguments.length <= 1) { 533 stop = start || 0; 534 start = 0; 535 } 536 step = arguments[2] || 1; 537 538 var len = Math.max(Math.ceil((stop - start) / step), 0); 539 var idx = 0; 540 var range = new Array(len); 541 542 while(idx < len) { 543 range[idx++] = start; 544 start += step; 545 } 546 547 return range; 548 }; 549 550 // Function (ahem) Functions 551 // ------------------ 552 553 // Reusable constructor function for prototype setting. 554 var ctor = function(){}; 555 556 // Create a function bound to a given object (assigning `this`, and arguments, 557 // optionally). Binding with arguments is also known as `curry`. 558 // Delegates to **ECMAScript 5**'s native `Function.bind` if available. 559 // We check for `func.bind` first, to fail fast when `func` is undefined. 560 _.bind = function bind(func, context) { 561 var bound, args; 562 if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); 563 if (!_.isFunction(func)) throw new TypeError; 564 args = slice.call(arguments, 2); 565 return bound = function() { 566 if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); 567 ctor.prototype = func.prototype; 568 var self = new ctor; 569 var result = func.apply(self, args.concat(slice.call(arguments))); 570 if (Object(result) === result) return result; 571 return self; 572 }; 573 }; 574 575 // Bind all of an object's methods to that object. Useful for ensuring that 576 // all callbacks defined on an object belong to it. 577 _.bindAll = function(obj) { 578 var funcs = slice.call(arguments, 1); 579 if (funcs.length == 0) funcs = _.functions(obj); 580 each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); 581 return obj; 582 }; 583 584 // Memoize an expensive function by storing its results. 585 _.memoize = function(func, hasher) { 586 var memo = {}; 587 hasher || (hasher = _.identity); 588 return function() { 589 var key = hasher.apply(this, arguments); 590 return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); 591 }; 592 }; 593 594 // Delays a function for the given number of milliseconds, and then calls 595 // it with the arguments supplied. 596 _.delay = function(func, wait) { 597 var args = slice.call(arguments, 2); 598 return setTimeout(function(){ return func.apply(null, args); }, wait); 599 }; 600 601 // Defers a function, scheduling it to run after the current call stack has 602 // cleared. 603 _.defer = function(func) { 604 return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); 605 }; 606 607 // Returns a function, that, when invoked, will only be triggered at most once 608 // during a given window of time. 609 _.throttle = function(func, wait) { 610 var context, args, timeout, throttling, more, result; 611 var whenDone = _.debounce(function(){ more = throttling = false; }, wait); 612 return function() { 613 context = this; args = arguments; 614 var later = function() { 615 timeout = null; 616 if (more) { 617 result = func.apply(context, args); 618 } 619 whenDone(); 620 }; 621 if (!timeout) timeout = setTimeout(later, wait); 622 if (throttling) { 623 more = true; 624 } else { 625 throttling = true; 626 result = func.apply(context, args); 627 } 628 whenDone(); 629 return result; 630 }; 631 }; 632 633 // Returns a function, that, as long as it continues to be invoked, will not 634 // be triggered. The function will be called after it stops being called for 635 // N milliseconds. If `immediate` is passed, trigger the function on the 636 // leading edge, instead of the trailing. 637 _.debounce = function(func, wait, immediate) { 638 var timeout, result; 639 return function() { 640 var context = this, args = arguments; 641 var later = function() { 642 timeout = null; 643 if (!immediate) result = func.apply(context, args); 644 }; 645 var callNow = immediate && !timeout; 646 clearTimeout(timeout); 647 timeout = setTimeout(later, wait); 648 if (callNow) result = func.apply(context, args); 649 return result; 650 }; 651 }; 652 653 // Returns a function that will be executed at most one time, no matter how 654 // often you call it. Useful for lazy initialization. 655 _.once = function(func) { 656 var ran = false, memo; 657 return function() { 658 if (ran) return memo; 659 ran = true; 660 memo = func.apply(this, arguments); 661 func = null; 662 return memo; 663 }; 664 }; 665 666 // Returns the first function passed as an argument to the second, 667 // allowing you to adjust arguments, run code before and after, and 668 // conditionally execute the original function. 669 _.wrap = function(func, wrapper) { 670 return function() { 671 var args = [func]; 672 push.apply(args, arguments); 673 return wrapper.apply(this, args); 674 }; 675 }; 676 677 // Returns a function that is the composition of a list of functions, each 678 // consuming the return value of the function that follows. 679 _.compose = function() { 680 var funcs = arguments; 681 return function() { 682 var args = arguments; 683 for (var i = funcs.length - 1; i >= 0; i--) { 684 args = [funcs[i].apply(this, args)]; 685 } 686 return args[0]; 687 }; 688 }; 689 690 // Returns a function that will only be executed after being called N times. 691 _.after = function(times, func) { 692 if (times <= 0) return func(); 693 return function() { 694 if (--times < 1) { 695 return func.apply(this, arguments); 696 } 697 }; 698 }; 699 700 // Object Functions 701 // ---------------- 702 703 // Retrieve the names of an object's properties. 704 // Delegates to **ECMAScript 5**'s native `Object.keys` 705 _.keys = nativeKeys || function(obj) { 706 if (obj !== Object(obj)) throw new TypeError('Invalid object'); 707 var keys = []; 708 for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; 709 return keys; 710 }; 711 712 // Retrieve the values of an object's properties. 713 _.values = function(obj) { 714 var values = []; 715 for (var key in obj) if (_.has(obj, key)) values.push(obj[key]); 716 return values; 717 }; 718 719 // Convert an object into a list of `[key, value]` pairs. 720 _.pairs = function(obj) { 721 var pairs = []; 722 for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]); 723 return pairs; 724 }; 725 726 // Invert the keys and values of an object. The values must be serializable. 727 _.invert = function(obj) { 728 var result = {}; 729 for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key; 730 return result; 731 }; 732 733 // Return a sorted list of the function names available on the object. 734 // Aliased as `methods` 735 _.functions = _.methods = function(obj) { 736 var names = []; 737 for (var key in obj) { 738 if (_.isFunction(obj[key])) names.push(key); 739 } 740 return names.sort(); 741 }; 742 743 // Extend a given object with all the properties in passed-in object(s). 744 _.extend = function(obj) { 745 each(slice.call(arguments, 1), function(source) { 746 for (var prop in source) { 747 obj[prop] = source[prop]; 748 } 749 }); 750 return obj; 751 }; 752 753 // Return a copy of the object only containing the whitelisted properties. 754 _.pick = function(obj) { 755 var copy = {}; 756 var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); 757 each(keys, function(key) { 758 if (key in obj) copy[key] = obj[key]; 759 }); 760 return copy; 761 }; 762 763 // Return a copy of the object without the blacklisted properties. 764 _.omit = function(obj) { 765 var copy = {}; 766 var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); 767 for (var key in obj) { 768 if (!_.contains(keys, key)) copy[key] = obj[key]; 769 } 770 return copy; 771 }; 772 773 // Fill in a given object with default properties. 774 _.defaults = function(obj) { 775 each(slice.call(arguments, 1), function(source) { 776 for (var prop in source) { 777 if (obj[prop] == null) obj[prop] = source[prop]; 778 } 779 }); 780 return obj; 781 }; 782 783 // Create a (shallow-cloned) duplicate of an object. 784 _.clone = function(obj) { 785 if (!_.isObject(obj)) return obj; 786 return _.isArray(obj) ? obj.slice() : _.extend({}, obj); 787 }; 788 789 // Invokes interceptor with the obj, and then returns obj. 790 // The primary purpose of this method is to "tap into" a method chain, in 791 // order to perform operations on intermediate results within the chain. 792 _.tap = function(obj, interceptor) { 793 interceptor(obj); 794 return obj; 795 }; 796 797 // Internal recursive comparison function for `isEqual`. 798 var eq = function(a, b, aStack, bStack) { 799 // Identical objects are equal. `0 === -0`, but they aren't identical. 800 // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal. 801 if (a === b) return a !== 0 || 1 / a == 1 / b; 802 // A strict comparison is necessary because `null == undefined`. 803 if (a == null || b == null) return a === b; 804 // Unwrap any wrapped objects. 805 if (a instanceof _) a = a._wrapped; 806 if (b instanceof _) b = b._wrapped; 807 // Compare `[[Class]]` names. 808 var className = toString.call(a); 809 if (className != toString.call(b)) return false; 810 switch (className) { 811 // Strings, numbers, dates, and booleans are compared by value. 812 case '[object String]': 813 // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is 814 // equivalent to `new String("5")`. 815 return a == String(b); 816 case '[object Number]': 817 // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for 818 // other numeric values. 819 return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); 820 case '[object Date]': 821 case '[object Boolean]': 822 // Coerce dates and booleans to numeric primitive values. Dates are compared by their 823 // millisecond representations. Note that invalid dates with millisecond representations 824 // of `NaN` are not equivalent. 825 return +a == +b; 826 // RegExps are compared by their source patterns and flags. 827 case '[object RegExp]': 828 return a.source == b.source && 829 a.global == b.global && 830 a.multiline == b.multiline && 831 a.ignoreCase == b.ignoreCase; 832 } 833 if (typeof a != 'object' || typeof b != 'object') return false; 834 // Assume equality for cyclic structures. The algorithm for detecting cyclic 835 // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. 836 var length = aStack.length; 837 while (length--) { 838 // Linear search. Performance is inversely proportional to the number of 839 // unique nested structures. 840 if (aStack[length] == a) return bStack[length] == b; 841 } 842 // Add the first object to the stack of traversed objects. 843 aStack.push(a); 844 bStack.push(b); 845 var size = 0, result = true; 846 // Recursively compare objects and arrays. 847 if (className == '[object Array]') { 848 // Compare array lengths to determine if a deep comparison is necessary. 849 size = a.length; 850 result = size == b.length; 851 if (result) { 852 // Deep compare the contents, ignoring non-numeric properties. 853 while (size--) { 854 if (!(result = eq(a[size], b[size], aStack, bStack))) break; 855 } 856 } 857 } else { 858 // Objects with different constructors are not equivalent, but `Object`s 859 // from different frames are. 860 var aCtor = a.constructor, bCtor = b.constructor; 861 if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) && 862 _.isFunction(bCtor) && (bCtor instanceof bCtor))) { 863 return false; 864 } 865 // Deep compare objects. 866 for (var key in a) { 867 if (_.has(a, key)) { 868 // Count the expected number of properties. 869 size++; 870 // Deep compare each member. 871 if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break; 872 } 873 } 874 // Ensure that both objects contain the same number of properties. 875 if (result) { 876 for (key in b) { 877 if (_.has(b, key) && !(size--)) break; 878 } 879 result = !size; 880 } 881 } 882 // Remove the first object from the stack of traversed objects. 883 aStack.pop(); 884 bStack.pop(); 885 return result; 886 }; 887 888 // Perform a deep comparison to check if two objects are equal. 889 _.isEqual = function(a, b) { 890 return eq(a, b, [], []); 891 }; 892 893 // Is a given array, string, or object empty? 894 // An "empty" object has no enumerable own-properties. 895 _.isEmpty = function(obj) { 896 if (obj == null) return true; 897 if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; 898 for (var key in obj) if (_.has(obj, key)) return false; 899 return true; 900 }; 901 902 // Is a given value a DOM element? 903 _.isElement = function(obj) { 904 return !!(obj && obj.nodeType === 1); 905 }; 906 907 // Is a given value an array? 908 // Delegates to ECMA5's native Array.isArray 909 _.isArray = nativeIsArray || function(obj) { 910 return toString.call(obj) == '[object Array]'; 911 }; 912 913 // Is a given variable an object? 914 _.isObject = function(obj) { 915 return obj === Object(obj); 916 }; 917 918 // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp. 919 each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) { 920 _['is' + name] = function(obj) { 921 return toString.call(obj) == '[object ' + name + ']'; 922 }; 923 }); 924 925 // Define a fallback version of the method in browsers (ahem, IE), where 926 // there isn't any inspectable "Arguments" type. 927 if (!_.isArguments(arguments)) { 928 _.isArguments = function(obj) { 929 return !!(obj && _.has(obj, 'callee')); 930 }; 931 } 932 933 // Optimize `isFunction` if appropriate. 934 if (typeof (/./) !== 'function') { 935 _.isFunction = function(obj) { 936 return typeof obj === 'function'; 937 }; 938 } 939 940 // Is a given object a finite number? 941 _.isFinite = function(obj) { 942 return _.isNumber(obj) && isFinite(obj); 943 }; 944 945 // Is the given value `NaN`? (NaN is the only number which does not equal itself). 946 _.isNaN = function(obj) { 947 return _.isNumber(obj) && obj != +obj; 948 }; 949 950 // Is a given value a boolean? 951 _.isBoolean = function(obj) { 952 return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; 953 }; 954 955 // Is a given value equal to null? 956 _.isNull = function(obj) { 957 return obj === null; 958 }; 959 960 // Is a given variable undefined? 961 _.isUndefined = function(obj) { 962 return obj === void 0; 963 }; 964 965 // Shortcut function for checking if an object has a given property directly 966 // on itself (in other words, not on a prototype). 967 _.has = function(obj, key) { 968 return hasOwnProperty.call(obj, key); 969 }; 970 971 // Utility Functions 972 // ----------------- 973 974 // Run Underscore.js in *noConflict* mode, returning the `_` variable to its 975 // previous owner. Returns a reference to the Underscore object. 976 _.noConflict = function() { 977 root._ = previousUnderscore; 978 return this; 979 }; 980 981 // Keep the identity function around for default iterators. 982 _.identity = function(value) { 983 return value; 984 }; 985 986 // Run a function **n** times. 987 _.times = function(n, iterator, context) { 988 for (var i = 0; i < n; i++) iterator.call(context, i); 989 }; 990 991 // Return a random integer between min and max (inclusive). 992 _.random = function(min, max) { 993 if (max == null) { 994 max = min; 995 min = 0; 996 } 997 return min + (0 | Math.random() * (max - min + 1)); 998 }; 999 1000 // List of HTML entities for escaping. 1001 var entityMap = { 1002 escape: { 1003 '&': '&', 1004 '<': '<', 1005 '>': '>', 1006 '"': '"', 1007 "'": ''', 1008 '/': '/' 1009 } 1010 }; 1011 entityMap.unescape = _.invert(entityMap.escape); 1012 1013 // Regexes containing the keys and values listed immediately above. 1014 var entityRegexes = { 1015 escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'), 1016 unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g') 1017 }; 1018 1019 // Functions for escaping and unescaping strings to/from HTML interpolation. 1020 _.each(['escape', 'unescape'], function(method) { 1021 _[method] = function(string) { 1022 if (string == null) return ''; 1023 return ('' + string).replace(entityRegexes[method], function(match) { 1024 return entityMap[method][match]; 1025 }); 1026 }; 1027 }); 1028 1029 // If the value of the named property is a function then invoke it; 1030 // otherwise, return it. 1031 _.result = function(object, property) { 1032 if (object == null) return null; 1033 var value = object[property]; 1034 return _.isFunction(value) ? value.call(object) : value; 1035 }; 1036 1037 // Add your own custom functions to the Underscore object. 1038 _.mixin = function(obj) { 1039 each(_.functions(obj), function(name){ 1040 var func = _[name] = obj[name]; 1041 _.prototype[name] = function() { 1042 var args = [this._wrapped]; 1043 push.apply(args, arguments); 1044 return result.call(this, func.apply(_, args)); 1045 }; 1046 }); 1047 }; 1048 1049 // Generate a unique integer id (unique within the entire client session). 1050 // Useful for temporary DOM ids. 1051 var idCounter = 0; 1052 _.uniqueId = function(prefix) { 1053 var id = idCounter++; 1054 return prefix ? prefix + id : id; 1055 }; 1056 1057 // By default, Underscore uses ERB-style template delimiters, change the 1058 // following template settings to use alternative delimiters. 1059 _.templateSettings = { 1060 evaluate : /<%([\s\S]+?)%>/g, 1061 interpolate : /<%=([\s\S]+?)%>/g, 1062 escape : /<%-([\s\S]+?)%>/g 1063 }; 1064 1065 // When customizing `templateSettings`, if you don't want to define an 1066 // interpolation, evaluation or escaping regex, we need one that is 1067 // guaranteed not to match. 1068 var noMatch = /(.)^/; 1069 1070 // Certain characters need to be escaped so that they can be put into a 1071 // string literal. 1072 var escapes = { 1073 "'": "'", 1074 '\\': '\\', 1075 '\r': 'r', 1076 '\n': 'n', 1077 '\t': 't', 1078 '\u2028': 'u2028', 1079 '\u2029': 'u2029' 1080 }; 1081 1082 var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; 1083 1084 // JavaScript micro-templating, similar to John Resig's implementation. 1085 // Underscore templating handles arbitrary delimiters, preserves whitespace, 1086 // and correctly escapes quotes within interpolated code. 1087 _.template = function(text, data, settings) { 1088 settings = _.defaults({}, settings, _.templateSettings); 1089 1090 // Combine delimiters into one regular expression via alternation. 1091 var matcher = new RegExp([ 1092 (settings.escape || noMatch).source, 1093 (settings.interpolate || noMatch).source, 1094 (settings.evaluate || noMatch).source 1095 ].join('|') + '|$', 'g'); 1096 1097 // Compile the template source, escaping string literals appropriately. 1098 var index = 0; 1099 var source = "__p+='"; 1100 text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { 1101 source += text.slice(index, offset) 1102 .replace(escaper, function(match) { return '\\' + escapes[match]; }); 1103 source += 1104 escape ? "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'" : 1105 interpolate ? "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'" : 1106 evaluate ? "';\n" + evaluate + "\n__p+='" : ''; 1107 index = offset + match.length; 1108 }); 1109 source += "';\n"; 1110 1111 // If a variable is not specified, place data values in local scope. 1112 if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; 1113 1114 source = "var __t,__p='',__j=Array.prototype.join," + 1115 "print=function(){__p+=__j.call(arguments,'');};\n" + 1116 source + "return __p;\n"; 1117 1118 try { 1119 var render = new Function(settings.variable || 'obj', '_', source); 1120 } catch (e) { 1121 e.source = source; 1122 throw e; 1123 } 1124 1125 if (data) return render(data, _); 1126 var template = function(data) { 1127 return render.call(this, data, _); 1128 }; 1129 1130 // Provide the compiled function source as a convenience for precompilation. 1131 template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; 1132 1133 return template; 1134 }; 1135 1136 // Add a "chain" function, which will delegate to the wrapper. 1137 _.chain = function(obj) { 1138 return _(obj).chain(); 1139 }; 1140 1141 // OOP 1142 // --------------- 1143 // If Underscore is called as a function, it returns a wrapped object that 1144 // can be used OO-style. This wrapper holds altered versions of all the 1145 // underscore functions. Wrapped objects may be chained. 1146 1147 // Helper function to continue chaining intermediate results. 1148 var result = function(obj) { 1149 return this._chain ? _(obj).chain() : obj; 1150 }; 1151 1152 // Add all of the Underscore functions to the wrapper object. 1153 _.mixin(_); 1154 1155 // Add all mutator Array functions to the wrapper. 1156 each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { 1157 var method = ArrayProto[name]; 1158 _.prototype[name] = function() { 1159 var obj = this._wrapped; 1160 method.apply(obj, arguments); 1161 if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0]; 1162 return result.call(this, obj); 1163 }; 1164 }); 1165 1166 // Add all accessor Array functions to the wrapper. 1167 each(['concat', 'join', 'slice'], function(name) { 1168 var method = ArrayProto[name]; 1169 _.prototype[name] = function() { 1170 return result.call(this, method.apply(this._wrapped, arguments)); 1171 }; 1172 }); 1173 1174 _.extend(_.prototype, { 1175 1176 // Start chaining a wrapped Underscore object. 1177 chain: function() { 1178 this._chain = true; 1179 return this; 1180 }, 1181 1182 // Extracts the result from a wrapped and chained object. 1183 value: function() { 1184 return this._wrapped; 1185 } 1186 1187 }); 1188 1189 }).call(this);
联系我们 |
---|
文章看不懂?联系我们为您免费解答!免费助力个人,小企站点! |
① 电话:020-2206-9892 |
② QQ咨询:1025174874 |
③ 邮件:info@361sale.com |
④ 工作时间:周一至周五,9:30-18:30,节假日休息 |
THE END
暂无评论内容