diff --git a/.cupboard b/.cupboard index f2d80a5..46d2b19 100644 --- a/.cupboard +++ b/.cupboard @@ -1,2 +1,2 @@ [commands] -proj = open project.tmproj +proj = subl --project project.sublime-project diff --git a/node_modules/Structr b/node_modules/Structr new file mode 120000 index 0000000..c315f79 --- /dev/null +++ b/node_modules/Structr @@ -0,0 +1 @@ +/usr/local/lib/node_modules/Structr \ No newline at end of file diff --git a/node_modules/celeri b/node_modules/celeri new file mode 120000 index 0000000..6dd85c6 --- /dev/null +++ b/node_modules/celeri @@ -0,0 +1 @@ +/usr/local/lib/node_modules/celeri \ No newline at end of file diff --git a/node_modules/ini/.gitignore b/node_modules/ini/.gitignore new file mode 100644 index 0000000..c1b5eb0 --- /dev/null +++ b/node_modules/ini/.gitignore @@ -0,0 +1,2 @@ +.cupboard +node_modules diff --git a/node_modules/ini/LICENSE b/node_modules/ini/LICENSE new file mode 100644 index 0000000..05a4010 --- /dev/null +++ b/node_modules/ini/LICENSE @@ -0,0 +1,23 @@ +Copyright 2009, 2010, 2011 Isaac Z. Schlueter. +All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/ini/README.md b/node_modules/ini/README.md new file mode 100644 index 0000000..cd434b7 --- /dev/null +++ b/node_modules/ini/README.md @@ -0,0 +1,71 @@ +An ini format parser and serializer for node. + +Sections are treated as nested objects. Items before the first heading +are saved on the object directly. + +## Usage + +Consider an ini-file `config.ini` that looks like this: + + ; this comment is beeing ignored + scope = global + + [database] + user = dbuser + password = dbpassword + database = use_this_database + + [paths.default] + datadir = /var/lib/data + +You can read, manipulate and write the ini-file like so: + + var fs = require('fs') + , ini = require('ini') + + var config = ini.parse(fs.readFileSync('./config.ini', 'utf-8')) + + config.scope = 'local' + config.database.database = 'use_another_database' + config.paths.default.tmpdir = '/tmp' + delete config.paths.default.datadir + + fs.writeFileSync('./config_modified.ini', ini.stringify(config, 'section')) + +This will result in a file called `config_modified.ini` being written to the filesystem with the following content: + + [section] + scope = local + [section.database] + user = dbuser + password = dbpassword + database = use_another_database + [section.paths.default] + tmpdir = /tmp + +## API + +### decode(inistring) +Decode the ini-style formatted `inistring` into a nested object. + +### parse(inistring) +Alias for `decode(inistring)` + +### encode(object, [section]) +Encode the object `object` into an ini-style formatted string. If the optional parameter `section` is given, then all top-level properties of the object are put into this section and the `section`-string is prepended to all sub-sections, see the usage example above. + +### stringify(object, [section]) +Alias for `encode(object, [section])` + +### safe(val) +Escapes the string `val` such that it is safe to be used as a key or value in an ini-file. Basically escapes quotes. For example + + ini.safe('"unsafe string"') + +would result in + + "\"unsafe string\"" + +### unsafe(val) +Unescapes the string `val` + diff --git a/node_modules/ini/ini.js b/node_modules/ini/ini.js new file mode 100644 index 0000000..0c0bc62 --- /dev/null +++ b/node_modules/ini/ini.js @@ -0,0 +1,106 @@ +var fs = require('fs'); + + +exports.parse = exports.decode = decode +exports.stringify = exports.encode = encode +exports.load = load; + +exports.safe = safe +exports.unsafe = unsafe + +function encode (obj, section) { + var children = [] + , out = "" + + Object.keys(obj).forEach(function (k, _, __) { + var val = obj[k] + if (val && typeof val === "object") { + children.push(k) + } else { + out += safe(k) + " = " + safe(val) + "\n" + } + }) + + if (section && out.length) { + out = "[" + safe(section) + "]" + "\n" + out + "\n\n" + } + + children.forEach(function (k, _, __) { + out += encode(obj[k], (section ? section + ":" : "") + k) + }) + + return out +} + +function load(source) +{ + return decode(fs.readFileSync(source,'utf8')); +} + +function decode (str) { + var out = {} + , p = out + , section = null + , state = "START" + // section |key = value + , re = /^\[([^\]]*)\]$|^([^=]+)(=(.*))?$/i + , lines = str.replace(/;[^\r\n]+/g,'').split(/[\r\n]+/g) + , section = null + + + lines.forEach(function (line, _, __) { + //line = line + var rem = line.indexOf(";") + if (rem !== -1) line = line.substr(0, rem)//.trim() + if (!line) return + var match = line.match(re) + if (!match) return + if (match[1] !== undefined) { + section = unsafe(match[1]) + p = out[section] = out[section] || {} + return + } + var key = unsafe(match[2]) + , value = match[3] ? unsafe((match[4] || "")) : true + p[key] = value + }) + + // {a:{y:1},"a.b":{x:2}} --> {a:{y:1,b:{x:2}}} + // use a filter to return the keys that have to be deleted. + Object.keys(out).filter(function (k, _, __) { + if (!out[k] || typeof out[k] !== "object") return false + // see if the parent section is also an object. + // if so, add it to that, and mark this one for deletion + var parts = k.split(":") + , p = out + , l = parts.pop() + parts.forEach(function (part, _, __) { + if (!p[part] || typeof p[part] !== "object") p[part] = {} + p = p[part] + }) + if (p === out) return false + p[l] = out[k] + return true + }).forEach(function (del, _, __) { + delete out[del] + }) + + return out +} + +function safe (val) { + return ( typeof val !== "string" + || val.match(/[\r\n]/) + || (val.length > 1 + && val.charAt(0) === "\"" + && val.slice(-1) === "\"") + || val !== val.trim() ) ? JSON.stringify(val) : val +} + +function unsafe (val) { + val = (val || "").trim() + if (val.charAt(0) === "\"" && val.slice(-1) === "\"") { + try { val = JSON.parse(val) } catch (_) {} + } + return val +} diff --git a/node_modules/ini/package.json b/node_modules/ini/package.json new file mode 100644 index 0000000..6bf81b8 --- /dev/null +++ b/node_modules/ini/package.json @@ -0,0 +1,24 @@ +{ + "author": "Isaac Z. Schlueter (http://blog.izs.me/)", + "name": "ini", + "description": "An ini encoder/decoder for node", + "version": "1.0.1", + "repository": { + "type": "git", + "url": "git://github.com/isaacs/ini.git" + }, + "main": "ini.js", + "scripts": { + "test": "node ini.js" + }, + "engines": { + "node": "*" + }, + "dependencies": {}, + "devDependencies": { + "tap": "~0.0.9" + }, + "scripts": { + "test": "tap test/*.js" + } +} diff --git a/node_modules/ini/test/fixtures/foo.ini b/node_modules/ini/test/fixtures/foo.ini new file mode 100644 index 0000000..aa4b177 --- /dev/null +++ b/node_modules/ini/test/fixtures/foo.ini @@ -0,0 +1,18 @@ +o = p + + a with spaces = b c + +; wrap in quotes to JSON-decode and preserve spaces +" xa n p " = "\"\r\nyoyoyo\r\r\n" + +; a section +[a] +av = a val +e = { o: p, a: { av: a val, b: { c: { e: "this value" } } } } +j = "{ o: "p", a: { av: "a val", b: { c: { e: "this value" } } } }" + +; nested child without middle parent +; should create otherwise-empty a.b +[a.b.c] +e = 1 +j = 2 diff --git a/node_modules/ini/test/foo.js b/node_modules/ini/test/foo.js new file mode 100644 index 0000000..31af103 --- /dev/null +++ b/node_modules/ini/test/foo.js @@ -0,0 +1,40 @@ +var i = require("../") + , tap = require("tap") + , test = tap.test + , fs = require("fs") + , path = require("path") + , fixture = path.resolve(__dirname, "./fixtures/foo.ini") + , data = fs.readFileSync(fixture, "utf8") + , d + , expectE = 'o = p\n' + + 'a with spaces = b c\n' + + '" xa n p " = "\\"\\r\\nyoyoyo\\r\\r\\n"\n' + + '[a]\n' + + 'av = a val\n' + + 'e = { o: p, a: ' + + '{ av: a val, b: { c: { e: "this value" ' + + '} } } }\nj = "\\"{ o: \\"p\\", a: { av:' + + ' \\"a val\\", b: { c: { e: \\"this value' + + '\\" } } } }\\""\n[a.b.c]\ne = 1\nj = 2\n' + , expectD = + { o: 'p', + 'a with spaces': 'b c', + " xa n p ":'"\r\nyoyoyo\r\r\n', + a: + { av: 'a val', + e: '{ o: p, a: { av: a val, b: { c: { e: "this value" } } } }', + j: '"{ o: "p", a: { av: "a val", b: { c: { e: "this value" } } } }"', + b: { c: { e: '1', j: '2' } } } + } + +test("decode from file", function (t) { + d = i.decode(data) + t.deepEqual(d, expectD) + t.end() +}) + +test("encode from data", function (t) { + e = i.encode(expectD) + t.deepEqual(e, expectE) + t.end() +}) diff --git a/node_modules/node-fs/LICENSE b/node_modules/node-fs/LICENSE new file mode 100644 index 0000000..014c16c --- /dev/null +++ b/node_modules/node-fs/LICENSE @@ -0,0 +1,18 @@ +Copyright 2010 Bruno Pedro. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/node-fs/README.md b/node_modules/node-fs/README.md new file mode 100644 index 0000000..dadb3e9 --- /dev/null +++ b/node_modules/node-fs/README.md @@ -0,0 +1,6 @@ +node-fs is an extension to the original [nodejs](http://nodejs.org) [fs library](http://nodejs.org/docs/v0.3.1/api/fs.html), offering new functionalities. See example.js for an example of how to use it. + +Right now, the following new operations are supported: + +* mkdir(path, mode, [recursive], [callback]): if the 'recursive' parameter is true, creates a directory recursively; +* mkdirSync(path, mode, [recursive]): if the 'recursive' parameter is true, synchronously creates a directory recursively. \ No newline at end of file diff --git a/node_modules/node-fs/example.js b/node_modules/node-fs/example.js new file mode 100644 index 0000000..e768f21 --- /dev/null +++ b/node_modules/node-fs/example.js @@ -0,0 +1,32 @@ +// +// Require our fs lib, not the original. +// +var fs = require('./lib/fs'); + +// +// Example with non-recursion. +// +fs.mkdir('/tmp/example_dir/first/second/third/fourth/fifth', 0777, function (err) { + if (err) { + console.log(err); + } else { + console.log('Directory created'); + } +}); + +// +// Example with recursion -- notice the parameter +// right before the callback function. +// +fs.mkdir('/tmp/example_dir/first/second/third/fourth/fifth', 0777, true, function (err) { + if (err) { + console.log(err); + } else { + console.log('Directory created'); + } +}); + +// +// Synchronous example with recursion. +// +fs.mkdirSync('/tmp/example_sync/first/second/third/fourth/fifth', 0777, true); diff --git a/node_modules/node-fs/lib/fs.js b/node_modules/node-fs/lib/fs.js new file mode 100644 index 0000000..830f341 --- /dev/null +++ b/node_modules/node-fs/lib/fs.js @@ -0,0 +1,109 @@ +(function () { + 'use strict'; + + var fs = require('fs'), + mkdirOrig = fs.mkdir, + mkdirSyncOrig = fs.mkdirSync; + + /** + * Offers functionality similar to mkdir -p + * + * Asynchronous operation. No arguments other than a possible exception + * are given to the completion callback. + */ + function mkdir_p (path, mode, callback, position) { + var parts = require('path').normalize(path).split('/'); + + mode = mode || process.umask(); + position = position || 0; + + if (position >= parts.length) { + return callback(); + } + + var directory = parts.slice(0, position + 1).join('/') || '/'; + fs.stat(directory, function(err) { + if (err === null) { + mkdir_p(path, mode, callback, position + 1); + } else { + mkdirOrig(directory, mode, function (err) { + if (err && err.errno != 17) { + return callback(err); + } else { + mkdir_p(path, mode, callback, position + 1); + } + }); + } + }); + } + + function mkdirSync_p(path, mode, position) { + var parts = require('path').normalize(path).split('/'); + + mode = mode || process.umask(); + position = position || 0; + + if (position >= parts.length) { + return true; + } + + var directory = parts.slice(0, position + 1).join('/') || '/'; + try { + fs.statSync(directory); + mkdirSync_p(path, mode, position + 1); + } catch (e) { + try { + mkdirSyncOrig(directory, mode); + mkdirSync_p(path, mode, position + 1); + } catch (e) { + if (e.errno != 17) { + throw err; + } + mkdirSync_p(path, mode, position + 1); + } + } + } + + /** + * Polymorphic approach to fs.mkdir() + * + * If the third parameter is boolean and true assume that + * caller wants recursive operation. + */ + fs.mkdir = function (path, mode, recursive, callback) { + if (typeof recursive !== 'boolean') { + callback = recursive; + recursive = false; + } + + if (typeof callback !== 'function') { + callback = function () {}; + } + + if (!recursive) { + mkdirOrig(path, mode, callback); + } else { + mkdir_p(path, mode, callback); + } + } + + /** + * Polymorphic approach to fs.mkdirSync() + * + * If the third parameter is boolean and true assume that + * caller wants recursive operation. + */ + fs.mkdirSync = function (path, mode, recursive) { + if (typeof recursive !== 'boolean') { + recursive = false; + } + + if (!recursive) { + mkdirSyncOrig(path, mode); + } else { + mkdirSync_p(path, mode); + } + } + + module.exports = fs; +}()); diff --git a/node_modules/node-fs/package.json b/node_modules/node-fs/package.json new file mode 100644 index 0000000..64d282e --- /dev/null +++ b/node_modules/node-fs/package.json @@ -0,0 +1,28 @@ +{ + "name": "node-fs", + "description": "node-fs is an extension to the original nodejs fs library, offering new functionalities.", + "version": "0.1.0", + "author": "Bruno Pedro ", + + "repository": { + "type" : "git", + "url": "git://github.com/bpedro/node-fs.git" + }, + + "os": [ "linux", "darwin", "freebsd" ], + + "directories": { + "lib": "./lib/" + }, + + "main": "./lib/fs", + + "engines": { + "node": ">=0.1.97" + }, + + "licenses": [{ + "type" : "MIT", + "url" : "https://github.com/bpedro/node-fs/raw/master/LICENSE" + }] +} diff --git a/node_modules/sk b/node_modules/sk new file mode 120000 index 0000000..b9da99e --- /dev/null +++ b/node_modules/sk @@ -0,0 +1 @@ +/usr/local/lib/node_modules/sk \ No newline at end of file diff --git a/node_modules/supervisord b/node_modules/supervisord new file mode 120000 index 0000000..16b5d44 --- /dev/null +++ b/node_modules/supervisord @@ -0,0 +1 @@ +/usr/local/lib/node_modules/supervisord \ No newline at end of file diff --git a/node_modules/underscore/.npmignore b/node_modules/underscore/.npmignore new file mode 100644 index 0000000..2ce2684 --- /dev/null +++ b/node_modules/underscore/.npmignore @@ -0,0 +1,3 @@ +test/ +Rakefile +docs/ \ No newline at end of file diff --git a/node_modules/underscore/LICENSE b/node_modules/underscore/LICENSE new file mode 100644 index 0000000..58c73b9 --- /dev/null +++ b/node_modules/underscore/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2011 Jeremy Ashkenas, DocumentCloud + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/underscore/README b/node_modules/underscore/README new file mode 100644 index 0000000..408145a --- /dev/null +++ b/node_modules/underscore/README @@ -0,0 +1,19 @@ + __ + /\ \ __ + __ __ ___ \_\ \ __ _ __ ____ ___ ___ _ __ __ /\_\ ____ +/\ \/\ \ /' _ `\ /'_ \ /'__`\/\ __\/ ,__\ / ___\ / __`\/\ __\/'__`\ \/\ \ /',__\ +\ \ \_\ \/\ \/\ \/\ \ \ \/\ __/\ \ \//\__, `\/\ \__//\ \ \ \ \ \//\ __/ __ \ \ \/\__, `\ + \ \____/\ \_\ \_\ \___,_\ \____\\ \_\\/\____/\ \____\ \____/\ \_\\ \____\/\_\ _\ \ \/\____/ + \/___/ \/_/\/_/\/__,_ /\/____/ \/_/ \/___/ \/____/\/___/ \/_/ \/____/\/_//\ \_\ \/___/ + \ \____/ + \/___/ + +Underscore is a utility-belt library for JavaScript that provides +support for the usual functional suspects (each, map, reduce, filter...) +without extending any core JavaScript objects. + +For Docs, License, Tests, and pre-packed downloads, see: +http://documentcloud.github.com/underscore/ + +Many thanks to our contributors: +https://github.com/documentcloud/underscore/contributors diff --git a/node_modules/underscore/index.html b/node_modules/underscore/index.html new file mode 100644 index 0000000..fe8321a --- /dev/null +++ b/node_modules/underscore/index.html @@ -0,0 +1,1759 @@ + + + + + + Underscore.js + + + + +
+ +

Underscore.js

+ +

+ Underscore is a + utility-belt library for JavaScript that provides a lot of the + functional programming support that you would expect in + Prototype.js + (or Ruby), + but without extending any of the built-in JavaScript objects. It's the + tie to go along with jQuery's tux. +

+ +

+ Underscore provides 60-odd functions that support both the usual + functional suspects: map, select, invoke — + as well as more specialized helpers: function binding, javascript + templating, deep equality testing, and so on. It delegates to built-in + functions, if present, so modern browsers will use the + native implementations of forEach, map, reduce, + filter, every, some and indexOf. +

+ +

+ A complete Test & Benchmark Suite + is included for your perusal. +

+ +

+ You may also read through the annotated source code. +

+ +

+ The project is + hosted on GitHub. + You can report bugs and discuss features on the + issues page, + on Freenode in the #documentcloud channel, + or send tweets to @documentcloud. +

+ +

+ Underscore is an open-source component of DocumentCloud. +

+ +

Downloads (Right-click, and use "Save As")

+ + + + + + + + + + +
Development Version (1.2.2)34kb, Uncompressed with Comments
Production Version (1.2.2)< 4kb, Minified and Gzipped
+ +

Table of Contents

+ + Object-Oriented and Functional Styles + +

+ Collections +
+ each, map, + reduce, reduceRight, + find, filter, + reject, all, + any, include, + invoke, pluck, + max, min, + sortBy, groupBy, + sortedIndex, shuffle, + toArray, size +

+ +

+ Arrays +
+ first, initial, last, rest, + compact, flatten, without, + union, intersection, difference, + uniq, zip, indexOf, + lastIndexOf, range +

+ +

+ Functions +
+ bind, bindAll, + memoize, delay, defer, + throttle, debounce, + once, after, wrap, compose +

+ +

+ Objects +
+ keys, values, + functions, extend, defaults, clone, tap, + isEqual, isEmpty, isElement, + isArray, isArguments, isFunction, isString, + isNumber, isBoolean, isDate, isRegExp + isNaN, isNull, + isUndefined + +

+ +

+ Utility +
+ noConflict, + identity, times, + mixin, uniqueId, + escape, template +

+ +

+ Chaining +
+ chain, value +

+ +
+ +

Object-Oriented and Functional Styles

+ +

+ You can use Underscore in either an object-oriented or a functional style, + depending on your preference. The following two lines of code are + identical ways to double a list of numbers. +

+ +
+_.map([1, 2, 3], function(n){ return n * 2; });
+_([1, 2, 3]).map(function(n){ return n * 2; });
+ +

+ Using the object-oriented style allows you to chain together methods. Calling + chain on a wrapped object will cause all future method calls to + return wrapped objects as well. When you've finished the computation, + use value to retrieve the final value. Here's an example of chaining + together a map/flatten/reduce, in order to get the word count of + every word in a song. +

+ +
+var lyrics = [
+  {line : 1, words : "I'm a lumberjack and I'm okay"},
+  {line : 2, words : "I sleep all night and I work all day"},
+  {line : 3, words : "He's a lumberjack and he's okay"},
+  {line : 4, words : "He sleeps all night and he works all day"}
+];
+
+_(lyrics).chain()
+  .map(function(line) { return line.words.split(' '); })
+  .flatten()
+  .reduce(function(counts, word) {
+    counts[word] = (counts[word] || 0) + 1;
+    return counts;
+}, {}).value();
+
+=> {lumberjack : 2, all : 4, night : 2 ... }
+ +

+ In addition, the + Array prototype's methods + are proxied through the chained Underscore object, so you can slip a + reverse or a push into your chain, and continue to + modify the array. +

+ +

Collection Functions (Arrays or Objects)

+ +

+ each_.each(list, iterator, [context]) + Alias: forEach +
+ Iterates over a list of elements, yielding each in turn to an iterator + function. The iterator is bound to the context object, if one is + passed. Each invocation of iterator is called with three arguments: + (element, index, list). If list is a JavaScript object, iterator's + arguments will be (value, key, list). Delegates to the native + forEach function if it exists. +

+
+_.each([1, 2, 3], function(num){ alert(num); });
+=> alerts each number in turn...
+_.each({one : 1, two : 2, three : 3}, function(num, key){ alert(num); });
+=> alerts each number in turn...
+ +

+ map_.map(list, iterator, [context]) +
+ Produces a new array of values by mapping each value in list + through a transformation function (iterator). If the native map method + exists, it will be used instead. If list is a JavaScript object, + iterator's arguments will be (value, key, list). +

+
+_.map([1, 2, 3], function(num){ return num * 3; });
+=> [3, 6, 9]
+_.map({one : 1, two : 2, three : 3}, function(num, key){ return num * 3; });
+=> [3, 6, 9]
+ +

+ reduce_.reduce(list, iterator, memo, [context]) + Aliases: inject, foldl +
+ Also known as inject and foldl, reduce boils down a + list of values into a single value. Memo is the initial state + of the reduction, and each successive step of it should be returned by + iterator. +

+
+var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0);
+=> 6
+
+ +

+ reduceRight_.reduceRight(list, iterator, memo, [context]) + Alias: foldr +
+ The right-associative version of reduce. Delegates to the + JavaScript 1.8 version of reduceRight, if it exists. Foldr + is not as useful in JavaScript as it would be in a language with lazy + evaluation. +

+
+var list = [[0, 1], [2, 3], [4, 5]];
+var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
+=> [4, 5, 2, 3, 0, 1]
+
+ +

+ find_.find(list, iterator, [context]) + Alias: detect +
+ Looks through each value in the list, returning the first one that + passes a truth test (iterator). The function returns as + soon as it finds an acceptable element, and doesn't traverse the + entire list. +

+
+var even = _.find([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
+=> 2
+
+ +

+ filter_.filter(list, iterator, [context]) + Alias: select +
+ Looks through each value in the list, returning an array of all + the values that pass a truth test (iterator). Delegates to the + native filter method, if it exists. +

+
+var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
+=> [2, 4, 6]
+
+ +

+ reject_.reject(list, iterator, [context]) +
+ Returns the values in list without the elements that the truth + test (iterator) passes. The opposite of filter. +

+
+var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
+=> [1, 3, 5]
+
+ +

+ all_.all(list, iterator, [context]) + Alias: every +
+ Returns true if all of the values in the list pass the iterator + truth test. Delegates to the native method every, if present. +

+
+_.all([true, 1, null, 'yes'], _.identity);
+=> false
+
+ +

+ any_.any(list, [iterator], [context]) + Alias: some +
+ Returns true if any of the values in the list pass the + iterator truth test. Short-circuits and stops traversing the list + if a true element is found. Delegates to the native method some, + if present. +

+
+_.any([null, 0, 'yes', false]);
+=> true
+
+ +

+ include_.include(list, value) + Alias: contains +
+ Returns true if the value is present in the list, using + === to test equality. Uses indexOf internally, if list + is an Array. +

+
+_.include([1, 2, 3], 3);
+=> true
+
+ +

+ invoke_.invoke(list, methodName, [*arguments]) +
+ Calls the method named by methodName on each value in the list. + Any extra arguments passed to invoke will be forwarded on to the + method invocation. +

+
+_.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
+=> [[1, 5, 7], [1, 2, 3]]
+
+ +

+ pluck_.pluck(list, propertyName) +
+ A convenient version of what is perhaps the most common use-case for + map: extracting a list of property values. +

+
+var stooges = [{name : 'moe', age : 40}, {name : 'larry', age : 50}, {name : 'curly', age : 60}];
+_.pluck(stooges, 'name');
+=> ["moe", "larry", "curly"]
+
+ +

+ max_.max(list, [iterator], [context]) +
+ Returns the maximum value in list. If iterator is passed, + it will be used on each value to generate the criterion by which the + value is ranked. +

+
+var stooges = [{name : 'moe', age : 40}, {name : 'larry', age : 50}, {name : 'curly', age : 60}];
+_.max(stooges, function(stooge){ return stooge.age; });
+=> {name : 'curly', age : 60};
+
+ +

+ min_.min(list, [iterator], [context]) +
+ Returns the minimum value in list. If iterator is passed, + it will be used on each value to generate the criterion by which the + value is ranked. +

+
+var numbers = [10, 5, 100, 2, 1000];
+_.min(numbers);
+=> 2
+
+ +

+ sortBy_.sortBy(list, iterator, [context]) +
+ Returns a sorted copy of list, ranked by the results of running + each value through iterator. +

+
+_.sortBy([1, 2, 3, 4, 5, 6], function(num){ return Math.sin(num); });
+=> [5, 4, 6, 3, 1, 2]
+
+ +

+ groupBy_.groupBy(list, iterator) +
+ Splits a collection into sets, grouped by the result of running each + value through iterator. If iterator is a string instead of + a function, groups by the property named by iterator on each of + the values. +

+
+_.groupBy([1.3, 2.1, 2.4], function(num){ return Math.floor(num); });
+=> {1: [1.3], 2: [2.1, 2.4]}
+
+_.groupBy(['one', 'two', 'three'], 'length');
+=> {3: ["one", "two"], 5: ["three"]}
+
+ +

+ sortedIndex_.sortedIndex(list, value, [iterator]) +
+ Uses a binary search to determine the index at which the value + should be inserted into the list in order to maintain the list's + sorted order. If an iterator is passed, it will be used to compute + the sort ranking of each value. +

+
+_.sortedIndex([10, 20, 30, 40, 50], 35);
+=> 3
+
+ +

+ shuffle_.shuffle(list) +
+ Returns a shuffled copy of the list, using a version of the + Fisher-Yates shuffle. +

+
+_.shuffle([1, 2, 3, 4, 5, 6]);
+=> [4, 1, 6, 3, 5, 2]
+
+ +

+ toArray_.toArray(list) +
+ Converts the list (anything that can be iterated over), into a + real Array. Useful for transmuting the arguments object. +

+
+(function(){ return _.toArray(arguments).slice(0); })(1, 2, 3);
+=> [1, 2, 3]
+
+ +

+ size_.size(list) +
+ Return the number of values in the list. +

+
+_.size({one : 1, two : 2, three : 3});
+=> 3
+
+ +

Array Functions

+ +

+ Note: All array functions will also work on the arguments object. +

+ +

+ first_.first(array, [n]) + Alias: head +
+ Returns the first element of an array. Passing n will + return the first n elements of the array. +

+
+_.first([5, 4, 3, 2, 1]);
+=> 5
+
+ +

+ initial_.initial(array, [n]) +
+ Returns everything but the last entry of the array. Especially useful on + the arguments object. Pass n to exclude the last n elements + from the result. +

+
+_.initial([5, 4, 3, 2, 1]);
+=> [5, 4, 3, 2]
+
+ +

+ last_.last(array, [n]) +
+ Returns the last element of an array. Passing n will return + the last n elements of the array. +

+
+_.last([5, 4, 3, 2, 1]);
+=> 1
+
+ +

+ rest_.rest(array, [index]) + Alias: tail +
+ Returns the rest of the elements in an array. Pass an index + to return the values of the array from that index onward. +

+
+_.rest([5, 4, 3, 2, 1]);
+=> [4, 3, 2, 1]
+
+ +

+ compact_.compact(array) +
+ Returns a copy of the array with all falsy values removed. + In JavaScript, false, null, 0, "", + undefined and NaN are all falsy. +

+
+_.compact([0, 1, false, 2, '', 3]);
+=> [1, 2, 3]
+
+ +

+ flatten_.flatten(array) +
+ Flattens a nested array (the nesting can be to any depth). +

+
+_.flatten([1, [2], [3, [[[4]]]]]);
+=> [1, 2, 3, 4];
+
+ +

+ without_.without(array, [*values]) +
+ Returns a copy of the array with all instances of the values + removed. === is used for the equality test. +

+
+_.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
+=> [2, 3, 4]
+
+ +

+ union_.union(*arrays) +
+ Computes the union of the passed-in arrays: the list of unique items, + in order, that are present in one or more of the arrays. +

+
+_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
+=> [1, 2, 3, 101, 10]
+
+ +

+ intersection_.intersection(*arrays) +
+ Computes the list of values that are the intersection of all the arrays. + Each value in the result is present in each of the arrays. +

+
+_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
+=> [1, 2]
+
+ +

+ difference_.difference(array, other) +
+ Similar to without, but returns the values from array that + are not present in other. +

+
+_.difference([1, 2, 3, 4, 5], [5, 2, 10]);
+=> [1, 3, 4]
+
+ +

+ uniq_.uniq(array, [isSorted], [iterator]) + Alias: unique +
+ Produces a duplicate-free version of the array, using === to test + object equality. If you know in advance that the array is sorted, + passing true for isSorted will run a much faster algorithm. + If you want to compute unique items based on a transformation, pass an + iterator function. +

+
+_.uniq([1, 2, 1, 3, 1, 4]);
+=> [1, 2, 3, 4]
+
+ +

+ zip_.zip(*arrays) +
+ Merges together the values of each of the arrays with the + values at the corresponding position. Useful when you have separate + data sources that are coordinated through matching array indexes. + If you're working with a matrix of nested arrays, zip.apply + can transpose the matrix in a similar fashion. +

+
+_.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
+=> [["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]
+
+ +

+ indexOf_.indexOf(array, value, [isSorted]) +
+ Returns the index at which value can be found in the array, + or -1 if value is not present in the array. Uses the native + indexOf function unless it's missing. If you're working with a + large array, and you know that the array is already sorted, pass true + for isSorted to use a faster binary search. +

+
+_.indexOf([1, 2, 3], 2);
+=> 1
+
+ +

+ lastIndexOf_.lastIndexOf(array, value) +
+ Returns the index of the last occurrence of value in the array, + or -1 if value is not present. Uses the native lastIndexOf + function if possible. +

+
+_.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
+=> 4
+
+ +

+ range_.range([start], stop, [step]) +
+ A function to create flexibly-numbered lists of integers, handy for + each and map loops. start, if omitted, defaults + to 0; step defaults to 1. Returns a list of integers + from start to stop, incremented (or decremented) by step, + exclusive. +

+
+_.range(10);
+=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+_.range(1, 11);
+=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+_.range(0, 30, 5);
+=> [0, 5, 10, 15, 20, 25]
+_.range(0, -10, -1);
+=> [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
+_.range(0);
+=> []
+
+ +

Function (uh, ahem) Functions

+ +

+ bind_.bind(function, object, [*arguments]) +
+ Bind a function to an object, meaning that whenever + the function is called, the value of this will be the object. + Optionally, bind arguments to the function to pre-fill them, + also known as currying. +

+
+var func = function(greeting){ return greeting + ': ' + this.name };
+func = _.bind(func, {name : 'moe'}, 'hi');
+func();
+=> 'hi: moe'
+
+ +

+ bindAll_.bindAll(object, [*methodNames]) +
+ Binds a number of methods on the object, specified by + methodNames, to be run in the context of that object whenever they + are invoked. Very handy for binding functions that are going to be used + as event handlers, which would otherwise be invoked with a fairly useless + this. If no methodNames are provided, all of the object's + function properties will be bound to it. +

+
+var buttonView = {
+  label   : 'underscore',
+  onClick : function(){ alert('clicked: ' + this.label); },
+  onHover : function(){ console.log('hovering: ' + this.label); }
+};
+_.bindAll(buttonView);
+jQuery('#underscore_button').bind('click', buttonView.onClick);
+=> When the button is clicked, this.label will have the correct value...
+
+ +

+ memoize_.memoize(function, [hashFunction]) +
+ Memoizes a given function by caching the computed result. Useful + for speeding up slow-running computations. If passed an optional + hashFunction, it will be used to compute the hash key for storing + the result, based on the arguments to the original function. The default + hashFunction just uses the first argument to the memoized function + as the key. +

+
+var fibonacci = _.memoize(function(n) {
+  return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
+});
+
+ +

+ delay_.delay(function, wait, [*arguments]) +
+ Much like setTimeout, invokes function after wait + milliseconds. If you pass the optional arguments, they will be + forwarded on to the function when it is invoked. +

+
+var log = _.bind(console.log, console);
+_.delay(log, 1000, 'logged later');
+=> 'logged later' // Appears after one second.
+
+ +

+ defer_.defer(function) +
+ Defers invoking the function until the current call stack has cleared, + similar to using setTimeout with a delay of 0. Useful for performing + expensive computations or HTML rendering in chunks without blocking the UI thread + from updating. +

+
+_.defer(function(){ alert('deferred'); });
+// Returns from the function before the alert runs.
+
+ +

+ throttle_.throttle(function, wait) +
+ Returns a throttled version of the function, that, when invoked repeatedly, + will only actually call the wrapped function at most once per every wait + milliseconds. Useful for rate-limiting events that occur faster than you + can keep up with. +

+
+var throttled = _.throttle(updatePosition, 100);
+$(window).scroll(throttled);
+
+ +

+ debounce_.debounce(function, wait) +
+ Calling a debounced function will postpone its execution until after + wait milliseconds have elapsed since the last time the function + was invoked. Useful for implementing behavior that should only happen + after the input has stopped arriving. For example: rendering a + preview of a Markdown comment, recalculating a layout after the window + has stopped being resized... +

+
+var lazyLayout = _.debounce(calculateLayout, 300);
+$(window).resize(lazyLayout);
+
+ +

+ once_.once(function) +
+ Creates a version of the function that can only be called one time. + Repeated calls to the modified function will have no effect, returning + the value from the original call. Useful for initialization functions, + instead of having to set a boolean flag and then check it later. +

+
+var initialize = _.once(createApplication);
+initialize();
+initialize();
+// Application is only created once.
+
+ +

+ after_.after(count, function) +
+ Creates a version of the function that will only be run after first + being called count times. Useful for grouping asynchronous responses, + where you want to be sure that all the async calls have finished, before + proceeding. +

+
+var renderNotes = _.after(notes.length, render);
+_.each(notes, function(note) {
+  note.asyncSave({success: renderNotes}); 
+});
+// renderNotes is run once, after all notes have saved.
+
+ +

+ wrap_.wrap(function, wrapper) +
+ Wraps the first function inside of the wrapper function, + passing it as the first argument. This allows the wrapper to + execute code before and after the function runs, adjust the arguments, + and execute it conditionally. +

+
+var hello = function(name) { return "hello: " + name; };
+hello = _.wrap(hello, function(func) {
+  return "before, " + func("moe") + ", after";
+});
+hello();
+=> 'before, hello: moe, after'
+
+ +

+ compose_.compose(*functions) +
+ Returns the composition of a list of functions, where each function + consumes the return value of the function that follows. In math terms, + composing the functions f(), g(), and h() produces + f(g(h())). +

+
+var greet    = function(name){ return "hi: " + name; };
+var exclaim  = function(statement){ return statement + "!"; };
+var welcome = _.compose(exclaim, greet);
+welcome('moe');
+=> 'hi: moe!'
+
+ +

Object Functions

+ +

+ keys_.keys(object) +
+ Retrieve all the names of the object's properties. +

+
+_.keys({one : 1, two : 2, three : 3});
+=> ["one", "two", "three"]
+
+ +

+ values_.values(object) +
+ Return all of the values of the object's properties. +

+
+_.values({one : 1, two : 2, three : 3});
+=> [1, 2, 3]
+
+ +

+ functions_.functions(object) + Alias: methods +
+ Returns a sorted list of the names of every method in an object — + that is to say, the name of every function property of the object. +

+
+_.functions(_);
+=> ["all", "any", "bind", "bindAll", "clone", "compact", "compose" ...
+
+ +

+ extend_.extend(destination, *sources) +
+ Copy all of the properties in the source objects over to the + destination object. It's in-order, so the last source will override + properties of the same name in previous arguments. +

+
+_.extend({name : 'moe'}, {age : 50});
+=> {name : 'moe', age : 50}
+
+ +

+ defaults_.defaults(object, *defaults) +
+ Fill in missing properties in object with default values from the + defaults objects. As soon as the property is filled, further defaults + will have no effect. +

+
+var iceCream = {flavor : "chocolate"};
+_.defaults(iceCream, {flavor : "vanilla", sprinkles : "lots"});
+=> {flavor : "chocolate", sprinkles : "lots"}
+
+ +

+ clone_.clone(object) +
+ Create a shallow-copied clone of the object. Any nested objects + or arrays will be copied by reference, not duplicated. +

+
+_.clone({name : 'moe'});
+=> {name : 'moe'};
+
+ +

+ tap_.tap(object, interceptor) +
+ Invokes interceptor with the object, and then returns object. + The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain. +

+
+_([1,2,3,200]).chain().
+  filter(function(num) { return num % 2 == 0; }).
+  tap(console.log).
+  map(function(num) { return num * num }).
+  value();
+=> [2, 200]
+=> [4, 40000]
+
+ +

+ isEqual_.isEqual(object, other) +
+ Performs an optimized deep comparison between the two objects, to determine + if they should be considered equal. +

+
+var moe   = {name : 'moe', luckyNumbers : [13, 27, 34]};
+var clone = {name : 'moe', luckyNumbers : [13, 27, 34]};
+moe == clone;
+=> false
+_.isEqual(moe, clone);
+=> true
+
+ +

+ isEmpty_.isEmpty(object) +
+ Returns true if object contains no values. +

+
+_.isEmpty([1, 2, 3]);
+=> false
+_.isEmpty({});
+=> true
+
+ +

+ isElement_.isElement(object) +
+ Returns true if object is a DOM element. +

+
+_.isElement(jQuery('body')[0]);
+=> true
+
+ +

+ isArray_.isArray(object) +
+ Returns true if object is an Array. +

+
+(function(){ return _.isArray(arguments); })();
+=> false
+_.isArray([1,2,3]);
+=> true
+
+ +

+ isArguments_.isArguments(object) +
+ Returns true if object is an Arguments object. +

+
+(function(){ return _.isArguments(arguments); })(1, 2, 3);
+=> true
+_.isArguments([1,2,3]);
+=> false
+
+ +

+ isFunction_.isFunction(object) +
+ Returns true if object is a Function. +

+
+_.isFunction(alert);
+=> true
+
+ +

+ isString_.isString(object) +
+ Returns true if object is a String. +

+
+_.isString("moe");
+=> true
+
+ +

+ isNumber_.isNumber(object) +
+ Returns true if object is a Number. +

+
+_.isNumber(8.4 * 5);
+=> true
+
+ +

+ isBoolean_.isBoolean(object) +
+ Returns true if object is either true or false. +

+
+_.isBoolean(null);
+=> false
+
+ +

+ isDate_.isDate(object) +
+ Returns true if object is a Date. +

+
+_.isDate(new Date());
+=> true
+
+ +

+ isRegExp_.isRegExp(object) +
+ Returns true if object is a RegExp. +

+
+_.isRegExp(/moe/);
+=> true
+
+ +

+ isNaN_.isNaN(object) +
+ Returns true if object is NaN.
Note: this is not + the same as the native isNaN function, which will also return + true if the variable is undefined. +

+
+_.isNaN(NaN);
+=> true
+isNaN(undefined);
+=> true
+_.isNaN(undefined);
+=> false
+
+ +

+ isNull_.isNull(object) +
+ Returns true if the value of object is null. +

+
+_.isNull(null);
+=> true
+_.isNull(undefined);
+=> false
+
+ +

+ isUndefined_.isUndefined(variable) +
+ Returns true if variable is undefined. +

+
+_.isUndefined(window.missingVariable);
+=> true
+
+ +

Utility Functions

+ +

+ noConflict_.noConflict() +
+ Give control of the "_" variable back to its previous owner. Returns + a reference to the Underscore object. +

+
+var underscore = _.noConflict();
+ +

+ identity_.identity(value) +
+ Returns the same value that is used as the argument. In math: + f(x) = x
+ This function looks useless, but is used throughout Underscore as + a default iterator. +

+
+var moe = {name : 'moe'};
+moe === _.identity(moe);
+=> true
+ +

+ times_.times(n, iterator) +
+ Invokes the given iterator function n times. +

+
+_(3).times(function(){ genie.grantWish(); });
+ +

+ mixin_.mixin(object) +
+ Allows you to extend Underscore with your own utility functions. Pass + a hash of {name: function} definitions to have your functions + added to the Underscore object, as well as the OOP wrapper. +

+
+_.mixin({
+  capitalize : function(string) {
+    return string.charAt(0).toUpperCase() + string.substring(1).toLowerCase();
+  }
+});
+_("fabio").capitalize();
+=> "Fabio"
+
+ +

+ uniqueId_.uniqueId([prefix]) +
+ Generate a globally-unique id for client-side models or DOM elements + that need one. If prefix is passed, the id will be appended to it. +

+
+_.uniqueId('contact_');
+=> 'contact_104'
+ +

+ escape_.escape(string) +
+ Escapes a string for insertion into HTML, replacing + &, <, >, ", ', and / characters. +

+
+_.escape('Curly, Larry & Moe');
+=> "Curly, Larry &amp; Moe"
+ +

+ template_.template(templateString, [context]) +
+ Compiles JavaScript templates into functions that can be evaluated + for rendering. Useful for rendering complicated bits of HTML from JSON + data sources. Template functions can both interpolate variables, using
+ <%= … %>, as well as execute arbitrary JavaScript code, with + <% … %>. If you wish to interpolate a value, and have + it be HTML-escaped, use <%- … %> When you evaluate a template function, pass in a + context object that has properties corresponding to the template's free + variables. If you're writing a one-off, you can pass the context + object as the second parameter to template in order to render + immediately instead of returning a template function. +

+
+var compiled = _.template("hello: <%= name %>");
+compiled({name : 'moe'});
+=> "hello: moe"
+
+var list = "<% _.each(people, function(name) { %> <li><%= name %></li> <% }); %>";
+_.template(list, {people : ['moe', 'curly', 'larry']});
+=> "<li>moe</li><li>curly</li><li>larry</li>"
+
+var template = _.template("<b><%- value %></b>");
+template({value : '<script>'});
+=> "<b>&lt;script&gt;</b>"
+ +

+ You can also use print from within JavaScript code. This is + sometimes more convenient than using <%= ... %>. +

+ +
+var compiled = _.template("<% print('Hello ' + epithet); %>");
+compiled({epithet: "stooge"});
+=> "Hello stooge."
+ +

+ If ERB-style delimiters aren't your cup of tea, you can change Underscore's + template settings to use different symbols to set off interpolated code. + Define an interpolate regex, and an (optional) evaluate regex + to match expressions that should be inserted and evaluated, respectively. + If no evaluate regex is provided, your templates will only be + capable of interpolating values. + For example, to perform + Mustache.js + style templating: +

+ +
+_.templateSettings = {
+  interpolate : /\{\{(.+?)\}\}/g
+};
+
+var template = _.template("Hello {{ name }}!");
+template({name : "Mustache"});
+=> "Hello Mustache!"
+ +

Chaining

+ +

+ chain_(obj).chain() +
+ Returns a wrapped object. Calling methods on this object will continue + to return wrapped objects until value is used. ( + A more realistic example.) +

+
+var stooges = [{name : 'curly', age : 25}, {name : 'moe', age : 21}, {name : 'larry', age : 23}];
+var youngest = _(stooges).chain()
+  .sortBy(function(stooge){ return stooge.age; })
+  .map(function(stooge){ return stooge.name + ' is ' + stooge.age; })
+  .first()
+  .value();
+=> "moe is 21"
+
+ +

+ value_(obj).value() +
+ Extracts the value of a wrapped object. +

+
+_([1, 2, 3]).value();
+=> [1, 2, 3]
+
+ +

Links & Suggested Reading

+ +

+ Underscore.lua, + a Lua port of the functions that are applicable in both languages. + Includes OOP-wrapping and chaining. + The source is + available on GitHub. +

+ +

+ Underscore.php, + a PHP port of the functions that are applicable in both languages. + Includes OOP-wrapping and chaining. + The source is + available on GitHub. +

+ +

+ Underscore-perl, + a Perl port of many of the Underscore.js functions, + aimed at on Perl hashes and arrays, also + available on GitHub. +

+ +

+ Underscore.string, + an Underscore extension that adds functions for string-manipulation: + trim, startsWith, contains, capitalize, + reverse, sprintf, and more. +

+ +

+ Ruby's Enumerable module. +

+ +

+ Prototype.js, which provides + JavaScript with collection functions in the manner closest to Ruby's Enumerable. +

+ +

+ Oliver Steele's + Functional JavaScript, + which includes comprehensive higher-order function support as well as string lambdas. +

+ +

+ Michael Aufreiter's Data.js, + a data manipulation + persistence library for JavaScript. +

+ +

+ Python's itertools. +

+ +

Change Log

+ +

+ 1.2.2Nov. 14, 2011
+

    +
  • + Continued tweaks to _.isEqual semantics. Now JS primitives are + considered equivalent to their wrapped versions, and arrays are compared + by their numeric properties only (#351). +
  • +
  • + _.escape no longer tries to be smart about not double-escaping + already-escaped HTML entities. Now it just escapes regardless (#350). +
  • +
  • + In _.template, you may now leave semicolons out of evaluated + statements if you wish: <% }) %> (#369). +
  • +
  • + _.after(callback, 0) will now trigger the callback immediately, + making "after" easier to use with asynchronous APIs (#366). +
  • +
+

+ +

+ 1.2.1Oct. 24, 2011
+

    +
  • + Several important bug fixes for _.isEqual, which should now + do better on mutated Arrays, and on non-Array objects with + length properties. (#329) +
  • +
  • + jrburke contributed Underscore exporting for AMD module loaders, + and tonylukasavage for Appcelerator Titanium. + (#335, #338) +
  • +
  • + You can now _.groupBy(list, 'property') as a shortcut for + grouping values by a particular common property. +
  • +
  • + _.throttle'd functions now fire immediately upon invocation, + and are rate-limited thereafter (#170, #266). +
  • +
  • + Most of the _.is[Type] checks no longer ducktype. +
  • +
  • + The _.bind function now also works on constructors, a-la + ES5 ... but you would never want to use _.bind on a + constructor function. +
  • +
  • + _.clone no longer wraps non-object types in Objects. +
  • +
  • + _.find and _.filter are now the preferred names for + _.detect and _.select. +
  • +
+

+ +

+ 1.2.0Oct. 5, 2011
+

    +
  • + The _.isEqual function now + supports true deep equality comparisons, with checks for cyclic structures, + thanks to Kit Cambridge. +
  • +
  • + Underscore templates now support HTML escaping interpolations, using + <%- ... %> syntax. +
  • +
  • + Ryan Tenney contributed _.shuffle, which uses a modified + Fisher-Yates to give you a shuffled copy of an array. +
  • +
  • + _.uniq can now be passed an optional iterator, to determine by + what criteria an object should be considered unique. +
  • +
  • + _.last now takes an optional argument which will return the last + N elements of the list. +
  • +
  • + A new _.initial function was added, as a mirror of _.rest, + which returns all the initial values of a list (except the last N). +
  • +
+

+ +

+ 1.1.7July 13, 2011
+ Added _.groupBy, which aggregates a collection into groups of like items. + Added _.union and _.difference, to complement the + (re-named) _.intersection. + Various improvements for support of sparse arrays. + _.toArray now returns a clone, if directly passed an array. + _.functions now also returns the names of functions that are present + in the prototype chain. +

+ +

+ 1.1.6April 18, 2011
+ Added _.after, which will return a function that only runs after + first being called a specified number of times. + _.invoke can now take a direct function reference. + _.every now requires an iterator function to be passed, which + mirrors the ECMA5 API. + _.extend no longer copies keys when the value is undefined. + _.bind now errors when trying to bind an undefined value. +

+ +

+ 1.1.5Mar 20, 2011
+ Added an _.defaults function, for use merging together JS objects + representing default options. + Added an _.once function, for manufacturing functions that should + only ever execute a single time. + _.bind now delegates to the native ECMAScript 5 version, + where available. + _.keys now throws an error when used on non-Object values, as in + ECMAScript 5. + Fixed a bug with _.keys when used over sparse arrays. +

+ +

+ 1.1.4Jan 9, 2011
+ Improved compliance with ES5's Array methods when passing null + as a value. _.wrap now correctly sets this for the + wrapped function. _.indexOf now takes an optional flag for + finding the insertion index in an array that is guaranteed to already + be sorted. Avoiding the use of .callee, to allow _.isArray + to work properly in ES5's strict mode. +

+ +

+ 1.1.3Dec 1, 2010
+ In CommonJS, Underscore may now be required with just:
+ var _ = require("underscore"). + Added _.throttle and _.debounce functions. + Removed _.breakLoop, in favor of an ECMA5-style un-break-able + each implementation — this removes the try/catch, and you'll now have + better stack traces for exceptions that are thrown within an Underscore iterator. + Improved the isType family of functions for better interoperability + with Internet Explorer host objects. + _.template now correctly escapes backslashes in templates. + Improved _.reduce compatibility with the ECMA5 version: + if you don't pass an initial value, the first item in the collection is used. + _.each no longer returns the iterated collection, for improved + consistency with ES5's forEach. +

+ +

+ 1.1.2
+ Fixed _.contains, which was mistakenly pointing at + _.intersect instead of _.include, like it should + have been. Added _.unique as an alias for _.uniq. +

+ +

+ 1.1.1
+ Improved the speed of _.template, and its handling of multiline + interpolations. Ryan Tenney contributed optimizations to many Underscore + functions. An annotated version of the source code is now available. +

+ +

+ 1.1.0
+ The method signature of _.reduce has been changed to match + the ECMAScript 5 signature, instead of the Ruby/Prototype.js version. + This is a backwards-incompatible change. _.template may now be + called with no arguments, and preserves whitespace. _.contains + is a new alias for _.include. +

+ +

+ 1.0.4
+ Andri Möll contributed the _.memoize + function, which can be used to speed up expensive repeated computations + by caching the results. +

+ +

+ 1.0.3
+ Patch that makes _.isEqual return false if any property + of the compared object has a NaN value. Technically the correct + thing to do, but of questionable semantics. Watch out for NaN comparisons. +

+ +

+ 1.0.2
+ Fixes _.isArguments in recent versions of Opera, which have + arguments objects as real Arrays. +

+ +

+ 1.0.1
+ Bugfix for _.isEqual, when comparing two objects with the same + number of undefined keys, but with different names. +

+ +

+ 1.0.0
+ Things have been stable for many months now, so Underscore is now + considered to be out of beta, at 1.0. Improvements since 0.6 + include _.isBoolean, and the ability to have _.extend + take multiple source objects. +

+ +

+ 0.6.0
+ Major release. Incorporates a number of + Mile Frawley's refactors for + safer duck-typing on collection functions, and cleaner internals. A new + _.mixin method that allows you to extend Underscore with utility + functions of your own. Added _.times, which works the same as in + Ruby or Prototype.js. Native support for ECMAScript 5's Array.isArray, + and Object.keys. +

+ +

+ 0.5.8
+ Fixed Underscore's collection functions to work on + NodeLists and + HTMLCollections + once more, thanks to + Justin Tulloss. +

+ +

+ 0.5.7
+ A safer implementation of _.isArguments, and a + faster _.isNumber,
thanks to + Jed Schmidt. +

+ +

+ 0.5.6
+ Customizable delimiters for _.template, contributed by + Noah Sloan. +

+ +

+ 0.5.5
+ Fix for a bug in MobileSafari's OOP-wrapper, with the arguments object. +

+ +

+ 0.5.4
+ Fix for multiple single quotes within a template string for + _.template. See: + Rick Strahl's blog post. +

+ +

+ 0.5.2
+ New implementations of isArray, isDate, isFunction, + isNumber, isRegExp, and isString, thanks to + a suggestion from + Robert Kieffer. + Instead of doing Object#toString + comparisons, they now check for expected properties, which is less safe, + but more than an order of magnitude faster. Most other Underscore + functions saw minor speed improvements as a result. + Evgeniy Dolzhenko + contributed _.tap, + similar to Ruby 1.9's, + which is handy for injecting side effects (like logging) into chained calls. +

+ +

+ 0.5.1
+ Added an _.isArguments function. Lots of little safety checks + and optimizations contributed by + Noah Sloan and + Andri Möll. +

+ +

+ 0.5.0
+ [API Changes] _.bindAll now takes the context object as + its first parameter. If no method names are passed, all of the context + object's methods are bound to it, enabling chaining and easier binding. + _.functions now takes a single argument and returns the names + of its Function properties. Calling _.functions(_) will get you + the previous behavior. + Added _.isRegExp so that isEqual can now test for RegExp equality. + All of the "is" functions have been shrunk down into a single definition. + Karl Guertin contributed patches. +

+ +

+ 0.4.7
+ 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. +

+ +

+ 0.4.6
+ Added the range function, a port of the + Python + function of the same name, for generating flexibly-numbered lists + of integers. Original patch contributed by + Kirill Ishanov. +

+ +

+ 0.4.5
+ Added rest for Arrays and arguments objects, and aliased + first as head, and rest as tail, + thanks to Luke Sutton's patches. + Added tests ensuring that all Underscore Array functions also work on + arguments objects. +

+ +

+ 0.4.4
+ Added isString, and isNumber, for consistency. Fixed + _.isEqual(NaN, NaN) to return true (which is debatable). +

+ +

+ 0.4.3
+ Started using the native StopIteration object in browsers that support it. + Fixed Underscore setup for CommonJS environments. +

+ +

+ 0.4.2
+ Renamed the unwrapping function to value, for clarity. +

+ +

+ 0.4.1
+ Chained Underscore objects now support the Array prototype methods, so + that you can perform the full range of operations on a wrapped array + without having to break your chain. Added a breakLoop method + to break in the middle of any Underscore iteration. Added an + isEmpty function that works on arrays and objects. +

+ +

+ 0.4.0
+ All Underscore functions can now be called in an object-oriented style, + like so: _([1, 2, 3]).map(...);. Original patch provided by + Marc-André Cournoyer. + Wrapped objects can be chained through multiple + method invocations. A functions method + was added, providing a sorted list of all the functions in Underscore. +

+ +

+ 0.3.3
+ Added the JavaScript 1.8 function reduceRight. Aliased it + as foldr, and aliased reduce as foldl. +

+ +

+ 0.3.2
+ Now runs on stock Rhino + interpreters with: load("underscore.js"). + Added identity as a utility function. +

+ +

+ 0.3.1
+ All iterators are now passed in the original collection as their third + argument, the same as JavaScript 1.6's forEach. Iterating over + objects is now called with (value, key, collection), for details + see _.each. +

+ +

+ 0.3.0
+ Added Dmitry Baranovskiy's + comprehensive optimizations, merged in + Kris Kowal's patches to make Underscore + CommonJS and + Narwhal compliant. +

+ +

+ 0.2.0
+ Added compose and lastIndexOf, renamed inject to + reduce, added aliases for inject, filter, + every, some, and forEach. +

+ +

+ 0.1.1
+ Added noConflict, so that the "Underscore" object can be assigned to + other variables. +

+ +

+ 0.1.0
+ Initial release of Underscore.js. +

+ +

+ + A DocumentCloud Project + +

+ +
+ +
+ + + + + + diff --git a/node_modules/underscore/index.js b/node_modules/underscore/index.js new file mode 100644 index 0000000..2cf0ca5 --- /dev/null +++ b/node_modules/underscore/index.js @@ -0,0 +1 @@ +module.exports = require('./underscore'); diff --git a/node_modules/underscore/package.json b/node_modules/underscore/package.json new file mode 100644 index 0000000..8481b77 --- /dev/null +++ b/node_modules/underscore/package.json @@ -0,0 +1,12 @@ +{ + "name" : "underscore", + "description" : "JavaScript's functional programming helper library.", + "homepage" : "http://documentcloud.github.com/underscore/", + "keywords" : ["util", "functional", "server", "client", "browser"], + "author" : "Jeremy Ashkenas ", + "contributors" : [], + "dependencies" : [], + "repository" : {"type": "git", "url": "git://github.com/documentcloud/underscore.git"}, + "main" : "underscore.js", + "version" : "1.2.2" +} diff --git a/node_modules/underscore/underscore-min.js b/node_modules/underscore/underscore-min.js new file mode 100644 index 0000000..fadc96e --- /dev/null +++ b/node_modules/underscore/underscore-min.js @@ -0,0 +1,30 @@ +// Underscore.js 1.2.2 +// (c) 2011 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore is freely distributable under the MIT license. +// Portions of Underscore are inspired or borrowed from Prototype, +// Oliver Steele's Functional, and John Resig's Micro-Templating. +// For all details and documentation: +// http://documentcloud.github.com/underscore +(function(){function r(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(b.isFunction(a.isEqual))return a.isEqual(c);if(b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return String(a)==String(c);case "[object Number]":return a=+a,c=+c,a!=a?c!=c:a==0?1/a==1/c:a==c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source== +c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&r(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(m.call(a,h)&&(f++,!(g=m.call(c,h)&&r(a[h],c[h],d))))break;if(g){for(h in c)if(m.call(c, +h)&&!f--)break;g=!f}}d.pop();return g}var s=this,F=s._,o={},k=Array.prototype,p=Object.prototype,i=k.slice,G=k.unshift,l=p.toString,m=p.hasOwnProperty,v=k.forEach,w=k.map,x=k.reduce,y=k.reduceRight,z=k.filter,A=k.every,B=k.some,q=k.indexOf,C=k.lastIndexOf,p=Array.isArray,H=Object.keys,t=Function.prototype.bind,b=function(a){return new n(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else typeof define==="function"&&define.amd? +define("underscore",function(){return b}):s._=b;b.VERSION="1.2.2";var j=b.each=b.forEach=function(a,c,b){if(a!=null)if(v&&a.forEach===v)a.forEach(c,b);else if(a.length===+a.length)for(var e=0,f=a.length;e=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;bd?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,c){var b=e(a,c);(d[b]||(d[b]=[])).push(a)});return d};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.difference=function(a,c){return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=H||function(a){if(a!== +Object(a))throw new TypeError("Invalid object");var b=[],d;for(d in a)m.call(a,d)&&(b[b.length]=d);return b};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)b[d]!==void 0&&(a[d]=b[d])});return a};b.defaults=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)? +a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return r(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(m.call(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=p||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};b.isArguments=l.call(arguments)=="[object Arguments]"?function(a){return l.call(a)=="[object Arguments]"}: +function(a){return!(!a||!m.call(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null}; +b.isUndefined=function(a){return a===void 0};b.noConflict=function(){s._=F;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.mixin=function(a){j(b.functions(a),function(c){I(c,b[c]=a[c])})};var J=0;b.uniqueId=function(a){var b=J++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g, +interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape,function(a,b){return"',_.escape("+b.replace(/\\'/g,"'")+"),'"}).replace(d.interpolate,function(a,b){return"',"+b.replace(/\\'/g,"'")+",'"}).replace(d.evaluate||null,function(a,b){return"');"+b.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g, +"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e(a,b)}};var n=function(a){this._wrapped=a};b.prototype=n.prototype;var u=function(a,c){return c?b(a).chain():a},I=function(a,c){n.prototype[a]=function(){var a=i.call(arguments);G.call(a,this._wrapped);return u(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];n.prototype[a]=function(){b.apply(this._wrapped, +arguments);return u(this._wrapped,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];n.prototype[a]=function(){return u(b.apply(this._wrapped,arguments),this._chain)}});n.prototype.chain=function(){this._chain=true;return this};n.prototype.value=function(){return this._wrapped}}).call(this); diff --git a/node_modules/underscore/underscore.js b/node_modules/underscore/underscore.js new file mode 100644 index 0000000..5579c07 --- /dev/null +++ b/node_modules/underscore/underscore.js @@ -0,0 +1,977 @@ +// Underscore.js 1.2.2 +// (c) 2011 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore is freely distributable under the MIT license. +// Portions of Underscore are inspired or borrowed from Prototype, +// Oliver Steele's Functional, and John Resig's Micro-Templating. +// For all details and documentation: +// http://documentcloud.github.com/underscore + +(function() { + + // Baseline setup + // -------------- + + // Establish the root object, `window` in the browser, or `global` on the server. + var root = this; + + // Save the previous value of the `_` variable. + var previousUnderscore = root._; + + // Establish the object that gets returned to break out of a loop iteration. + var breaker = {}; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; + + // Create quick reference variables for speed access to core prototypes. + var slice = ArrayProto.slice, + unshift = ArrayProto.unshift, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + + // All **ECMAScript 5** native function implementations that we hope to use + // are declared here. + var + nativeForEach = ArrayProto.forEach, + nativeMap = ArrayProto.map, + nativeReduce = ArrayProto.reduce, + nativeReduceRight = ArrayProto.reduceRight, + nativeFilter = ArrayProto.filter, + nativeEvery = ArrayProto.every, + nativeSome = ArrayProto.some, + nativeIndexOf = ArrayProto.indexOf, + nativeLastIndexOf = ArrayProto.lastIndexOf, + nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeBind = FuncProto.bind; + + // Create a safe reference to the Underscore object for use below. + var _ = function(obj) { return new wrapper(obj); }; + + // Export the Underscore object for **Node.js** and **"CommonJS"**, with + // backwards-compatibility for the old `require()` API. If we're not in + // CommonJS, add `_` to the global object. + if (typeof exports !== 'undefined') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = _; + } + exports._ = _; + } else if (typeof define === 'function' && define.amd) { + // Register as a named module with AMD. + define('underscore', function() { + return _; + }); + } else { + // Exported as a string, for Closure Compiler "advanced" mode. + root['_'] = _; + } + + // Current version. + _.VERSION = '1.2.2'; + + // Collection Functions + // -------------------- + + // The cornerstone, an `each` implementation, aka `forEach`. + // Handles objects with the built-in `forEach`, arrays, and raw objects. + // Delegates to **ECMAScript 5**'s native `forEach` if available. + var each = _.each = _.forEach = function(obj, iterator, context) { + if (obj == null) return; + if (nativeForEach && obj.forEach === nativeForEach) { + obj.forEach(iterator, context); + } else if (obj.length === +obj.length) { + for (var i = 0, l = obj.length; i < l; i++) { + if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return; + } + } else { + for (var key in obj) { + if (hasOwnProperty.call(obj, key)) { + if (iterator.call(context, obj[key], key, obj) === breaker) return; + } + } + } + }; + + // Return the results of applying the iterator to each element. + // Delegates to **ECMAScript 5**'s native `map` if available. + _.map = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); + each(obj, function(value, index, list) { + results[results.length] = iterator.call(context, value, index, list); + }); + return results; + }; + + // **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) { + var initial = memo !== void 0; + if (obj == null) obj = []; + if (nativeReduce && obj.reduce === nativeReduce) { + if (context) iterator = _.bind(iterator, context); + return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); + } + each(obj, function(value, index, list) { + if (!initial) { + memo = value; + initial = true; + } else { + memo = iterator.call(context, memo, value, index, list); + } + }); + if (!initial) throw new TypeError("Reduce of empty array with no initial value"); + return memo; + }; + + // The right-associative version of reduce, also known as `foldr`. + // Delegates to **ECMAScript 5**'s native `reduceRight` if available. + _.reduceRight = _.foldr = function(obj, iterator, memo, context) { + if (obj == null) obj = []; + if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { + if (context) iterator = _.bind(iterator, context); + return memo !== void 0 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); + } + var reversed = (_.isArray(obj) ? obj.slice() : _.toArray(obj)).reverse(); + return _.reduce(reversed, iterator, memo, context); + }; + + // Return the first value which passes a truth test. Aliased as `detect`. + _.find = _.detect = function(obj, iterator, context) { + var result; + any(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) { + result = value; + return true; + } + }); + return result; + }; + + // Return all the elements that pass a truth test. + // Delegates to **ECMAScript 5**'s native `filter` if available. + // Aliased as `select`. + _.filter = _.select = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); + each(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) results[results.length] = value; + }); + return results; + }; + + // Return all the elements for which a truth test fails. + _.reject = function(obj, iterator, 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. + // Delegates to **ECMAScript 5**'s native `every` if available. + // Aliased as `all`. + _.every = _.all = function(obj, iterator, context) { + var result = true; + if (obj == null) return result; + if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); + each(obj, function(value, index, list) { + if (!(result = result && iterator.call(context, value, index, list))) return breaker; + }); + return result; + }; + + // Determine if at least one element in the object matches a truth test. + // Delegates to **ECMAScript 5**'s native `some` if available. + // Aliased as `any`. + var any = _.some = _.any = function(obj, iterator, context) { + iterator = iterator || _.identity; + var result = false; + if (obj == null) return result; + if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); + each(obj, function(value, index, list) { + if (result || (result = iterator.call(context, value, index, list))) return breaker; + }); + return !!result; + }; + + // Determine if a given value is included in the array or object using `===`. + // Aliased as `contains`. + _.include = _.contains = function(obj, target) { + var found = false; + if (obj == null) return found; + if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; + 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); + return _.map(obj, function(value) { + return (method.call ? method || value : value[method]).apply(value, args); + }); + }; + + // Convenience version of a common use case of `map`: fetching a property. + _.pluck = function(obj, key) { + return _.map(obj, function(value){ return value[key]; }); + }; + + // Return the maximum element or (element-based computation). + _.max = function(obj, iterator, context) { + if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj); + if (!iterator && _.isEmpty(obj)) return -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}); + }); + return result.value; + }; + + // Return the minimum element (or element-based computation). + _.min = function(obj, iterator, context) { + if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj); + if (!iterator && _.isEmpty(obj)) return 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}); + }); + return result.value; + }; + + // Shuffle an array. + _.shuffle = function(obj) { + var shuffled = [], rand; + each(obj, function(value, index, list) { + if (index == 0) { + shuffled[0] = value; + } else { + rand = Math.floor(Math.random() * (index + 1)); + shuffled[index] = shuffled[rand]; + shuffled[rand] = value; + } + }); + return shuffled; + }; + + // Sort the object's values by a criterion produced by an iterator. + _.sortBy = function(obj, iterator, context) { + return _.pluck(_.map(obj, function(value, index, list) { + return { + value : value, + criteria : iterator.call(context, value, index, list) + }; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }), 'value'); + }; + + // Groups the object's values by a criterion. Pass either a string attribute + // to group by, or a function that returns the criterion. + _.groupBy = function(obj, val) { + var result = {}; + var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; }; + each(obj, function(value, index) { + var key = iterator(value, index); + (result[key] || (result[key] = [])).push(value); + }); + return result; + }; + + // Use a comparator function to figure out at what index an object should + // be inserted so as to maintain order. Uses binary search. + _.sortedIndex = function(array, obj, iterator) { + iterator || (iterator = _.identity); + var low = 0, high = array.length; + while (low < high) { + var mid = (low + high) >> 1; + iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid; + } + return low; + }; + + // Safely convert anything iterable into a real, live array. + _.toArray = function(iterable) { + if (!iterable) return []; + if (iterable.toArray) return iterable.toArray(); + if (_.isArray(iterable)) return slice.call(iterable); + if (_.isArguments(iterable)) return slice.call(iterable); + return _.values(iterable); + }; + + // Return the number of elements in an object. + _.size = function(obj) { + return _.toArray(obj).length; + }; + + // Array Functions + // --------------- + + // Get the first element of an array. Passing **n** will return the first N + // values in the array. Aliased as `head`. The **guard** check allows it to work + // with `_.map`. + _.first = _.head = function(array, n, guard) { + return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; + }; + + // Returns everything but the last entry of the array. Especcialy useful on + // the arguments object. Passing **n** will return all the values in + // the array, excluding the last N. The **guard** check allows it to work with + // `_.map`. + _.initial = function(array, n, guard) { + return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); + }; + + // 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 ((n != null) && !guard) { + return slice.call(array, Math.max(array.length - n, 0)); + } else { + return array[array.length - 1]; + } + }; + + // Returns everything but the first entry of the array. Aliased as `tail`. + // Especially useful on the arguments object. Passing an **index** will return + // the rest of the values in the array from that index onward. The **guard** + // check allows it to work with `_.map`. + _.rest = _.tail = function(array, index, guard) { + return slice.call(array, (index == null) || guard ? 1 : index); + }; + + // Trim out all falsy values from an array. + _.compact = function(array) { + return _.filter(array, function(value){ return !!value; }); + }; + + // Return a completely flattened version of an array. + _.flatten = function(array, shallow) { + return _.reduce(array, function(memo, value) { + if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value)); + memo[memo.length] = value; + return memo; + }, []); + }; + + // Return a version of the array that does not contain the specified value(s). + _.without = function(array) { + return _.difference(array, slice.call(arguments, 1)); + }; + + // Produce a duplicate-free version of the array. If the array has already + // been sorted, you have the option of using a faster algorithm. + // Aliased as `unique`. + _.uniq = _.unique = function(array, isSorted, iterator) { + var initial = iterator ? _.map(array, iterator) : array; + var result = []; + _.reduce(initial, function(memo, el, i) { + if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) { + memo[memo.length] = el; + result[result.length] = array[i]; + } + return memo; + }, []); + return result; + }; + + // Produce an array that contains the union: each distinct element from all of + // the passed-in arrays. + _.union = function() { + return _.uniq(_.flatten(arguments, true)); + }; + + // Produce an array that contains every item shared between all the + // passed-in arrays. (Aliased as "intersect" for back-compat.) + _.intersection = _.intersect = function(array) { + var rest = slice.call(arguments, 1); + return _.filter(_.uniq(array), function(item) { + return _.every(rest, function(other) { + return _.indexOf(other, item) >= 0; + }); + }); + }; + + // Take the difference between one array and another. + // Only the elements present in just the first array will remain. + _.difference = function(array, other) { + return _.filter(array, function(value){ return !_.include(other, value); }); + }; + + // Zip together multiple lists into a single array -- elements that share + // an index go together. + _.zip = function() { + var args = slice.call(arguments); + var length = _.max(_.pluck(args, 'length')); + var results = new Array(length); + for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i); + return results; + }; + + // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), + // we need this function. Return the position of the first occurrence of an + // item in an array, or -1 if the item is not included in the array. + // Delegates to **ECMAScript 5**'s native `indexOf` if available. + // If the array is large and already in sort order, pass `true` + // for **isSorted** to use binary search. + _.indexOf = function(array, item, isSorted) { + if (array == null) return -1; + var i, l; + if (isSorted) { + i = _.sortedIndex(array, item); + return array[i] === item ? i : -1; + } + if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item); + for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i; + return -1; + }; + + // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. + _.lastIndexOf = function(array, item) { + if (array == null) return -1; + if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item); + var i = array.length; + while (i--) if (array[i] === item) return i; + return -1; + }; + + // Generate an integer Array containing an arithmetic progression. A port of + // the native Python `range()` function. See + // [the Python documentation](http://docs.python.org/library/functions.html#range). + _.range = function(start, stop, step) { + if (arguments.length <= 1) { + stop = start || 0; + start = 0; + } + step = arguments[2] || 1; + + var len = Math.max(Math.ceil((stop - start) / step), 0); + var idx = 0; + var range = new Array(len); + + while(idx < len) { + range[idx++] = start; + start += step; + } + + return range; + }; + + // Function (ahem) Functions + // ------------------ + + // Reusable constructor function for prototype setting. + var ctor = function(){}; + + // 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; + }; + }; + + // Bind all of an object's methods to that object. Useful for ensuring that + // 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); + each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); + return obj; + }; + + // Memoize an expensive function by storing its results. + _.memoize = function(func, hasher) { + var memo = {}; + hasher || (hasher = _.identity); + return function() { + var key = hasher.apply(this, arguments); + return hasOwnProperty.call(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); + }; + }; + + // Delays a function for the given number of milliseconds, and then calls + // it with the arguments supplied. + _.delay = function(func, wait) { + var args = slice.call(arguments, 2); + return setTimeout(function(){ return func.apply(func, args); }, wait); + }; + + // Defers a function, scheduling it to run after the current call stack has + // cleared. + _.defer = function(func) { + return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); + }; + + // 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, throttling, more; + var whenDone = _.debounce(function(){ more = throttling = false; }, wait); + return function() { + context = this; args = arguments; + var later = function() { + timeout = null; + if (more) func.apply(context, args); + whenDone(); + }; + if (!timeout) timeout = setTimeout(later, wait); + if (throttling) { + more = true; + } else { + func.apply(context, args); + } + whenDone(); + throttling = true; + }; + }; + + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. + _.debounce = function(func, wait) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + func.apply(context, args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + }; + + // Returns a function that will be executed at most one time, no matter how + // often you call it. Useful for lazy initialization. + _.once = function(func) { + var ran = false, memo; + return function() { + if (ran) return memo; + ran = true; + return memo = func.apply(this, arguments); + }; + }; + + // Returns the first function passed as an argument to the second, + // allowing you to adjust arguments, run code before and after, and + // conditionally execute the original function. + _.wrap = function(func, wrapper) { + return function() { + var args = [func].concat(slice.call(arguments)); + return wrapper.apply(this, args); + }; + }; + + // Returns a function that is the composition of a list of functions, each + // consuming the return value of the function that follows. + _.compose = function() { + var funcs = slice.call(arguments); + return function() { + var args = slice.call(arguments); + for (var i = funcs.length - 1; i >= 0; i--) { + args = [funcs[i].apply(this, args)]; + } + return args[0]; + }; + }; + + // Returns a function that will only be executed after being called N times. + _.after = function(times, func) { + if (times <= 0) return func(); + return function() { + if (--times < 1) { return func.apply(this, arguments); } + }; + }; + + // Object Functions + // ---------------- + + // Retrieve the names of an object's properties. + // Delegates to **ECMAScript 5**'s native `Object.keys` + _.keys = nativeKeys || function(obj) { + if (obj !== Object(obj)) throw new TypeError('Invalid object'); + var keys = []; + for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key; + return keys; + }; + + // Retrieve the values of an object's properties. + _.values = function(obj) { + return _.map(obj, _.identity); + }; + + // Return a sorted list of the function names available on the object. + // Aliased as `methods` + _.functions = _.methods = function(obj) { + var names = []; + for (var key in obj) { + if (_.isFunction(obj[key])) names.push(key); + } + return names.sort(); + }; + + // Extend a given object with all the properties in passed-in object(s). + _.extend = function(obj) { + each(slice.call(arguments, 1), function(source) { + for (var prop in source) { + if (source[prop] !== void 0) obj[prop] = source[prop]; + } + }); + return obj; + }; + + // Fill in a given object with default properties. + _.defaults = function(obj) { + each(slice.call(arguments, 1), function(source) { + for (var prop in source) { + if (obj[prop] == null) obj[prop] = source[prop]; + } + }); + return obj; + }; + + // Create a (shallow-cloned) duplicate of an object. + _.clone = function(obj) { + if (!_.isObject(obj)) return obj; + return _.isArray(obj) ? obj.slice() : _.extend({}, obj); + }; + + // Invokes interceptor with the obj, and then returns obj. + // The primary purpose of this method is to "tap into" a method chain, in + // order to perform operations on intermediate results within the chain. + _.tap = function(obj, interceptor) { + interceptor(obj); + return obj; + }; + + // Internal recursive comparison function. + function eq(a, b, stack) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal. + if (a === b) return a !== 0 || 1 / a == 1 / b; + // A strict comparison is necessary because `null == undefined`. + if (a == null || b == null) return a === b; + // Unwrap any wrapped objects. + if (a._chain) a = a._wrapped; + if (b._chain) b = b._wrapped; + // Invoke a custom `isEqual` method if one is provided. + if (_.isFunction(a.isEqual)) return a.isEqual(b); + if (_.isFunction(b.isEqual)) return b.isEqual(a); + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className != toString.call(b)) return false; + switch (className) { + // Strings, numbers, dates, and booleans are compared by value. + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")`. + return String(a) == String(b); + case '[object Number]': + a = +a; + b = +b; + // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for + // other numeric values. + return a != a ? b != b : (a == 0 ? 1 / a == 1 / b : a == b); + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are compared by their + // millisecond representations. Note that invalid dates with millisecond representations + // of `NaN` are not equivalent. + return +a == +b; + // RegExps are compared by their source patterns and flags. + case '[object RegExp]': + return a.source == b.source && + a.global == b.global && + a.multiline == b.multiline && + a.ignoreCase == b.ignoreCase; + } + if (typeof a != 'object' || typeof b != 'object') return false; + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. + var length = stack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (stack[length] == a) return true; + } + // Add the first object to the stack of traversed objects. + stack.push(a); + var size = 0, result = true; + // Recursively compare objects and arrays. + if (className == '[object Array]') { + // Compare array lengths to determine if a deep comparison is necessary. + size = a.length; + result = size == b.length; + if (result) { + // Deep compare the contents, ignoring non-numeric properties. + while (size--) { + // Ensure commutative equality for sparse arrays. + if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break; + } + } + } else { + // Objects with different constructors are not equivalent. + if ("constructor" in a != "constructor" in b || a.constructor != b.constructor) return false; + // Deep compare objects. + for (var key in a) { + if (hasOwnProperty.call(a, key)) { + // Count the expected number of properties. + size++; + // Deep compare each member. + if (!(result = hasOwnProperty.call(b, key) && eq(a[key], b[key], stack))) break; + } + } + // Ensure that both objects contain the same number of properties. + if (result) { + for (key in b) { + if (hasOwnProperty.call(b, key) && !(size--)) break; + } + result = !size; + } + } + // Remove the first object from the stack of traversed objects. + stack.pop(); + return result; + } + + // Perform a deep comparison to check if two objects are equal. + _.isEqual = function(a, b) { + return eq(a, b, []); + }; + + // Is a given array, string, or object empty? + // An "empty" object has no enumerable own-properties. + _.isEmpty = function(obj) { + if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; + for (var key in obj) if (hasOwnProperty.call(obj, key)) return false; + return true; + }; + + // Is a given value a DOM element? + _.isElement = function(obj) { + return !!(obj && obj.nodeType == 1); + }; + + // Is a given value an array? + // Delegates to ECMA5's native Array.isArray + _.isArray = nativeIsArray || function(obj) { + return toString.call(obj) == '[object Array]'; + }; + + // Is a given variable an object? + _.isObject = function(obj) { + return obj === Object(obj); + }; + + // Is a given variable an arguments object? + if (toString.call(arguments) == '[object Arguments]') { + _.isArguments = function(obj) { + return toString.call(obj) == '[object Arguments]'; + }; + } else { + _.isArguments = function(obj) { + return !!(obj && hasOwnProperty.call(obj, 'callee')); + }; + } + + // Is a given value a function? + _.isFunction = function(obj) { + return toString.call(obj) == '[object Function]'; + }; + + // Is a given value a string? + _.isString = function(obj) { + return toString.call(obj) == '[object String]'; + }; + + // Is a given value a number? + _.isNumber = function(obj) { + return toString.call(obj) == '[object Number]'; + }; + + // Is the given value `NaN`? + _.isNaN = function(obj) { + // `NaN` is the only value for which `===` is not reflexive. + return obj !== obj; + }; + + // Is a given value a boolean? + _.isBoolean = function(obj) { + return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; + }; + + // Is a given value a date? + _.isDate = function(obj) { + return toString.call(obj) == '[object Date]'; + }; + + // Is the given value a regular expression? + _.isRegExp = function(obj) { + return toString.call(obj) == '[object RegExp]'; + }; + + // Is a given value equal to null? + _.isNull = function(obj) { + return obj === null; + }; + + // Is a given variable undefined? + _.isUndefined = function(obj) { + return obj === void 0; + }; + + // Utility Functions + // ----------------- + + // Run Underscore.js in *noConflict* mode, returning the `_` variable to its + // previous owner. Returns a reference to the Underscore object. + _.noConflict = function() { + root._ = previousUnderscore; + return this; + }; + + // Keep the identity function around for default iterators. + _.identity = function(value) { + return value; + }; + + // Run a function **n** times. + _.times = function (n, iterator, context) { + for (var i = 0; i < n; i++) iterator.call(context, i); + }; + + // Escape a string for HTML interpolation. + _.escape = function(string) { + return (''+string).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g,'/'); + }; + + // Add your own custom functions to the Underscore object, ensuring that + // they're correctly added to the OOP wrapper as well. + _.mixin = function(obj) { + each(_.functions(obj), function(name){ + addToWrapper(name, _[name] = obj[name]); + }); + }; + + // Generate a unique integer id (unique within the entire client session). + // Useful for temporary DOM ids. + var idCounter = 0; + _.uniqueId = function(prefix) { + var id = idCounter++; + return prefix ? prefix + id : id; + }; + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(str, data) { + var c = _.templateSettings; + var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' + + 'with(obj||{}){__p.push(\'' + + str.replace(/\\/g, '\\\\') + .replace(/'/g, "\\'") + .replace(c.escape, function(match, code) { + return "',_.escape(" + code.replace(/\\'/g, "'") + "),'"; + }) + .replace(c.interpolate, function(match, code) { + return "'," + code.replace(/\\'/g, "'") + ",'"; + }) + .replace(c.evaluate || null, function(match, code) { + return "');" + code.replace(/\\'/g, "'") + .replace(/[\r\n\t]/g, ' ') + ";__p.push('"; + }) + .replace(/\r/g, '\\r') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') + + "');}return __p.join('');"; + var func = new Function('obj', '_', tmpl); + return data ? func(data, _) : function(data) { return func(data, _) }; + }; + + // The OOP Wrapper + // --------------- + + // If Underscore is called as a function, it returns a wrapped object that + // can be used OO-style. This wrapper holds altered versions of all the + // underscore functions. Wrapped objects may be chained. + var wrapper = function(obj) { this._wrapped = obj; }; + + // Expose `wrapper.prototype` as `_.prototype` + _.prototype = wrapper.prototype; + + // Helper function to continue chaining intermediate results. + var result = function(obj, chain) { + return chain ? _(obj).chain() : obj; + }; + + // A method to easily add functions to the OOP wrapper. + var addToWrapper = function(name, func) { + wrapper.prototype[name] = function() { + var args = slice.call(arguments); + unshift.call(args, this._wrapped); + return result(func.apply(_, args), this._chain); + }; + }; + + // Add all of the Underscore functions to the wrapper object. + _.mixin(_); + + // Add all mutator Array functions to the wrapper. + each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + wrapper.prototype[name] = function() { + method.apply(this._wrapped, arguments); + return result(this._wrapped, this._chain); + }; + }); + + // Add all accessor Array functions to the wrapper. + each(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + wrapper.prototype[name] = function() { + return result(method.apply(this._wrapped, arguments), this._chain); + }; + }); + + // Start chaining a wrapped Underscore object. + wrapper.prototype.chain = function() { + this._chain = true; + return this; + }; + + // Extracts the result from a wrapped and chained object. + wrapper.prototype.value = function() { + return this._wrapped; + }; + +}).call(this); diff --git a/node_modules/yaconfig b/node_modules/yaconfig new file mode 120000 index 0000000..f5b46c9 --- /dev/null +++ b/node_modules/yaconfig @@ -0,0 +1 @@ +/usr/local/lib/node_modules/yaconfig \ No newline at end of file diff --git a/project.sublime-project b/project.sublime-project new file mode 100644 index 0000000..59b8038 --- /dev/null +++ b/project.sublime-project @@ -0,0 +1,8 @@ +{ + "folders": + [ + { + "path": "/Users/craig/.cupboard/projects/beet" + } + ] +} \ No newline at end of file