From aa663f9fc75d196d2eb1a76f19e2a79b2cf0b53f Mon Sep 17 00:00:00 2001 From: Naomi Seyfer Date: Sat, 9 Mar 2013 11:43:01 -0800 Subject: [PATCH 1/2] Underscore 1.4.4 was making tests run much slower than 1.4.2 ever did. Until we figure out some solution to this (or switch to lo-dash), I'm going to remove 1.4.4 so I can get work done on top of devel. Revert "upgrade package underscore too" This reverts commit 7022916fb4a6f895e93c74b5b831bc4f1ba2c231. --- packages/underscore/underscore.js | 178 +++++++++++++----------------- 1 file changed, 76 insertions(+), 102 deletions(-) diff --git a/packages/underscore/underscore.js b/packages/underscore/underscore.js index a12f0d96cf..1ebe2671b9 100644 --- a/packages/underscore/underscore.js +++ b/packages/underscore/underscore.js @@ -1,6 +1,6 @@ -// Underscore.js 1.4.4 +// Underscore.js 1.4.2 // http://underscorejs.org -// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc. +// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. // Underscore may be freely distributed under the MIT license. (function() { @@ -24,6 +24,7 @@ var push = ArrayProto.push, slice = ArrayProto.slice, concat = ArrayProto.concat, + unshift = ArrayProto.unshift, toString = ObjProto.toString, hasOwnProperty = ObjProto.hasOwnProperty; @@ -60,11 +61,11 @@ } exports._ = _; } else { - root._ = _; + root['_'] = _; } // Current version. - _.VERSION = '1.4.4'; + _.VERSION = '1.4.2'; // Collection Functions // -------------------- @@ -101,8 +102,6 @@ return results; }; - var reduceError = 'Reduce of empty array with no initial value'; - // **Reduce** builds up a single result from a list of values, aka `inject`, // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { @@ -120,7 +119,7 @@ memo = iterator.call(context, memo, value, index, list); } }); - if (!initial) throw new TypeError(reduceError); + if (!initial) throw new TypeError('Reduce of empty array with no initial value'); return memo; }; @@ -131,7 +130,7 @@ if (obj == null) obj = []; if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { if (context) iterator = _.bind(iterator, context); - return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); + return arguments.length > 2 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); } var length = obj.length; if (length !== +length) { @@ -147,7 +146,7 @@ memo = iterator.call(context, memo, obj[index], index, list); } }); - if (!initial) throw new TypeError(reduceError); + if (!initial) throw new TypeError('Reduce of empty array with no initial value'); return memo; }; @@ -178,9 +177,12 @@ // Return all the elements for which a truth test fails. _.reject = function(obj, iterator, context) { - return _.filter(obj, function(value, index, list) { - return !iterator.call(context, value, index, list); - }, context); + var results = []; + if (obj == null) return results; + each(obj, function(value, index, list) { + if (!iterator.call(context, value, index, list)) results[results.length] = value; + }); + return results; }; // Determine whether all of the elements match a truth test. @@ -214,19 +216,20 @@ // Determine if the array or object contains a given value (using `===`). // Aliased as `include`. _.contains = _.include = function(obj, target) { - if (obj == null) return false; + var found = false; + if (obj == null) return found; if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; - return any(obj, function(value) { + found = any(obj, function(value) { return value === target; }); + return found; }; // Invoke a method (with arguments) on every item in a collection. _.invoke = function(obj, method) { var args = slice.call(arguments, 2); - var isFunc = _.isFunction(method); return _.map(obj, function(value) { - return (isFunc ? method : value[method]).apply(value, args); + return (_.isFunction(method) ? method : value[method]).apply(value, args); }); }; @@ -236,10 +239,10 @@ }; // Convenience version of a common use case of `filter`: selecting only objects - // containing specific `key:value` pairs. - _.where = function(obj, attrs, first) { - if (_.isEmpty(attrs)) return first ? null : []; - return _[first ? 'find' : 'filter'](obj, function(value) { + // with specific `key:value` pairs. + _.where = function(obj, attrs) { + if (_.isEmpty(attrs)) return []; + return _.filter(obj, function(value) { for (var key in attrs) { if (attrs[key] !== value[key]) return false; } @@ -247,12 +250,6 @@ }); }; - // Convenience version of a common use case of `find`: getting the first object - // containing specific `key:value` pairs. - _.findWhere = function(obj, attrs) { - return _.where(obj, attrs, true); - }; - // Return the maximum element or (element-based computation). // Can't optimize arrays of integers longer than 65,535 elements. // See: https://bugs.webkit.org/show_bug.cgi?id=80797 @@ -261,7 +258,7 @@ return Math.max.apply(Math, obj); } if (!iterator && _.isEmpty(obj)) return -Infinity; - var result = {computed : -Infinity, value: -Infinity}; + var result = {computed : -Infinity}; each(obj, function(value, index, list) { var computed = iterator ? iterator.call(context, value, index, list) : value; computed >= result.computed && (result = {value : value, computed : computed}); @@ -275,7 +272,7 @@ return Math.min.apply(Math, obj); } if (!iterator && _.isEmpty(obj)) return Infinity; - var result = {computed : Infinity, value: Infinity}; + var result = {computed : Infinity}; each(obj, function(value, index, list) { var computed = iterator ? iterator.call(context, value, index, list) : value; computed < result.computed && (result = {value : value, computed : computed}); @@ -324,7 +321,7 @@ // An internal function used for aggregate "group by" operations. var group = function(obj, value, context, behavior) { var result = {}; - var iterator = lookupIterator(value || _.identity); + var iterator = lookupIterator(value); each(obj, function(value, index) { var key = iterator.call(context, value, index, obj); behavior(result, key, value); @@ -344,7 +341,7 @@ // either a string attribute to count by, or a function that returns the // criterion. _.countBy = function(obj, value, context) { - return group(obj, value, context, function(result, key) { + return group(obj, value, context, function(result, key, value) { if (!_.has(result, key)) result[key] = 0; result[key]++; }); @@ -366,14 +363,12 @@ // Safely convert anything iterable into a real, live array. _.toArray = function(obj) { if (!obj) return []; - if (_.isArray(obj)) return slice.call(obj); - if (obj.length === +obj.length) return _.map(obj, _.identity); + if (obj.length === +obj.length) return slice.call(obj); return _.values(obj); }; // Return the number of elements in an object. _.size = function(obj) { - if (obj == null) return 0; return (obj.length === +obj.length) ? obj.length : _.keys(obj).length; }; @@ -384,7 +379,6 @@ // values in the array. Aliased as `head` and `take`. The **guard** check // allows it to work with `_.map`. _.first = _.head = _.take = function(array, n, guard) { - if (array == null) return void 0; return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; }; @@ -399,7 +393,6 @@ // Get the last element of an array. Passing **n** will return the last N // values in the array. The **guard** check allows it to work with `_.map`. _.last = function(array, n, guard) { - if (array == null) return void 0; if ((n != null) && !guard) { return slice.call(array, Math.max(array.length - n, 0)); } else { @@ -417,7 +410,7 @@ // Trim out all falsy values from an array. _.compact = function(array) { - return _.filter(array, _.identity); + return _.filter(array, function(value){ return !!value; }); }; // Internal implementation of a recursive `flatten` function. @@ -446,11 +439,6 @@ // been sorted, you have the option of using a faster algorithm. // Aliased as `unique`. _.uniq = _.unique = function(array, isSorted, iterator, context) { - if (_.isFunction(isSorted)) { - context = iterator; - iterator = isSorted; - isSorted = false; - } var initial = iterator ? _.map(array, iterator, context) : array; var results = []; var seen = []; @@ -503,7 +491,6 @@ // pairs, or two parallel arrays of the same length -- one of keys, and one of // the corresponding values. _.object = function(list, values) { - if (list == null) return {}; var result = {}; for (var i = 0, l = list.length; i < l; i++) { if (values) { @@ -574,23 +561,25 @@ // Function (ahem) Functions // ------------------ - // Create a function bound to a given object (assigning `this`, and arguments, - // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if - // available. - _.bind = function(func, context) { - if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); - var args = slice.call(arguments, 2); - return function() { - return func.apply(context, args.concat(slice.call(arguments))); - }; - }; + // Reusable constructor function for prototype setting. + var ctor = function(){}; - // Partially apply a function by creating a version that has had some of its - // arguments pre-filled, without changing its dynamic `this` context. - _.partial = function(func) { - var args = slice.call(arguments, 1); - return function() { - return func.apply(this, args.concat(slice.call(arguments))); + // Create a function bound to a given object (assigning `this`, and arguments, + // optionally). Binding with arguments is also known as `curry`. + // Delegates to **ECMAScript 5**'s native `Function.bind` if available. + // We check for `func.bind` first, to fail fast when `func` is undefined. + _.bind = function bind(func, context) { + var bound, args; + if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); + if (!_.isFunction(func)) throw new TypeError; + args = slice.call(arguments, 2); + return bound = function() { + if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); + ctor.prototype = func.prototype; + var self = new ctor; + var result = func.apply(self, args.concat(slice.call(arguments))); + if (Object(result) === result) return result; + return self; }; }; @@ -598,7 +587,7 @@ // all callbacks defined on an object belong to it. _.bindAll = function(obj) { var funcs = slice.call(arguments, 1); - if (funcs.length === 0) funcs = _.functions(obj); + if (funcs.length == 0) funcs = _.functions(obj); each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); return obj; }; @@ -629,26 +618,25 @@ // Returns a function, that, when invoked, will only be triggered at most once // during a given window of time. _.throttle = function(func, wait) { - var context, args, timeout, result; - var previous = 0; - var later = function() { - previous = new Date; - timeout = null; - result = func.apply(context, args); - }; + var context, args, timeout, throttling, more, result; + var whenDone = _.debounce(function(){ more = throttling = false; }, wait); return function() { - var now = new Date; - var remaining = wait - (now - previous); - context = this; - args = arguments; - if (remaining <= 0) { - clearTimeout(timeout); + context = this; args = arguments; + var later = function() { timeout = null; - previous = now; + if (more) { + result = func.apply(context, args); + } + whenDone(); + }; + if (!timeout) timeout = setTimeout(later, wait); + if (throttling) { + more = true; + } else { + throttling = true; result = func.apply(context, args); - } else if (!timeout) { - timeout = setTimeout(later, remaining); } + whenDone(); return result; }; }; @@ -766,10 +754,8 @@ // Extend a given object with all the properties in passed-in object(s). _.extend = function(obj) { each(slice.call(arguments, 1), function(source) { - if (source) { - for (var prop in source) { - obj[prop] = source[prop]; - } + for (var prop in source) { + obj[prop] = source[prop]; } }); return obj; @@ -798,10 +784,8 @@ // Fill in a given object with default properties. _.defaults = function(obj) { each(slice.call(arguments, 1), function(source) { - if (source) { - for (var prop in source) { - if (obj[prop] == null) obj[prop] = source[prop]; - } + for (var prop in source) { + if (obj[prop] == null) obj[prop] = source[prop]; } }); return obj; @@ -966,7 +950,7 @@ // Is a given object a finite number? _.isFinite = function(obj) { - return isFinite(obj) && !isNaN(parseFloat(obj)); + return _.isNumber(obj) && isFinite(obj); }; // Is the given value `NaN`? (NaN is the only number which does not equal itself). @@ -1012,9 +996,7 @@ // Run a function **n** times. _.times = function(n, iterator, context) { - var accum = Array(n); - for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i); - return accum; + for (var i = 0; i < n; i++) iterator.call(context, i); }; // Return a random integer between min and max (inclusive). @@ -1023,7 +1005,7 @@ max = min; min = 0; } - return min + Math.floor(Math.random() * (max - min + 1)); + return min + (0 | Math.random() * (max - min + 1)); }; // List of HTML entities for escaping. @@ -1079,7 +1061,7 @@ // Useful for temporary DOM ids. var idCounter = 0; _.uniqueId = function(prefix) { - var id = ++idCounter + ''; + var id = idCounter++; return prefix ? prefix + id : id; }; @@ -1114,7 +1096,6 @@ // Underscore templating handles arbitrary delimiters, preserves whitespace, // and correctly escapes quotes within interpolated code. _.template = function(text, data, settings) { - var render; settings = _.defaults({}, settings, _.templateSettings); // Combine delimiters into one regular expression via alternation. @@ -1130,18 +1111,11 @@ text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { source += text.slice(index, offset) .replace(escaper, function(match) { return '\\' + escapes[match]; }); - - if (escape) { - source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; - } - if (interpolate) { - source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; - } - if (evaluate) { - source += "';\n" + evaluate + "\n__p+='"; - } + source += + escape ? "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'" : + interpolate ? "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'" : + evaluate ? "';\n" + evaluate + "\n__p+='" : ''; index = offset + match.length; - return match; }); source += "';\n"; @@ -1153,7 +1127,7 @@ source + "return __p;\n"; try { - render = new Function(settings.variable || 'obj', '_', source); + var render = new Function(settings.variable || 'obj', '_', source); } catch (e) { e.source = source; throw e; From 0bac1b3e2d356c16d806c4c2bfc763d56cb9f67c Mon Sep 17 00:00:00 2001 From: Naomi Seyfer Date: Sat, 9 Mar 2013 11:48:26 -0800 Subject: [PATCH 2/2] Remove underscore version bump from History.md Debatably, we should also downgrade the dev bundle? Unsure about this. --- History.md | 1 - 1 file changed, 1 deletion(-) diff --git a/History.md b/History.md index fa3b148c62..90ccfd08ef 100644 --- a/History.md +++ b/History.md @@ -38,7 +38,6 @@ * Upgraded dependencies: * mongodb driver to version 1.2.13 (from 0.1.11) - * underscore to version 1.4.4 (from 1.4.2) * mime module removed (it was unused)