1// Underscore.js 1.2.1 2// (c) 2011 Jeremy Ashkenas, DocumentCloud Inc. 3// Underscore is freely distributable under the MIT license. 4// Portions of Underscore are inspired or borrowed from Prototype, 5// Oliver Steele's Functional, and John Resig's Micro-Templating. 6// For all details and documentation: 7// http://documentcloud.github.com/underscore 8 9(function() { 10 11 // Baseline setup 12 // -------------- 13 14 // Establish the root object, `window` in the browser, or `global` on the server. 15 var root = this; 16 17 // Save the previous value of the `_` variable. 18 var previousUnderscore = root._; 19 20 // Establish the object that gets returned to break out of a loop iteration. 21 var breaker = {}; 22 23 // Save bytes in the minified (but not gzipped) version: 24 var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; 25 26 // Create quick reference variables for speed access to core prototypes. 27 var slice = ArrayProto.slice, 28 unshift = ArrayProto.unshift, 29 toString = ObjProto.toString, 30 hasOwnProperty = ObjProto.hasOwnProperty; 31 32 // All **ECMAScript 5** native function implementations that we hope to use 33 // are declared here. 34 var 35 nativeForEach = ArrayProto.forEach, 36 nativeMap = ArrayProto.map, 37 nativeReduce = ArrayProto.reduce, 38 nativeReduceRight = ArrayProto.reduceRight, 39 nativeFilter = ArrayProto.filter, 40 nativeEvery = ArrayProto.every, 41 nativeSome = ArrayProto.some, 42 nativeIndexOf = ArrayProto.indexOf, 43 nativeLastIndexOf = ArrayProto.lastIndexOf, 44 nativeIsArray = Array.isArray, 45 nativeKeys = Object.keys, 46 nativeBind = FuncProto.bind; 47 48 // Create a safe reference to the Underscore object for use below. 49 var _ = function(obj) { return new wrapper(obj); }; 50 51 // Export the Underscore object for **Node.js** and **"CommonJS"**, with 52 // backwards-compatibility for the old `require()` API. If we're not in 53 // CommonJS, add `_` to the global object. 54 if (typeof exports !== 'undefined') { 55 if (typeof module !== 'undefined' && module.exports) { 56 exports = module.exports = _; 57 } 58 exports._ = _; 59 } else if (typeof define === 'function' && define.amd) { 60 // Register as a named module with AMD. 61 define('underscore', function() { 62 return _; 63 }); 64 } else { 65 // Exported as a string, for Closure Compiler "advanced" mode. 66 root['_'] = _; 67 } 68 69 // Current version. 70 _.VERSION = '1.2.1'; 71 72 // Collection Functions 73 // -------------------- 74 75 // The cornerstone, an `each` implementation, aka `forEach`. 76 // Handles objects with the built-in `forEach`, arrays, and raw objects. 77 // Delegates to **ECMAScript 5**'s native `forEach` if available. 78 var each = _.each = _.forEach = function(obj, iterator, context) { 79 if (obj == null) return; 80 if (nativeForEach && obj.forEach === nativeForEach) { 81 obj.forEach(iterator, context); 82 } else if (obj.length === +obj.length) { 83 for (var i = 0, l = obj.length; i < l; i++) { 84 if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return; 85 } 86 } else { 87 for (var key in obj) { 88 if (hasOwnProperty.call(obj, key)) { 89 if (iterator.call(context, obj[key], key, obj) === breaker) return; 90 } 91 } 92 } 93 }; 94 95 // Return the results of applying the iterator to each element. 96 // Delegates to **ECMAScript 5**'s native `map` if available. 97 _.map = function(obj, iterator, context) { 98 var results = []; 99 if (obj == null) return results; 100 if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); 101 each(obj, function(value, index, list) { 102 results[results.length] = iterator.call(context, value, index, list); 103 }); 104 return results; 105 }; 106 107 // **Reduce** builds up a single result from a list of values, aka `inject`, 108 // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. 109 _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { 110 var initial = memo !== void 0; 111 if (obj == null) obj = []; 112 if (nativeReduce && obj.reduce === nativeReduce) { 113 if (context) iterator = _.bind(iterator, context); 114 return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); 115 } 116 each(obj, function(value, index, list) { 117 if (!initial) { 118 memo = value; 119 initial = true; 120 } else { 121 memo = iterator.call(context, memo, value, index, list); 122 } 123 }); 124 if (!initial) throw new TypeError("Reduce of empty array with
124no initial value"); 125 return memo; 126 }; 127 128 // The right-associative version of reduce, also known as `foldr`. 129 // Delegates to **ECMAScript 5**'s native `reduceRight` if available. 130 _.reduceRight = _.foldr = function(obj, iterator, memo, context) { 131 if (obj == null) obj = []; 132 if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { 133 if (context) iterator = _.bind(iterator, context); 134 return memo !== void 0 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); 135 } 136 var reversed = (_.isArray(obj) ? obj.slice() : _.toArray(obj)).reverse(); 137 return _.reduce(reversed, iterator, memo, context); 138 }; 139 140 // Return the first value which passes a truth test. Aliased as `detect`. 141 _.find = _.detect = function(obj, iterator, context) { 142 var result; 143 any(obj, function(value, index, list) { 144 if (iterator.call(context, value, index, list)) { 145 result = value; 146 return true; 147 } 148 }); 149 return result; 150 }; 151 152 // Return all the elements that pass a truth test. 153 // Delegates to **ECMAScript 5**'s native `filter` if available. 154 // Aliased as `select`. 155 _.filter = _.select = function(obj, iterator, context) { 156 var results = []; 157 if (obj == null) return results; 158 if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); 159 each(obj, function(value, index, list) { 160 if (iterator.call(context, value, index, list)) results[results.length] = value; 161 }); 162 return results; 163 }; 164 165 // Return all the elements for which a truth test fails. 166 _.reject = function(obj, iterator, context) { 167 var results = []; 168 if (obj == null) return results; 169 each(obj, function(value, index, list) { 170 if (!iterator.call(context, value, index, list)) results[results.length] = value; 171 }); 172 return results; 173 }; 174 175 // Determine whether all of the elements match a truth test. 176 // Delegates to **ECMAScript 5**'s native `every` if available. 177 // Aliased as `all`. 178 _.every = _.all = function(obj, iterator, context) { 179 var result = true; 180 if (obj == null) return result; 181 if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); 182 each(obj, function(value, index, list) { 183 if (!(result = result && iterator.call(context, value, index, list))) return breaker; 184 }); 185 return result; 186 }; 187 188 // Determine if at least one element in the object matches a truth test. 189 // Delegates to **ECMAScript 5**'s native `some` if available. 190 // Aliased as `any`. 191 var any = _.some = _.any = function(obj, iterator, context) { 192 iterator = iterator || _.identity; 193 var result = false;
194 if (obj == null) return result; 195 if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); 196 each(obj, function(value, index, list) { 197 if (result |= iterator.call(context, value, index, list)) return breaker; 198 }); 199 return !!result; 200 }; 201 202 // Determine if a given value is included in the array or object using `===`. 203 // Aliased as `contains`. 204 _.include = _.contains = function(obj, target) { 205 var found = false; 206 if (obj == null) return found; 207 if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; 208 found = any(obj, function(value) { 209 if (value === target) return true; 210 }); 211 return found; 212 }; 213 214 // Invoke a method (with arguments) on every item in a collection. 215 _.invoke = function(obj, method) { 216 var args = slice.call(arguments, 2); 217 return _.map(obj, function(value) { 218 return (method.call ? method || value : value[method]).apply(value, args); 219 }); 220 }; 221 222 // Convenience version of a common use case of `map`: fetching a property. 223 _.pluck = function(obj, key) { 224 return _.map(obj, function(value){ return value[key]; }); 225 }; 226 227 // Return the maximum element or (element-based computation). 228 _.max = function(obj, iterator, context) { 229 if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj); 230 if (!iterator && _.isEmpty(obj)) return -Infinity; 231 var result = {computed : -Infinity}; 232 each(obj, function(value, index, list) { 233 var computed = iterator ? iterator.call(context, value, index, list) : value; 234 computed >= result.computed && (result = {value : value, computed : computed}); 235 }); 236 return result.value; 237 }; 238 239 // Return the minimum element (or element-based computation). 240 _.min = function(obj, iterator, context) { 241 if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj); 242 if (!iterator && _.isEmpty(obj)) return Infinity; 243 var result = {computed : Infinity}; 244 each(obj, function(value, index, list) { 245 var computed = iterator ? iterator.call(context, value, index, list) : value; 246 computed < result.computed && (result = {value : value, computed : computed}); 247 }); 248 return result.value; 249 }; 250 251 // Shuffle an array. 252 _.shuffle = function(obj) { 253 var shuffled = [], rand; 254 each(obj, function(value, index, list) { 255 if (index == 0) { 256 shuffled[0] = value; 257 } else { 258 rand = Math.floor(Math.random() * (index + 1)); 259 shuffled[index] = shuffled[rand]; 260 shuffled[rand] = value; 261 } 262 }); 263 return shuffled; 264 }; 265 266 // Sort the object's values by a criterion produced by an iterator. 267 _.sortBy = function(obj, iterator, context) { 268 return _.pluck(_.map(obj, function(value, index, list) { 269 return { 270 value : value, 271 criteria : iterator.call(context, value, index, list) 272 }; 273 }).sort(function(left, right) { 274 var a = left.criteria, b = right.criteria; 275 return a < b ? -1 : a > b ? 1 : 0; 276 }), 'value'); 277 }; 278 279 // Groups the object's values by a criterion. Pass either a string attribute 280 // to group by, or a function that returns the criterion. 281 _.groupBy = function(obj, val) { 282 var result = {}; 283 var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; }; 284 each(obj, function(value, index) { 285 var key = iterator(value, index); 286 (result[key] || (result[key] = [])).push(value); 287 }); 288 return result; 289 }; 290 291 // Use a comparator function to figure out at what index an object should 292 // be inserted so as to maintain order. Uses binary search. 293 _.sortedIndex = function(array, obj, iterator) { 294 iterator || (iterator = _.identity); 295 var low = 0, high = array.length; 296 while (low < high) { 297 var mid = (low + high) >> 1; 298 iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid; 299 } 300 return low; 301 }; 302 303 // Safely convert anything iterable into a real, live array. 304 _.toArray = function(iterable) { 305 if (!iterable) return []; 306 if (iterable.toArray) return iterable.toArray(); 307 if (_.isArray(iterable)) return slice.call(iterable); 308 if (_.isArguments(iterable)) return slice.call(iterable); 309 return _.values(iterable); 310 }; 311 312 // Return the number of elements in an object. 313 _.size = function(obj) { 314 return _.toArray(obj).length; 315 }; 316 317 // Array Functions 318 // --------------- 319 320 // Get the first element of an array. Passing **n** will return the first N 321 // values in the array. Aliased as `head`. The **guard** check allows it to work 322 // with `_.map`. 323 _.first = _.head = function(array, n, guard) { 324 return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; 325 }; 326 327 // Returns everything but the last entry of the array. Especcialy useful on 328 // the arguments object. Passing **n** will return all the values in 329 // the array, excluding the last N. The **guard** check allows it to work with 330 // `_.map`. 331 _.initial = function(array, n, guard) { 332 return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); 333 }; 334 335 // Get the last element of an array. Passing **n** will return the last N 336 // values in the array. The **guard** check allows it to work with `_.map`. 337 _.last = function(array, n, guard) { 338 return (n != null) && !guard ? slice.call(array, array.length - n) : array[array.length - 1]; 339 }; 340 341 // Returns everything but the first entry of the array. Aliased as `tail`. 342 // Especially useful on the arguments object. Passing an **index** will return 343 // the rest of the values in the array from that index onward. The **guard** 344 // check allows it to work with `_.map`. 345 _.rest = _.tail = function(array, index, guard) { 346 return slice.call(array, (index == null) || guard ? 1 : index); 347 }; 348 349 // Trim out all falsy values from an array.
350 _.compact = function(array) { 351 return _.filter(array, function(value){ return !!value; }); 352 }; 353 354 // Return a completely flattened version of an array. 355 _.flatten = function(array, shallow) { 356 return _.reduce(array, function(memo, value) { 357 if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value)); 358 memo[memo.length] = value; 359 return memo; 360 }, []); 361 }; 362 363 // Return a version of the array that does not contain the specified value(s). 364 _.without = function(array) { 365 return _.difference(array, slice.call(arguments, 1)); 366 }; 367 368 // Produce a duplicate-free version of the array. If the array has already 369 // been sorted, you have the option of using a faster algorithm. 370 // Aliased as `unique`. 371 _.uniq = _.unique = function(array, isSorted, iterator) { 372 var initial = iterator ? _.map(array, iterator) : array; 373 var result = []; 374 _.reduce(initial, function(memo, el, i) { 375 if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) { 376 memo[memo.length] = el; 377 result[result.length] = array[i]; 378 } 379 return memo; 380 }, []); 381 return result; 382 }; 383 384 // Produce an array that contains the union: each distinct element from all of 385 // the passed-in arrays. 386 _.union = function() { 387 return _.uniq(_.flatten(arguments, true)); 388 }; 389 390 // Produce an array that contains every item shared between all the 391 // passed-in arrays. (Aliased as "intersect" for back-compat.) 392 _.intersection = _.intersect = function(array) { 393 var rest = slice.call(arguments, 1); 394 return _.filter(_.uniq(array), function(item) { 395 return _.every(rest, function(other) { 396 return _.indexOf(other, item) >= 0; 397 }); 398 }); 399 }; 400 401 // Take the difference between one array and another. 402 // Only the elements present in just the first array will remain. 403 _.difference = function(array, other) { 404 return _.filter(array, function(value){ return !_.include(other, value); }); 405 }; 406 407 // Zip together multiple lists into a single array -- elements that share 408 // an index go together. 409 _.zip = function() { 410 var args = slice.call(arguments); 411 var length = _.max(_.pluck(args, 'length')); 412 var results = new Array(length); 413 for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i); 414 return results; 415 }; 416 417 // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), 418 // we need this function. Return the position of the first occurrence of an 419 // item in an array, or -1 if the item is not included in the array. 420 // Delegates to **ECMAScript 5**'s native `indexOf` if available. 421 // If the array is large and already in sort order, pass `true` 422 // for **isSorted** to use binary search. 423 _.indexOf = function(array, item, isSorted) { 424 if (array == null) return -1; 425 var i, l; 426 if (isSorted) { 427 i = _.sortedIndex(array, item); 428 return array[i] === item ? i : -1; 429 } 430 if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item); 431 for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i; 432 return -1; 433 }; 434 435 // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. 436 _.lastIndexOf = function(array, item) { 437 if (array == null) return -1; 438 if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item); 439 var i = array.length; 440 while (i--) if (array[i] === item) return i; 441 return -1; 442 }; 443 444 // Generate an integer Array containing an arithmetic progression. A port of 445 // the native Python `range()` function. See 446 // [the Python documentation](http://docs.python.org/library/functions.html#range). 447 _.range = function(start, stop, step) { 448 if (arguments.length <= 1) { 449 stop = start || 0; 450 start = 0; 451 } 452 step = arguments[2] || 1; 453 454 var len = Math.max(Math.ceil((stop - start) / step), 0); 455 var idx = 0; 456 var range = new Array(len); 457 458 while(idx < len) { 459 range[idx++] = start; 460 start += step; 461 } 462 463 return range; 464 }; 465 466 // Function (ahem) Functions 467 // ------------------ 468 469 // Reusable constructor function for prototype setting. 470 var ctor = function(){}; 471 472 // Create a function bound to a given object (assigning `this`, and arguments, 473 // optionally). Binding with arguments is also known as `curry`. 474 // Delegates to **ECMAScript 5**'s native `Function.bind` if available. 475 // We check for `func.bind` first, to fail fast when `func` is undefined. 476 _.bind = function bind(func, context) { 477 var bound, args; 478 if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); 479 if (!_.isFunction(func)) throw new TypeError; 480 args = slice.call(arguments, 2); 481 return bound = function() { 482 if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); 483 ctor.prototype = func.prototype; 484 var self = new ctor; 485 var result = func.apply(self, args.concat(slice.call(arguments))); 486 if (Object(result) === result) return result; 487 return self; 488 }; 489 }; 490 491 // Bind all of an object's methods to that object. Useful for ensuring that 492 // all callbacks defined on an object belong to it. 493 _.bindAll = function(obj) { 494 var funcs = slice.call(arguments, 1);
495 if (funcs.length == 0) funcs = _.functions(obj); 496 each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); 497 return obj; 498 }; 499 500 // Memoize an expensive function by storing its results. 501 _.memoize = function(func, hasher) { 502 var memo = {}; 503 hasher || (hasher = _.identity); 504 return function() { 505 var key = hasher.apply(this, arguments); 506 return hasOwnProperty.call(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); 507 }; 508 }; 509 510 // Delays a function for the given number of milliseconds, and then calls 511 // it with the arguments supplied. 512 _.delay = function(func, wait) { 513 var args = slice.call(arguments, 2); 514 return setTimeout(function(){ return func.apply(func, args); }, wait); 515 }; 516 517 // Defers a function, scheduling it to run after the current call stack has 518 // cleared. 519 _.defer = function(func) { 520 return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); 521 }; 522 523 // Returns a function, that, when invoked, will only be triggered at most once 524 // during a given window of time. 525 _.throttle = function(func, wait) { 526 var timeout, context, args, throttling, finishThrottle; 527 finishThrottle = _.debounce(function(){ throttling = false; }, wait); 528 return function() { 529 context = this; args = arguments; 530 var throttler = function() { 531 timeout = null; 532 func.apply(context, args); 533 finishThrottle(); 534 }; 535 if (!timeout) timeout = setTimeout(throttler, wait); 536 if (!throttling) func.apply(context, args); 537 if (finishThrottle) finishThrottle(); 538 throttling = true; 539 }; 540 }; 541 542 // Returns a function, that, as long as it continues to be invoked, will not 543 // be triggered. The function will be called after it stops being called for 544 // N milliseconds. 545 _.debounce = function(func, wait) { 546 var timeout; 547 return function() { 548 var context = this, args = arguments; 549 var throttler = function() { 550 timeout = null; 551 func.apply(context, args); 552 }; 553 clearTimeout(timeout); 554 timeout = setTimeout(throttler, wait); 555 }; 556 }; 557 558 // Returns a function that will be executed at most one time, no matter how 559 // often you call it. Useful for lazy initialization. 560 _.once = function(func) { 561 var ran = false, memo; 562 return function() { 563 if (ran) return memo; 564 ran = true; 565 return memo = func.apply(this, arguments); 566 }; 567 }; 568 569 // Returns the first function passed as an argument to the second, 570 // allowing you to adjust arguments, run code before and after, and 571 // conditionally execute the original function. 572 _.wrap = function(func, wrapper) { 573 return function() { 574 var args = [func].concat(slice.call(arguments)); 575 return wrapper.apply(this, args); 576 }; 577 }; 578 579 // Returns a function that is the composition of a list of functions, each 580 // consuming the return value of the function that follows. 581 _.compose = function() { 582 var funcs = slice.call(arguments); 583 return function() { 584 var args = slice.call(arguments); 585 for (var i = funcs.length - 1; i >= 0; i--) { 586 args = [funcs[i].apply(this, args)]; 587 } 588 return args[0]; 589 }; 590 }; 591 592 // Returns a function that will only be executed after being called N times. 593 _.after = function(times, func) { 594 return function() { 595 if (--times < 1) { return func.apply(this, arguments); } 596 }; 597 }; 598 599 // Object Functions 600 // ---------------- 601 602 // Retrieve the names of an object's properties. 603 // Delegates to **ECMAScript 5**'s native `Object.keys` 604 _.keys = nativeKeys || function(obj) { 605 if (obj !== Object(obj)) throw new TypeError('Invalid object'); 606 var keys = []; 607 for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key; 608 return keys; 609 }; 610 611 // Retrieve the values of an object's properties. 612 _.values = function(obj) { 613 return _.map(obj, _.identity); 614 }; 615 616 // Return a sorted list of the function names available on the object. 617 // Aliased as `methods` 618 _.functions = _.methods = function(obj) { 619 var names = []; 620 for (var key in obj) { 621 if (_.isFunction(obj[key])) names.push(key); 622 } 623 return names.sort(); 624 }; 625 626 // Extend a given object with all the properties in passed-in object(s). 627 _.extend = function(obj) { 628 each(slice.call(arguments, 1), function(source) { 629 for (var prop in source) { 630 if (source[prop] !== void 0) obj[prop] = source[prop]; 631 } 632 }); 633 return obj; 634 }; 635 636 // Fill in a given object with default properties. 637 _.defaults = function(obj) { 638 each(slice.call(arguments, 1), function(source) { 639 for (var prop in source) { 640 if (obj[prop] == null) obj[prop] = source[prop]; 641 } 642 }); 643 return obj; 644 }; 645 646 // Create a (shallow-cloned) duplicate of an object. 647 _.clone = function(obj) { 648 if (!_.isObject(obj)) return obj; 649 return _.isArray(obj) ? obj.slice() : _.extend({}, obj); 650 }; 651 652 // Invokes interceptor with the obj, and then returns obj.
653 // The primary purpose of this method is to "tap into" a method chain, in 654 // order to perform operations on intermediate results within the chain. 655 _.tap = function(obj, interceptor) { 656 interceptor(obj); 657 return obj; 658 }; 659 660 // Internal recursive comparison function. 661 function eq(a, b, stack) { 662 // Identical objects are equal. `0 === -0`, but they aren't identical. 663 // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal. 664 if (a === b) return a !== 0 || 1 / a == 1 / b; 665 // A strict comparison is necessary because `null == undefined`. 666 if ((a == null) || (b == null)) return a === b; 667 // Unwrap any wrapped objects. 668 if (a._chain) a = a._wrapped; 669 if (b._chain) b = b._wrapped; 670 // Invoke a custom `isEqual` method if one is provided. 671 if (_.isFunction(a.isEqual)) return a.isEqual(b); 672 if (_.isFunction(b.isEqual)) return b.isEqual(a); 673 // Compare object types. 674 var typeA = typeof a; 675 if (typeA != typeof b) return false; 676 // Optimization; ensure that both values are truthy or falsy. 677 if (!a != !b) return false; 678 // `NaN` values are equal. 679 if (_.isNaN(a)) return _.isNaN(b); 680 // Compare string objects by value. 681 var isStringA = _.isString(a), isStringB = _.isString(b); 682 if (isStringA || isStringB) return isStringA && isStringB && String(a) == String(b); 683 // Compare number objects by value. 684 var isNumberA = _.isNumber(a), isNumberB = _.isNumber(b); 685 if (isNumberA || isNumberB) return isNumberA && isNumberB && +a == +b; 686 // Compare boolean objects by value. The value of `true` is 1; the value of `false` is 0. 687 var isBooleanA = _.isBoolean(a), isBooleanB = _.isBoolean(b); 688 if (isBooleanA || isBooleanB) return isBooleanA && isBooleanB && +a == +b; 689 // Compare dates by their millisecond values. 690 var isDateA = _.isDate(a), isDateB = _.isDate(b); 691 if (isDateA || isDateB) return isDateA && isDateB && a.getTime() == b.getTime(); 692 // Compare RegExps by their source patterns and flags. 693 var isRegExpA = _.isRegExp(a), isRegExpB = _.isRegExp(b); 694 if (isRegExpA || isRegExpB) { 695 // Ensure commutative equality for RegExps. 696 return isRegExpA && isRegExpB && 697 a.source == b.source && 698 a.global == b.global && 699 a.multiline == b.multiline && 700 a.ignoreCase == b.ignoreCase; 701 } 702 // Ensure that both values are objects. 703 if (typeA != 'object') return false; 704 // Arrays or Arraylikes with different lengths are not equal. 705 if (a.length !== b.length) return false; 706 // Objects with different constructors are not equal. 707 if (a.constructor !== b.constructor) return false; 708 // Assume equality for cyclic structures. The algorithm for detecting cyclic 709 // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. 710 var length = stack.length; 711 while (length--) { 712 // Linear search. Performance is inversely proportional to the number of 713 // unique nested structures. 714 if (stack[length] == a) return true; 715 } 716 // Add the first object to the stack of traversed objects. 717 stack.push(a); 718 var size = 0, result = true; 719 // Deep compare objects. 720 for (var key in a) { 721 if (hasOwnProperty.call(a, key)) { 722 // Count the expected number of properties. 723 size++; 724 // Deep compare each member. 725 if (!(result = hasOwnProperty.call(b, key) && eq(a[key], b[key], stack))) break; 726 } 727 } 728 // Ensure that both objects contain the same number of properties. 729 if (result) { 730 for (key in b) { 731 if (hasOwnProperty.call(b, key) && !size--) break; 732 } 733 result = !size; 734 } 735 // Remove the first object from the stack of traversed objects. 736 stack.pop(); 737 return result; 738 } 739 740 // Perform a deep comparison to check if two objects are equal. 741 _.isEqual = function(a, b) { 742 return eq(a, b, []); 743 }; 744 745 // Is a given array, string, or object empty? 746 // An "empty" object has no enumerable own-properties. 747 _.isEmpty = function(obj) { 748 if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; 749 for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;
750 return true; 751 }; 752 753 // Is a given value a DOM element? 754 _.isElement = function(obj) { 755 return !!(obj && obj.nodeType == 1); 756 }; 757 758 // Is a given value an array? 759 // Delegates to ECMA5's native Array.isArray 760 _.isArray = nativeIsArray || function(obj) { 761 return toString.call(obj) == '[object Array]'; 762 }; 763 764 // Is a given variable an object? 765 _.isObject = function(obj) { 766 return obj === Object(obj); 767 }; 768 769 // Is a given variable an arguments object? 770 if (toString.call(arguments) == '[object Arguments]') { 771 _.isArguments = function(obj) { 772 return toString.call(obj) == '[object Arguments]'; 773 }; 774 } else { 775 _.isArguments = function(obj) { 776 return !!(obj && hasOwnProperty.call(obj, 'callee')); 777 }; 778 } 779 780 // Is a given value a function? 781 _.isFunction = function(obj) { 782 return toString.call(obj) == '[object Function]'; 783 }; 784 785 // Is a given value a string? 786 _.isString = function(obj) { 787 return toString.call(obj) == '[object String]'; 788 }; 789 790 // Is a given value a number? 791 _.isNumber = function(obj) { 792 return toString.call(obj) == '[object Number]'; 793 }; 794 795 // Is the given value `NaN`? 796 _.isNaN = function(obj) { 797 // `NaN` is the only value for which `===` is not reflexive. 798 return obj !== obj; 799 }; 800 801 // Is a given value a boolean? 802 _.isBoolean = function(obj) { 803 return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; 804 }; 805 806 // Is a given value a date? 807 _.isDate = function(obj) { 808 return toString.call(obj) == '[object Date]'; 809 }; 810 811 // Is the given value a regular expression? 812 _.isRegExp = function(obj) { 813 return toString.call(obj) == '[object RegExp]'; 814 }; 815 816 // Is a given value equal to null? 817 _.isNull = function(obj) { 818 return obj === null; 819 }; 820 821 // Is a given variable undefined? 822 _.isUndefined = function(obj) { 823 return obj === void 0; 824 }; 825 826 // Utility Functions 827 // ----------------- 828 829 // Run Underscore.js in *noConflict* mode, returning the `_` variable to its 830 // previous owner. Returns a reference to the Underscore object. 831 _.noConflict = function() { 832 root._ = previousUnderscore; 833 return this; 834 }; 835 836 // Keep the identity function around for default iterators. 837 _.identity = function(value) { 838 return value; 839 }; 840 841 // Run a function **n** times. 842 _.times = function (n, iterator, context) { 843 for (var i = 0; i < n; i++) iterator.call(context, i); 844 }; 845 846 // Escape a string for HTML interpolation. 847 _.escape = function(string) { 848 return (''+string).replace(/&(?!\w+;|#\d+;|#x[\da-f]+;)/gi, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g,'/'); 849 }; 850 851 // Add your own custom functions to the Underscore object, ensuring that 852 // they're correctly added to the OOP wrapper as well. 853 _.mixin = function(obj) { 854 each(_.functions(obj), function(name){ 855 addToWrapper(name, _[name] = obj[name]); 856 }); 857 }; 858 859 // Generate a unique integer id (unique within the entire client session). 860 // Useful for temporary DOM ids. 861 var idCounter = 0; 862 _.uniqueId = function(prefix) { 863 var id = idCounter++; 864 return prefix ? prefix + id : id; 865 }; 866 867 // By default, Underscore uses ERB-style template delimiters, change the 868 // following template settings to use alternative delimiters. 869 _.templateSettings = { 870 evaluate : /<%([\s\S]+?)%>/g, 871 interpolate : /<%=([\s\S]+?)%>/g, 872 escape : /<%-([\s\S]+?)%>/g 873 }; 874 875 // JavaScript micro-templating, similar to John Resig's implementation. 876 // Underscore templating handles arbitrary delimiters, preserves whitespace, 877 // and correctly escapes quotes within interpolated code. 878 _.template = function(str, data) { 879 var c = _.templateSettings; 880 var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' + 881 'with(obj||{}){__p.push(\'' + 882 str.replace(/\\/g, '\\\\') 883 .replace(/'/g, "\\'") 884 .replace(c.escape, function(match, code) { 885 return "',_.escape(" + code.replace(/\\'/g, "'") + "),'"; 886 }) 887 .replace(c.interpolate, function(match, code) { 888 return "'," + code.replace(/\\'/g, "'") + ",'"; 889 }) 890 .replace(c.evaluate || null, function(match, code) { 891 return "');" + code.replace(/\\'/g, "'") 892 .replace(/[\r\n\t]/g, ' ') + "__p.push('"; 893 }) 894 .replace(/\r/g, '\\r') 895 .replace(/\n/g, '\\n') 896 .replace(/\t/g, '\\t') 897 + "');}return __p.join('');"; 898 var func = new Function('obj', tmpl); 899 return data ? func(data) : func; 900 }; 901 902 // The OOP Wrapper 903 // --------------- 904 905 // If Underscore is called as a function, it returns a wrapped object that 906 // can be used OO-style. This wrapper holds altered versions of all the 907 // underscore functions. Wrapped objects may be chained. 908 var wrapper = function(obj) { this._wrapped = obj; }; 909 910 // Expose `wrapper.prototype` as `_.prototype`
911 _.prototype = wrapper.prototype; 912 913 // Helper function to continue chaining intermediate results. 914 var result = function(obj, chain) { 915 return chain ? _(obj).chain() : obj; 916 }; 917 918 // A method to easily add functions to the OOP wrapper. 919 var addToWrapper = function(name, func) { 920 wrapper.prototype[name] = function() { 921 var args = slice.call(arguments); 922 unshift.call(args, this._wrapped); 923 return result(func.apply(_, args), this._chain); 924 }; 925 }; 926 927 // Add all of the Underscore functions to the wrapper object. 928 _.mixin(_); 929 930 // Add all mutator Array functions to the wrapper. 931 each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { 932 var method = ArrayProto[name]; 933 wrapper.prototype[name] = function() { 934 method.apply(this._wrapped, arguments); 935 return result(this._wrapped, this._chain); 936 }; 937 }); 938 939 // Add all accessor Array functions to the wrapper. 940 each(['concat', 'join', 'slice'], function(name) { 941 var method = ArrayProto[name]; 942 wrapper.prototype[name] = function() { 943 return result(method.apply(this._wrapped, arguments), this._chain); 944 }; 945 }); 946 947 // Start chaining a wrapped Underscore object. 948 wrapper.prototype.chain = function() { 949 this._chain = true; 950 return this; 951 }; 952 953 // Extracts the result from a wrapped and chained object. 954 wrapper.prototype.value = function() { 955 return this._wrapped; 956 }; 957 958})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.