diff --git a/Rakefile b/Rakefile
new file mode 100644
index 000000000..6af14bb6d
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,9 @@
+require 'rubygems'
+require 'closure-compiler'
+
+desc "Use the Closure Compiler to compress Underscore.js"
+task :build do
+ js = File.open('underscore.js', 'r')
+ min = Closure::Compiler.new.compile(js)
+ File.open('underscore-min.js', 'w') {|f| f.write(min) }
+end
\ No newline at end of file
diff --git a/index.html b/index.html
index 0c48b1c99..fd49a24fa 100644
--- a/index.html
+++ b/index.html
@@ -998,7 +998,10 @@
Change Log
-
+ Added isDate, isNaN, and isNull, for completeness.
+ Optimizations for isEqual when checking equality between Arrays
+ or Dates. _.keys is now 25%–2X faster (depending on your
+ browser) which speeds up the functions that rely on it, such as _.each.
diff --git a/underscore-min.js b/underscore-min.js
index 80bfa08c2..18b4bcfbc 100644
--- a/underscore-min.js
+++ b/underscore-min.js
@@ -1,15 +1,15 @@
-(function(){var j=this,m=j._,i=function(a){this._wrapped=a},l=typeof StopIteration!=="undefined"?StopIteration:"__break__",b=j._=function(a){return new i(a)};if(typeof exports!=="undefined")exports._=b;b.VERSION="0.4.6";b.each=function(a,c,d){try{if(a.forEach)a.forEach(c,d);else if(a.length)for(var e=0,f=a.length;e=e.computed&&(e={value:f,computed:g})});
-return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;gf?1:0}),"value")};b.sortedIndex=function(a,c,d){d=d||b.identity;for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.zip=function(){for(var a=b.toArray(arguments),c=
-b.max(b.pluck(a,"length")),d=new Array(c),e=0;e0?f-c:c-f)>=0)return e;e[g++]=f}};b.bind=function(a,c){var d=b.rest(arguments,2);return function(){return a.apply(c||j,d.concat(b.toArray(arguments)))}};b.bindAll=function(){var a=Array.prototype.pop.call(arguments);b.each(arguments,function(c){a[c]=b.bind(a[c],a)})};b.delay=function(a,c){var d=b.rest(arguments,2);return setTimeout(function(){return a.apply(a,d)},c)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(b.rest(arguments)))};b.wrap=function(a,c){return function(){var d=
-[a].concat(b.toArray(arguments));return c.apply(c,d)}};b.compose=function(){var a=b.toArray(arguments);return function(){for(var c=a.length-1;c>=0;c--)arguments=[a[c].apply(this,arguments)];return arguments[0]}};b.keys=function(a){return b.map(a,function(c,d){return d})};b.values=function(a){return b.map(a,b.identity)};b.extend=function(a,c){for(var d in c)a[d]=c[d];return a};b.clone=function(a){if(b.isArray(a))return a.slice(0);return b.extend({},a)};b.isEqual=function(a,c){if(a===c)return true;
-var d=typeof a,e=typeof c;if(d!=e)return false;if(a==c)return true;if(a.isEqual)return a.isEqual(c);if(b.isNumber(a)&&b.isNumber(c)&&isNaN(a)&&isNaN(c))return true;if(d!=="object")return false;d=b.keys(a);e=b.keys(c);if(d.length!=e.length)return false;for(var f in a)if(!b.isEqual(a[f],c[f]))return false;return true};b.isEmpty=function(a){return(b.isArray(a)?a:b.values(a)).length==0};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=function(a){return Object.prototype.toString.call(a)==
-"[object Array]"};b.isFunction=function(a){return Object.prototype.toString.call(a)=="[object Function]"};b.isString=function(a){return Object.prototype.toString.call(a)=="[object String]"};b.isNumber=function(a){return Object.prototype.toString.call(a)=="[object Number]"};b.isUndefined=function(a){return typeof a=="undefined"};b.noConflict=function(){j._=m;return this};b.identity=function(a){return a};b.breakLoop=function(){throw l;};var n=0;b.uniqueId=function(a){var c=n++;return a?a+c:c};b.functions=
-function(){var a=[];for(var c in b)Object.prototype.hasOwnProperty.call(b,c)&&a.push(c);return b.without(a,"VERSION","prototype","noConflict").sort()};b.template=function(a,c){a=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g," ").split("<%").join("\t").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split("\t").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');");return c?
-a(c):a};b.forEach=b.each;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.filter=b.select;b.every=b.all;b.some=b.any;b.head=b.first;b.tail=b.rest;b.methods=b.functions;var k=function(a,c){return c?b(a).chain():a};b.each(b.functions(),function(a){i.prototype[a]=function(){Array.prototype.unshift.call(arguments,this._wrapped);return k(b[a].apply(b,arguments),this._chain)}});b.each(["pop","push","reverse","shift","sort","splice","unshift"],function(a){i.prototype[a]=function(){Array.prototype[a].apply(this._wrapped,
-arguments);return k(this._wrapped,this._chain)}});b.each(["concat","join","slice"],function(a){i.prototype[a]=function(){return k(Array.prototype[a].apply(this._wrapped,arguments),this._chain)}});i.prototype.chain=function(){this._chain=true;return this};i.prototype.value=function(){return this._wrapped}})();
+(function(){var k=this,n=k._,i=function(a){this._wrapped=a},m=typeof StopIteration!=="undefined"?StopIteration:"__break__",b=k._=function(a){return new i(a)};if(typeof exports!=="undefined")exports._=b;var j=Object.prototype;b.VERSION="0.4.7";b.each=function(a,c,d){try{if(a.forEach)a.forEach(c,d);else if(a.length)for(var e=0,f=a.length;e=e.computed&&
+(e={value:f,computed:g})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;gf?1:0}),"value")};b.sortedIndex=function(a,c,d){d=d||b.identity;for(var e=0,f=a.length;e<
+f;){var g=e+f>>1;d(a[g])=0})})};b.zip=function(){for(var a=
+b.toArray(arguments),c=b.max(b.pluck(a,"length")),d=new Array(c),e=0;e0?f-c:c-f)>=0)return e;e[g++]=f}};b.bind=function(a,c){var d=b.rest(arguments,2);return function(){return a.apply(c||k,d.concat(b.toArray(arguments)))}};b.bindAll=function(){var a=Array.prototype.pop.call(arguments);b.each(arguments,function(c){a[c]=b.bind(a[c],a)})};b.delay=function(a,c){var d=b.rest(arguments,2);return setTimeout(function(){return a.apply(a,d)},c)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(b.rest(arguments)))};b.wrap=function(a,c){return function(){var d=
+[a].concat(b.toArray(arguments));return c.apply(c,d)}};b.compose=function(){var a=b.toArray(arguments);return function(){for(var c=b.toArray(arguments),d=a.length-1;d>=0;d--)c=[a[d].apply(this,c)];return c[0]}};b.keys=function(a){if(b.isArray(a))return b.range(0,a.length);var c=[];for(var d in a)j.hasOwnProperty.call(a,d)&&c.push(d);return c};b.values=function(a){return b.map(a,b.identity)};b.extend=function(a,c){for(var d in c)a[d]=c[d];return a};b.clone=function(a){if(b.isArray(a))return a.slice(0);
+return b.extend({},a)};b.isEqual=function(a,c){if(a===c)return true;var d=typeof a;if(d!=typeof c)return false;if(a==c)return true;if(b.isDate(a)&&b.isDate(c))return a.getTime()===c.getTime();if(a.isEqual)return a.isEqual(c);if(b.isNaN(a)&&b.isNaN(c))return true;if(d!=="object")return false;if(!b.isUndefined(a.length)&&a.length!==c.length)return false;d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return false;for(var f in a)if(!b.isEqual(a[f],c[f]))return false;return true};b.isEmpty=function(a){return b.keys(a).length==
+0};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=function(a){return j.toString.call(a)=="[object Array]"};b.isFunction=function(a){return j.toString.call(a)=="[object Function]"};b.isString=function(a){return j.toString.call(a)=="[object String]"};b.isNumber=function(a){return j.toString.call(a)=="[object Number]"};b.isDate=function(a){return j.toString.call(a)=="[object Date]"};b.isNaN=function(a){return b.isNumber(a)&&isNaN(a)};b.isNull=function(a){return a===null};b.isUndefined=
+function(a){return typeof a=="undefined"};b.noConflict=function(){k._=n;return this};b.identity=function(a){return a};b.breakLoop=function(){throw m;};var o=0;b.uniqueId=function(a){var c=o++;return a?a+c:c};b.functions=function(){return b.without(b.keys(b),"VERSION","prototype","noConflict").sort()};b.template=function(a,c){a=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g," ").split("<%").join("\t").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,
+"',$1,'").split("\t").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');");return c?a(c):a};b.forEach=b.each;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.filter=b.select;b.every=b.all;b.some=b.any;b.head=b.first;b.tail=b.rest;b.methods=b.functions;var l=function(a,c){return c?b(a).chain():a};b.each(b.functions(),function(a){i.prototype[a]=function(){Array.prototype.unshift.call(arguments,this._wrapped);return l(b[a].apply(b,arguments),this._chain)}});b.each(["pop",
+"push","reverse","shift","sort","splice","unshift"],function(a){i.prototype[a]=function(){Array.prototype[a].apply(this._wrapped,arguments);return l(this._wrapped,this._chain)}});b.each(["concat","join","slice"],function(a){i.prototype[a]=function(){return l(Array.prototype[a].apply(this._wrapped,arguments),this._chain)}});i.prototype.chain=function(){this._chain=true;return this};i.prototype.value=function(){return this._wrapped}})();
diff --git a/underscore.js b/underscore.js
index cbdf3e2e7..49d5b08c1 100644
--- a/underscore.js
+++ b/underscore.js
@@ -31,7 +31,7 @@
if (typeof exports !== 'undefined') exports._ = _;
// Maintain a reference to the Object prototype for quick access.
- var oproto = Object.prototype;
+ var objPro = Object.prototype;
// Current version.
_.VERSION = '0.4.7';
@@ -395,7 +395,7 @@
_.keys = function(obj) {
if(_.isArray(obj)) return _.range(0, obj.length);
var keys = [];
- for (var key in obj) if (oproto.hasOwnProperty.call(obj, key)) keys.push(key);
+ for (var key in obj) if (objPro.hasOwnProperty.call(obj, key)) keys.push(key);
return keys;
};
@@ -456,27 +456,27 @@
// Is a given value a real Array?
_.isArray = function(obj) {
- return oproto.toString.call(obj) == '[object Array]';
+ return objPro.toString.call(obj) == '[object Array]';
};
// Is a given value a Function?
_.isFunction = function(obj) {
- return oproto.toString.call(obj) == '[object Function]';
+ return objPro.toString.call(obj) == '[object Function]';
};
// Is a given value a String?
_.isString = function(obj) {
- return oproto.toString.call(obj) == '[object String]';
+ return objPro.toString.call(obj) == '[object String]';
};
// Is a given value a Number?
_.isNumber = function(obj) {
- return oproto.toString.call(obj) == '[object Number]';
+ return objPro.toString.call(obj) == '[object Number]';
};
// Is a given value a Date?
_.isDate = function(obj) {
- return oproto.toString.call(obj) == '[object Date]';
+ return objPro.toString.call(obj) == '[object Date]';
};
// Is the given value NaN -- this one is interesting. NaN != NaN, and