From 351e5b3e1f08190e7c6c32b5cd03bc14abbb82e9 Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Fri, 2 Dec 2011 16:12:31 +0000 Subject: [PATCH] Restored async.js module Got lost in a spate of Git confusion on my part --- node_modules/async/.gitmodules | 9 + node_modules/async/LICENSE | 19 + node_modules/async/Makefile | 21 + node_modules/async/README.md | 1009 +++++++++++++ node_modules/async/deps/nodeunit.css | 70 + node_modules/async/deps/nodeunit.js | 1966 +++++++++++++++++++++++++ node_modules/async/dist/async.min.js | 1 + node_modules/async/index.js | 3 + node_modules/async/lib/async.js | 690 +++++++++ node_modules/async/nodelint.cfg | 4 + node_modules/async/package.json | 16 + node_modules/async/test/test-async.js | 1577 ++++++++++++++++++++ node_modules/async/test/test.html | 24 + 13 files changed, 5409 insertions(+) create mode 100644 node_modules/async/.gitmodules create mode 100644 node_modules/async/LICENSE create mode 100644 node_modules/async/Makefile create mode 100644 node_modules/async/README.md create mode 100644 node_modules/async/deps/nodeunit.css create mode 100644 node_modules/async/deps/nodeunit.js create mode 100644 node_modules/async/dist/async.min.js create mode 100644 node_modules/async/index.js create mode 100644 node_modules/async/lib/async.js create mode 100644 node_modules/async/nodelint.cfg create mode 100644 node_modules/async/package.json create mode 100644 node_modules/async/test/test-async.js create mode 100644 node_modules/async/test/test.html diff --git a/node_modules/async/.gitmodules b/node_modules/async/.gitmodules new file mode 100644 index 000000000..a9aae984f --- /dev/null +++ b/node_modules/async/.gitmodules @@ -0,0 +1,9 @@ +[submodule "deps/nodeunit"] + path = deps/nodeunit + url = git://github.com/caolan/nodeunit.git +[submodule "deps/UglifyJS"] + path = deps/UglifyJS + url = https://github.com/mishoo/UglifyJS.git +[submodule "deps/nodelint"] + path = deps/nodelint + url = https://github.com/tav/nodelint.git diff --git a/node_modules/async/LICENSE b/node_modules/async/LICENSE new file mode 100644 index 000000000..b7f9d5001 --- /dev/null +++ b/node_modules/async/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2010 Caolan McMahon + +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/async/Makefile b/node_modules/async/Makefile new file mode 100644 index 000000000..00f07ea02 --- /dev/null +++ b/node_modules/async/Makefile @@ -0,0 +1,21 @@ +PACKAGE = asyncjs +NODEJS = $(if $(shell test -f /usr/bin/nodejs && echo "true"),nodejs,node) + +BUILDDIR = dist + +all: build + +build: $(wildcard lib/*.js) + mkdir -p $(BUILDDIR) + uglifyjs lib/async.js > $(BUILDDIR)/async.min.js + +test: + nodeunit test + +clean: + rm -rf $(BUILDDIR) + +lint: + nodelint --config nodelint.cfg lib/async.js + +.PHONY: test build all diff --git a/node_modules/async/README.md b/node_modules/async/README.md new file mode 100644 index 000000000..f3c44ac86 --- /dev/null +++ b/node_modules/async/README.md @@ -0,0 +1,1009 @@ +# Async.js + +Async is a utility module which provides straight-forward, powerful functions +for working with asynchronous JavaScript. Although originally designed for +use with [node.js](http://nodejs.org), it can also be used directly in the +browser. + +Async provides around 20 functions that include the usual 'functional' +suspects (map, reduce, filter, forEach…) as well as some common patterns +for asynchronous control flow (parallel, series, waterfall…). All these +functions assume you follow the node.js convention of providing a single +callback as the last argument of your async function. + + +## Quick Examples + + async.map(['file1','file2','file3'], fs.stat, function(err, results){ + // results is now an array of stats for each file + }); + + async.filter(['file1','file2','file3'], path.exists, function(results){ + // results now equals an array of the existing files + }); + + async.parallel([ + function(){ ... }, + function(){ ... } + ], callback); + + async.series([ + function(){ ... }, + function(){ ... } + ]); + +There are many more functions available so take a look at the docs below for a +full list. This module aims to be comprehensive, so if you feel anything is +missing please create a GitHub issue for it. + + +## Download + +Releases are available for download from +[GitHub](http://github.com/caolan/async/downloads). +Alternatively, you can install using Node Package Manager (npm): + + npm install async + + +__Development:__ [async.js](https://github.com/caolan/async/raw/master/lib/async.js) - 17.5kb Uncompressed + +__Production:__ [async.min.js](https://github.com/caolan/async/raw/master/dist/async.min.js) - 1.7kb Packed and Gzipped + + +## In the Browser + +So far its been tested in IE6, IE7, IE8, FF3.6 and Chrome 5. Usage: + + + + + +## Documentation + +### Collections + +* [forEach](#forEach) +* [map](#map) +* [filter](#filter) +* [reject](#reject) +* [reduce](#reduce) +* [detect](#detect) +* [sortBy](#sortBy) +* [some](#some) +* [every](#every) +* [concat](#concat) + +### Control Flow + +* [series](#series) +* [parallel](#parallel) +* [whilst](#whilst) +* [until](#until) +* [waterfall](#waterfall) +* [queue](#queue) +* [auto](#auto) +* [iterator](#iterator) +* [apply](#apply) +* [nextTick](#nextTick) + +### Utils + +* [memoize](#memoize) +* [unmemoize](#unmemoize) +* [log](#log) +* [dir](#dir) +* [noConflict](#noConflict) + + +## Collections + + +### forEach(arr, iterator, callback) + +Applies an iterator function to each item in an array, in parallel. +The iterator is called with an item from the list and a callback for when it +has finished. If the iterator passes an error to this callback, the main +callback for the forEach function is immediately called with the error. + +Note, that since this function applies the iterator to each item in parallel +there is no guarantee that the iterator functions will complete in order. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback which must be called once it has completed. +* callback(err) - A callback which is called after all the iterator functions + have finished, or an error has occurred. + +__Example__ + + // assuming openFiles is an array of file names and saveFile is a function + // to save the modified contents of that file: + + async.forEach(openFiles, saveFile, function(err){ + // if any of the saves produced an error, err would equal that error + }); + +--------------------------------------- + + +### forEachSeries(arr, iterator, callback) + +The same as forEach only the iterator is applied to each item in the array in +series. The next iterator is only called once the current one has completed +processing. This means the iterator functions will complete in order. + + +--------------------------------------- + + +### forEachLimit(arr, limit, iterator, callback) + +The same as forEach only the iterator is applied to batches of items in the +array, in series. The next batch of iterators is only called once the current +one has completed processing. + +__Arguments__ + +* arr - An array to iterate over. +* limit - How many items should be in each batch. +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback which must be called once it has completed. +* callback(err) - A callback which is called after all the iterator functions + have finished, or an error has occurred. + +__Example__ + + // Assume documents is an array of JSON objects and requestApi is a + // function that interacts with a rate-limited REST api. + + async.forEachLimit(documents, 20, requestApi, function(err){ + // if any of the saves produced an error, err would equal that error + }); +--------------------------------------- + + +### map(arr, iterator, callback) + +Produces a new array of values by mapping each value in the given array through +the iterator function. The iterator is called with an item from the array and a +callback for when it has finished processing. The callback takes 2 arguments, +an error and the transformed item from the array. If the iterator passes an +error to this callback, the main callback for the map function is immediately +called with the error. + +Note, that since this function applies the iterator to each item in parallel +there is no guarantee that the iterator functions will complete in order, however +the results array will be in the same order as the original array. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback which must be called once it has completed + with an error (which can be null) and a transformed item. +* callback(err, results) - A callback which is called after all the iterator + functions have finished, or an error has occurred. Results is an array of the + transformed items from the original array. + +__Example__ + + async.map(['file1','file2','file3'], fs.stat, function(err, results){ + // results is now an array of stats for each file + }); + +--------------------------------------- + + +### mapSeries(arr, iterator, callback) + +The same as map only the iterator is applied to each item in the array in +series. The next iterator is only called once the current one has completed +processing. The results array will be in the same order as the original. + + +--------------------------------------- + + +### filter(arr, iterator, callback) + +__Alias:__ select + +Returns a new array of all the values which pass an async truth test. +_The callback for each iterator call only accepts a single argument of true or +false, it does not accept an error argument first!_ This is in-line with the +way node libraries work with truth tests like path.exists. This operation is +performed in parallel, but the results array will be in the same order as the +original. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A truth test to apply to each item in the array. + The iterator is passed a callback which must be called once it has completed. +* callback(results) - A callback which is called after all the iterator + functions have finished. + +__Example__ + + async.filter(['file1','file2','file3'], path.exists, function(results){ + // results now equals an array of the existing files + }); + +--------------------------------------- + + +### filterSeries(arr, iterator, callback) + +__alias:__ selectSeries + +The same as filter only the iterator is applied to each item in the array in +series. The next iterator is only called once the current one has completed +processing. The results array will be in the same order as the original. + +--------------------------------------- + + +### reject(arr, iterator, callback) + +The opposite of filter. Removes values that pass an async truth test. + +--------------------------------------- + + +### rejectSeries(arr, iterator, callback) + +The same as filter, only the iterator is applied to each item in the array +in series. + + +--------------------------------------- + + +### reduce(arr, memo, iterator, callback) + +__aliases:__ inject, foldl + +Reduces a list of values into a single value using an async iterator to return +each successive step. Memo is the initial state of the reduction. This +function only operates in series. For performance reasons, it may make sense to +split a call to this function into a parallel map, then use the normal +Array.prototype.reduce on the results. This function is for situations where +each step in the reduction needs to be async, if you can get the data before +reducing it then its probably a good idea to do so. + +__Arguments__ + +* arr - An array to iterate over. +* memo - The initial state of the reduction. +* iterator(memo, item, callback) - A function applied to each item in the + array to produce the next step in the reduction. The iterator is passed a + callback which accepts an optional error as its first argument, and the state + of the reduction as the second. If an error is passed to the callback, the + reduction is stopped and the main callback is immediately called with the + error. +* callback(err, result) - A callback which is called after all the iterator + functions have finished. Result is the reduced value. + +__Example__ + + async.reduce([1,2,3], 0, function(memo, item, callback){ + // pointless async: + process.nextTick(function(){ + callback(null, memo + item) + }); + }, function(err, result){ + // result is now equal to the last value of memo, which is 6 + }); + +--------------------------------------- + + +### reduceRight(arr, memo, iterator, callback) + +__Alias:__ foldr + +Same as reduce, only operates on the items in the array in reverse order. + + +--------------------------------------- + + +### detect(arr, iterator, callback) + +Returns the first value in a list that passes an async truth test. The +iterator is applied in parallel, meaning the first iterator to return true will +fire the detect callback with that result. That means the result might not be +the first item in the original array (in terms of order) that passes the test. + +If order within the original array is important then look at detectSeries. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A truth test to apply to each item in the array. + The iterator is passed a callback which must be called once it has completed. +* callback(result) - A callback which is called as soon as any iterator returns + true, or after all the iterator functions have finished. Result will be + the first item in the array that passes the truth test (iterator) or the + value undefined if none passed. + +__Example__ + + async.detect(['file1','file2','file3'], path.exists, function(result){ + // result now equals the first file in the list that exists + }); + +--------------------------------------- + + +### detectSeries(arr, iterator, callback) + +The same as detect, only the iterator is applied to each item in the array +in series. This means the result is always the first in the original array (in +terms of array order) that passes the truth test. + + +--------------------------------------- + + +### sortBy(arr, iterator, callback) + +Sorts a list by the results of running each value through an async iterator. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback which must be called once it has completed + with an error (which can be null) and a value to use as the sort criteria. +* callback(err, results) - A callback which is called after all the iterator + functions have finished, or an error has occurred. Results is the items from + the original array sorted by the values returned by the iterator calls. + +__Example__ + + async.sortBy(['file1','file2','file3'], function(file, callback){ + fs.stat(file, function(err, stats){ + callback(err, stats.mtime); + }); + }, function(err, results){ + // results is now the original array of files sorted by + // modified date + }); + + +--------------------------------------- + + +### some(arr, iterator, callback) + +__Alias:__ any + +Returns true if at least one element in the array satisfies an async test. +_The callback for each iterator call only accepts a single argument of true or +false, it does not accept an error argument first!_ This is in-line with the +way node libraries work with truth tests like path.exists. Once any iterator +call returns true, the main callback is immediately called. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A truth test to apply to each item in the array. + The iterator is passed a callback which must be called once it has completed. +* callback(result) - A callback which is called as soon as any iterator returns + true, or after all the iterator functions have finished. Result will be + either true or false depending on the values of the async tests. + +__Example__ + + async.some(['file1','file2','file3'], path.exists, function(result){ + // if result is true then at least one of the files exists + }); + +--------------------------------------- + + +### every(arr, iterator, callback) + +__Alias:__ all + +Returns true if every element in the array satisfies an async test. +_The callback for each iterator call only accepts a single argument of true or +false, it does not accept an error argument first!_ This is in-line with the +way node libraries work with truth tests like path.exists. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A truth test to apply to each item in the array. + The iterator is passed a callback which must be called once it has completed. +* callback(result) - A callback which is called after all the iterator + functions have finished. Result will be either true or false depending on + the values of the async tests. + +__Example__ + + async.every(['file1','file2','file3'], path.exists, function(result){ + // if result is true then every file exists + }); + +--------------------------------------- + + +### concat(arr, iterator, callback) + +Applies an iterator to each item in a list, concatenating the results. Returns the +concatenated list. The iterators are called in parallel, and the results are +concatenated as they return. There is no guarantee that the results array will +be returned in the original order of the arguments passed to the iterator function. + +__Arguments__ + +* arr - An array to iterate over +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback which must be called once it has completed + with an error (which can be null) and an array of results. +* callback(err, results) - A callback which is called after all the iterator + functions have finished, or an error has occurred. Results is an array containing + the concatenated results of the iterator function. + +__Example__ + + async.concat(['dir1','dir2','dir3'], fs.readdir, function(err, files){ + // files is now a list of filenames that exist in the 3 directories + }); + +--------------------------------------- + + +### concatSeries(arr, iterator, callback) + +Same as async.concat, but executes in series instead of parallel. + + +## Control Flow + + +### series(tasks, [callback]) + +Run an array of functions in series, each one running once the previous +function has completed. If any functions in the series pass an error to its +callback, no more functions are run and the callback for the series is +immediately called with the value of the error. Once the tasks have completed, +the results are passed to the final callback as an array. + +It is also possible to use an object instead of an array. Each property will be +run as a function and the results will be passed to the final callback as an object +instead of an array. This can be a more readable way of handling results from +async.series. + + +__Arguments__ + +* tasks - An array or object containing functions to run, each function is passed + a callback it must call on completion. +* callback(err, results) - An optional callback to run once all the functions + have completed. This function gets an array of all the arguments passed to + the callbacks used in the array. + +__Example__ + + async.series([ + function(callback){ + // do some stuff ... + callback(null, 'one'); + }, + function(callback){ + // do some more stuff ... + callback(null, 'two'); + }, + ], + // optional callback + function(err, results){ + // results is now equal to ['one', 'two'] + }); + + + // an example using an object instead of an array + async.series({ + one: function(callback){ + setTimeout(function(){ + callback(null, 1); + }, 200); + }, + two: function(callback){ + setTimeout(function(){ + callback(null, 2); + }, 100); + }, + }, + function(err, results) { + // results is now equal to: {one: 1, two: 2} + }); + + +--------------------------------------- + + +### parallel(tasks, [callback]) + +Run an array of functions in parallel, without waiting until the previous +function has completed. If any of the functions pass an error to its +callback, the main callback is immediately called with the value of the error. +Once the tasks have completed, the results are passed to the final callback as an +array. + +It is also possible to use an object instead of an array. Each property will be +run as a function and the results will be passed to the final callback as an object +instead of an array. This can be a more readable way of handling results from +async.parallel. + + +__Arguments__ + +* tasks - An array or object containing functions to run, each function is passed a + callback it must call on completion. +* callback(err, results) - An optional callback to run once all the functions + have completed. This function gets an array of all the arguments passed to + the callbacks used in the array. + +__Example__ + + async.parallel([ + function(callback){ + setTimeout(function(){ + callback(null, 'one'); + }, 200); + }, + function(callback){ + setTimeout(function(){ + callback(null, 'two'); + }, 100); + }, + ], + // optional callback + function(err, results){ + // in this case, the results array will equal ['two','one'] + // because the functions were run in parallel and the second + // function had a shorter timeout before calling the callback. + }); + + + // an example using an object instead of an array + async.parallel({ + one: function(callback){ + setTimeout(function(){ + callback(null, 1); + }, 200); + }, + two: function(callback){ + setTimeout(function(){ + callback(null, 2); + }, 100); + }, + }, + function(err, results) { + // results is now equals to: {one: 1, two: 2} + }); + + +--------------------------------------- + + +### whilst(test, fn, callback) + +Repeatedly call fn, while test returns true. Calls the callback when stopped, +or an error occurs. + +__Arguments__ + +* test() - synchronous truth test to perform before each execution of fn. +* fn(callback) - A function to call each time the test passes. The function is + passed a callback which must be called once it has completed with an optional + error as the first argument. +* callback(err) - A callback which is called after the test fails and repeated + execution of fn has stopped. + +__Example__ + + var count = 0; + + async.whilst( + function () { return count < 5; }, + function (callback) { + count++; + setTimeout(callback, 1000); + }, + function (err) { + // 5 seconds have passed + } + }); + + +--------------------------------------- + + +### until(test, fn, callback) + +Repeatedly call fn, until test returns true. Calls the callback when stopped, +or an error occurs. + +The inverse of async.whilst. + + +--------------------------------------- + + +### waterfall(tasks, [callback]) + +Runs an array of functions in series, each passing their results to the next in +the array. However, if any of the functions pass an error to the callback, the +next function is not executed and the main callback is immediately called with +the error. + +__Arguments__ + +* tasks - An array of functions to run, each function is passed a callback it + must call on completion. +* callback(err) - An optional callback to run once all the functions have + completed. This function gets passed any error that may have occurred. + +__Example__ + + async.waterfall([ + function(callback){ + callback(null, 'one', 'two'); + }, + function(arg1, arg2, callback){ + callback(null, 'three'); + }, + function(arg1, callback){ + // arg1 now equals 'three' + callback(null, 'done'); + } + ]); + + +--------------------------------------- + + +### queue(worker, concurrency) + +Creates a queue object with the specified concurrency. Tasks added to the +queue will be processed in parallel (up to the concurrency limit). If all +workers are in progress, the task is queued until one is available. Once +a worker has completed a task, the task's callback is called. + +__Arguments__ + +* worker(task, callback) - An asynchronous function for processing a queued + task. +* concurrency - An integer for determining how many worker functions should be + run in parallel. + +__Queue objects__ + +The queue object returned by this function has the following properties and +methods: + +* length() - a function returning the number of items waiting to be processed. +* concurrency - an integer for determining how many worker functions should be + run in parallel. This property can be changed after a queue is created to + alter the concurrency on-the-fly. +* push(task, [callback]) - add a new task to the queue, the callback is called + once the worker has finished processing the task. +* saturated - a callback that is called when the queue length hits the concurrency and further tasks will be queued +* empty - a callback that is called when the last item from the queue is given to a worker +* drain - a callback that is called when the last item from the queue has returned from the worker + +__Example__ + + // create a queue object with concurrency 2 + + var q = async.queue(function (task, callback) { + console.log('hello ' + task.name); + callback(); + }, 2); + + + // assign a callback + q.drain = function() { + console.log('all items have been processed'); + } + + // add some items to the queue + + q.push({name: 'foo'}, function (err) { + console.log('finished processing foo'); + }); + q.push({name: 'bar'}, function (err) { + console.log('finished processing bar'); + }); + + +--------------------------------------- + + +### auto(tasks, [callback]) + +Determines the best order for running functions based on their requirements. +Each function can optionally depend on other functions being completed first, +and each function is run as soon as its requirements are satisfied. If any of +the functions pass an error to their callback, that function will not complete +(so any other functions depending on it will not run) and the main callback +will be called immediately with the error. Functions also receive an object +containing the results of functions on which they depend. + +__Arguments__ + +* tasks - An object literal containing named functions or an array of + requirements, with the function itself the last item in the array. The key + used for each function or array is used when specifying requirements. The + syntax is easier to understand by looking at the example. +* callback(err) - An optional callback which is called when all the tasks have + been completed. The callback may receive an error as an argument. + +__Example__ + + async.auto({ + get_data: function(callback){ + // async code to get some data + }, + make_folder: function(callback){ + // async code to create a directory to store a file in + // this is run at the same time as getting the data + }, + write_file: ['get_data', 'make_folder', function(callback){ + // once there is some data and the directory exists, + // write the data to a file in the directory + callback(null, filename); + }], + email_link: ['write_file', function(callback, results){ + // once the file is written let's email a link to it... + // results.write_file contains the filename returned by write_file. + }] + }); + +This is a fairly trivial example, but to do this using the basic parallel and +series functions would look like this: + + async.parallel([ + function(callback){ + // async code to get some data + }, + function(callback){ + // async code to create a directory to store a file in + // this is run at the same time as getting the data + } + ], + function(results){ + async.series([ + function(callback){ + // once there is some data and the directory exists, + // write the data to a file in the directory + }, + email_link: ['write_file', function(callback){ + // once the file is written let's email a link to it... + } + ]); + }); + +For a complicated series of async tasks using the auto function makes adding +new tasks much easier and makes the code more readable. + + +--------------------------------------- + + +### iterator(tasks) + +Creates an iterator function which calls the next function in the array, +returning a continuation to call the next one after that. Its also possible to +'peek' the next iterator by doing iterator.next(). + +This function is used internally by the async module but can be useful when +you want to manually control the flow of functions in series. + +__Arguments__ + +* tasks - An array of functions to run, each function is passed a callback it + must call on completion. + +__Example__ + + var iterator = async.iterator([ + function(){ sys.p('one'); }, + function(){ sys.p('two'); }, + function(){ sys.p('three'); } + ]); + + node> var iterator2 = iterator(); + 'one' + node> var iterator3 = iterator2(); + 'two' + node> iterator3(); + 'three' + node> var nextfn = iterator2.next(); + node> nextfn(); + 'three' + + +--------------------------------------- + + +### apply(function, arguments..) + +Creates a continuation function with some arguments already applied, a useful +shorthand when combined with other control flow functions. Any arguments +passed to the returned function are added to the arguments originally passed +to apply. + +__Arguments__ + +* function - The function you want to eventually apply all arguments to. +* arguments... - Any number of arguments to automatically apply when the + continuation is called. + +__Example__ + + // using apply + + async.parallel([ + async.apply(fs.writeFile, 'testfile1', 'test1'), + async.apply(fs.writeFile, 'testfile2', 'test2'), + ]); + + + // the same process without using apply + + async.parallel([ + function(callback){ + fs.writeFile('testfile1', 'test1', callback); + }, + function(callback){ + fs.writeFile('testfile2', 'test2', callback); + }, + ]); + +It's possible to pass any number of additional arguments when calling the +continuation: + + node> var fn = async.apply(sys.puts, 'one'); + node> fn('two', 'three'); + one + two + three + +--------------------------------------- + + +### nextTick(callback) + +Calls the callback on a later loop around the event loop. In node.js this just +calls process.nextTick, in the browser it falls back to setTimeout(callback, 0), +which means other higher priority events may precede the execution of the callback. + +This is used internally for browser-compatibility purposes. + +__Arguments__ + +* callback - The function to call on a later loop around the event loop. + +__Example__ + + var call_order = []; + async.nextTick(function(){ + call_order.push('two'); + // call_order now equals ['one','two] + }); + call_order.push('one') + + +## Utils + + +### memoize(fn, [hasher]) + +Caches the results of an async function. When creating a hash to store function +results against, the callback is omitted from the hash and an optional hash +function can be used. + +__Arguments__ + +* fn - the function you to proxy and cache results from. +* hasher - an optional function for generating a custom hash for storing + results, it has all the arguments applied to it apart from the callback, and + must be synchronous. + +__Example__ + + var slow_fn = function (name, callback) { + // do something + callback(null, result); + }; + var fn = async.memoize(slow_fn); + + // fn can now be used as if it were slow_fn + fn('some name', function () { + // callback + }); + + +### unmemoize(fn) + +Undoes a memoized function, reverting it to the original, unmemoized +form. Comes handy in tests. + +__Arguments__ + +* fn - the memoized function + + +### log(function, arguments) + +Logs the result of an async function to the console. Only works in node.js or +in browsers that support console.log and console.error (such as FF and Chrome). +If multiple arguments are returned from the async function, console.log is +called on each argument in order. + +__Arguments__ + +* function - The function you want to eventually apply all arguments to. +* arguments... - Any number of arguments to apply to the function. + +__Example__ + + var hello = function(name, callback){ + setTimeout(function(){ + callback(null, 'hello ' + name); + }, 1000); + }; + + node> async.log(hello, 'world'); + 'hello world' + + +--------------------------------------- + + +### dir(function, arguments) + +Logs the result of an async function to the console using console.dir to +display the properties of the resulting object. Only works in node.js or +in browsers that support console.dir and console.error (such as FF and Chrome). +If multiple arguments are returned from the async function, console.dir is +called on each argument in order. + +__Arguments__ + +* function - The function you want to eventually apply all arguments to. +* arguments... - Any number of arguments to apply to the function. + +__Example__ + + var hello = function(name, callback){ + setTimeout(function(){ + callback(null, {hello: name}); + }, 1000); + }; + + node> async.dir(hello, 'world'); + {hello: 'world'} + + +--------------------------------------- + + +### noConflict() + +Changes the value of async back to its original value, returning a reference to the +async object. diff --git a/node_modules/async/deps/nodeunit.css b/node_modules/async/deps/nodeunit.css new file mode 100644 index 000000000..274434a4a --- /dev/null +++ b/node_modules/async/deps/nodeunit.css @@ -0,0 +1,70 @@ +/*! + * Styles taken from qunit.css + */ + +h1#nodeunit-header, h1.nodeunit-header { + padding: 15px; + font-size: large; + background-color: #06b; + color: white; + font-family: 'trebuchet ms', verdana, arial; + margin: 0; +} + +h1#nodeunit-header a { + color: white; +} + +h2#nodeunit-banner { + height: 2em; + border-bottom: 1px solid white; + background-color: #eee; + margin: 0; + font-family: 'trebuchet ms', verdana, arial; +} +h2#nodeunit-banner.pass { + background-color: green; +} +h2#nodeunit-banner.fail { + background-color: red; +} + +h2#nodeunit-userAgent, h2.nodeunit-userAgent { + padding: 10px; + background-color: #eee; + color: black; + margin: 0; + font-size: small; + font-weight: normal; + font-family: 'trebuchet ms', verdana, arial; + font-size: 10pt; +} + +div#nodeunit-testrunner-toolbar { + background: #eee; + border-top: 1px solid black; + padding: 10px; + font-family: 'trebuchet ms', verdana, arial; + margin: 0; + font-size: 10pt; +} + +ol#nodeunit-tests { + font-family: 'trebuchet ms', verdana, arial; + font-size: 10pt; +} +ol#nodeunit-tests li strong { + cursor:pointer; +} +ol#nodeunit-tests .pass { + color: green; +} +ol#nodeunit-tests .fail { + color: red; +} + +p#nodeunit-testresult { + margin-left: 1em; + font-size: 10pt; + font-family: 'trebuchet ms', verdana, arial; +} diff --git a/node_modules/async/deps/nodeunit.js b/node_modules/async/deps/nodeunit.js new file mode 100644 index 000000000..59571840c --- /dev/null +++ b/node_modules/async/deps/nodeunit.js @@ -0,0 +1,1966 @@ +/*! + * Nodeunit + * https://github.com/caolan/nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + * + * json2.js + * http://www.JSON.org/json2.js + * Public Domain. + * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + */ +nodeunit = (function(){ +/* + http://www.JSON.org/json2.js + 2010-11-17 + + Public Domain. + + NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + + See http://www.JSON.org/js.html + + + This code should be minified before deployment. + See http://javascript.crockford.com/jsmin.html + + USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO + NOT CONTROL. + + + This file creates a global JSON object containing two methods: stringify + and parse. + + JSON.stringify(value, replacer, space) + value any JavaScript value, usually an object or array. + + replacer an optional parameter that determines how object + values are stringified for objects. It can be a + function or an array of strings. + + space an optional parameter that specifies the indentation + of nested structures. If it is omitted, the text will + be packed without extra whitespace. If it is a number, + it will specify the number of spaces to indent at each + level. If it is a string (such as '\t' or ' '), + it contains the characters used to indent at each level. + + This method produces a JSON text from a JavaScript value. + + When an object value is found, if the object contains a toJSON + method, its toJSON method will be called and the result will be + stringified. A toJSON method does not serialize: it returns the + value represented by the name/value pair that should be serialized, + or undefined if nothing should be serialized. The toJSON method + will be passed the key associated with the value, and this will be + bound to the value + + For example, this would serialize Dates as ISO strings. + + Date.prototype.toJSON = function (key) { + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + return this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z'; + }; + + You can provide an optional replacer method. It will be passed the + key and value of each member, with this bound to the containing + object. The value that is returned from your method will be + serialized. If your method returns undefined, then the member will + be excluded from the serialization. + + If the replacer parameter is an array of strings, then it will be + used to select the members to be serialized. It filters the results + such that only members with keys listed in the replacer array are + stringified. + + Values that do not have JSON representations, such as undefined or + functions, will not be serialized. Such values in objects will be + dropped; in arrays they will be replaced with null. You can use + a replacer function to replace those with JSON values. + JSON.stringify(undefined) returns undefined. + + The optional space parameter produces a stringification of the + value that is filled with line breaks and indentation to make it + easier to read. + + If the space parameter is a non-empty string, then that string will + be used for indentation. If the space parameter is a number, then + the indentation will be that many spaces. + + Example: + + text = JSON.stringify(['e', {pluribus: 'unum'}]); + // text is '["e",{"pluribus":"unum"}]' + + + text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); + // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' + + text = JSON.stringify([new Date()], function (key, value) { + return this[key] instanceof Date ? + 'Date(' + this[key] + ')' : value; + }); + // text is '["Date(---current time---)"]' + + + JSON.parse(text, reviver) + This method parses a JSON text to produce an object or array. + It can throw a SyntaxError exception. + + The optional reviver parameter is a function that can filter and + transform the results. It receives each of the keys and values, + and its return value is used instead of the original value. + If it returns what it received, then the structure is not modified. + If it returns undefined then the member is deleted. + + Example: + + // Parse the text. Values that look like ISO date strings will + // be converted to Date objects. + + myData = JSON.parse(text, function (key, value) { + var a; + if (typeof value === 'string') { + a = +/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); + if (a) { + return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], + +a[5], +a[6])); + } + } + return value; + }); + + myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { + var d; + if (typeof value === 'string' && + value.slice(0, 5) === 'Date(' && + value.slice(-1) === ')') { + d = new Date(value.slice(5, -1)); + if (d) { + return d; + } + } + return value; + }); + + + This is a reference implementation. You are free to copy, modify, or + redistribute. +*/ + +/*jslint evil: true, strict: false, regexp: false */ + +/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, + call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, + getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, + lastIndex, length, parse, prototype, push, replace, slice, stringify, + test, toJSON, toString, valueOf +*/ + + +// Create a JSON object only if one does not already exist. We create the +// methods in a closure to avoid creating global variables. + +if (!this.JSON) { + this.JSON = {}; +} + +(function () { + "use strict"; + + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + if (typeof Date.prototype.toJSON !== 'function') { + + Date.prototype.toJSON = function (key) { + + return isFinite(this.valueOf()) ? + this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z' : null; + }; + + String.prototype.toJSON = + Number.prototype.toJSON = + Boolean.prototype.toJSON = function (key) { + return this.valueOf(); + }; + } + + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + gap, + indent, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + rep; + + + function quote(string) { + +// If the string contains no control characters, no quote characters, and no +// backslash characters, then we can safely slap some quotes around it. +// Otherwise we must also replace the offending characters with safe escape +// sequences. + + escapable.lastIndex = 0; + return escapable.test(string) ? + '"' + string.replace(escapable, function (a) { + var c = meta[a]; + return typeof c === 'string' ? c : + '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + '"' : + '"' + string + '"'; + } + + + function str(key, holder) { + +// Produce a string from holder[key]. + + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key]; + +// If the value has a toJSON method, call it to obtain a replacement value. + + if (value && typeof value === 'object' && + typeof value.toJSON === 'function') { + value = value.toJSON(key); + } + +// If we were called with a replacer function, then call the replacer to +// obtain a replacement value. + + if (typeof rep === 'function') { + value = rep.call(holder, key, value); + } + +// What happens next depends on the value's type. + + switch (typeof value) { + case 'string': + return quote(value); + + case 'number': + +// JSON numbers must be finite. Encode non-finite numbers as null. + + return isFinite(value) ? String(value) : 'null'; + + case 'boolean': + case 'null': + +// If the value is a boolean or null, convert it to a string. Note: +// typeof null does not produce 'null'. The case is included here in +// the remote chance that this gets fixed someday. + + return String(value); + +// If the type is 'object', we might be dealing with an object or an array or +// null. + + case 'object': + +// Due to a specification blunder in ECMAScript, typeof null is 'object', +// so watch out for that case. + + if (!value) { + return 'null'; + } + +// Make an array to hold the partial results of stringifying this object value. + + gap += indent; + partial = []; + +// Is the value an array? + + if (Object.prototype.toString.apply(value) === '[object Array]') { + +// The value is an array. Stringify every element. Use null as a placeholder +// for non-JSON values. + + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null'; + } + +// Join all of the elements together, separated with commas, and wrap them in +// brackets. + + v = partial.length === 0 ? '[]' : + gap ? '[\n' + gap + + partial.join(',\n' + gap) + '\n' + + mind + ']' : + '[' + partial.join(',') + ']'; + gap = mind; + return v; + } + +// If the replacer is an array, use it to select the members to be stringified. + + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + k = rep[i]; + if (typeof k === 'string') { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } else { + +// Otherwise, iterate through all of the keys in the object. + + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } + +// Join all of the member texts together, separated with commas, +// and wrap them in braces. + + v = partial.length === 0 ? '{}' : + gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + + mind + '}' : '{' + partial.join(',') + '}'; + gap = mind; + return v; + } + } + +// If the JSON object does not yet have a stringify method, give it one. + + if (typeof JSON.stringify !== 'function') { + JSON.stringify = function (value, replacer, space) { + +// The stringify method takes a value and an optional replacer, and an optional +// space parameter, and returns a JSON text. The replacer can be a function +// that can replace values, or an array of strings that will select the keys. +// A default replacer method can be provided. Use of the space parameter can +// produce text that is more easily readable. + + var i; + gap = ''; + indent = ''; + +// If the space parameter is a number, make an indent string containing that +// many spaces. + + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' '; + } + +// If the space parameter is a string, it will be used as the indent string. + + } else if (typeof space === 'string') { + indent = space; + } + +// If there is a replacer, it must be a function or an array. +// Otherwise, throw an error. + + rep = replacer; + if (replacer && typeof replacer !== 'function' && + (typeof replacer !== 'object' || + typeof replacer.length !== 'number')) { + throw new Error('JSON.stringify'); + } + +// Make a fake root object containing our value under the key of ''. +// Return the result of stringifying the value. + + return str('', {'': value}); + }; + } + + +// If the JSON object does not yet have a parse method, give it one. + + if (typeof JSON.parse !== 'function') { + JSON.parse = function (text, reviver) { + +// The parse method takes a text and an optional reviver function, and returns +// a JavaScript value if the text is a valid JSON text. + + var j; + + function walk(holder, key) { + +// The walk method is used to recursively walk the resulting structure so +// that modifications can be made. + + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v; + } else { + delete value[k]; + } + } + } + } + return reviver.call(holder, key, value); + } + + +// Parsing happens in four stages. In the first stage, we replace certain +// Unicode characters with escape sequences. JavaScript handles many characters +// incorrectly, either silently deleting them, or treating them as line endings. + + text = String(text); + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + +// In the second stage, we run the text against regular expressions that look +// for non-JSON patterns. We are especially concerned with '()' and 'new' +// because they can cause invocation, and '=' because it can cause mutation. +// But just to be safe, we want to reject all unexpected forms. + +// We split the second stage into 4 regexp operations in order to work around +// crippling inefficiencies in IE's and Safari's regexp engines. First we +// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we +// replace all simple value tokens with ']' characters. Third, we delete all +// open brackets that follow a colon or comma or that begin the text. Finally, +// we look to see that the remaining characters are only whitespace or ']' or +// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. + + if (/^[\],:{}\s]*$/ +.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') +.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') +.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + +// In the third stage we use the eval function to compile the text into a +// JavaScript structure. The '{' operator is subject to a syntactic ambiguity +// in JavaScript: it can begin a block or an object literal. We wrap the text +// in parens to eliminate the ambiguity. + + j = eval('(' + text + ')'); + +// In the optional fourth stage, we recursively walk the new structure, passing +// each name/value pair to a reviver function for possible transformation. + + return typeof reviver === 'function' ? + walk({'': j}, '') : j; + } + +// If the text is not JSON parseable, then a SyntaxError is thrown. + + throw new SyntaxError('JSON.parse'); + }; + } +}()); +var assert = this.assert = {}; +var types = {}; +var core = {}; +var nodeunit = {}; +var reporter = {}; +/*global setTimeout: false, console: false */ +(function () { + + var async = {}; + + // global on the server, window in the browser + var root = this, + previous_async = root.async; + + if (typeof module !== 'undefined' && module.exports) { + module.exports = async; + } + else { + root.async = async; + } + + async.noConflict = function () { + root.async = previous_async; + return async; + }; + + //// cross-browser compatiblity functions //// + + var _forEach = function (arr, iterator) { + if (arr.forEach) { + return arr.forEach(iterator); + } + for (var i = 0; i < arr.length; i += 1) { + iterator(arr[i], i, arr); + } + }; + + var _map = function (arr, iterator) { + if (arr.map) { + return arr.map(iterator); + } + var results = []; + _forEach(arr, function (x, i, a) { + results.push(iterator(x, i, a)); + }); + return results; + }; + + var _reduce = function (arr, iterator, memo) { + if (arr.reduce) { + return arr.reduce(iterator, memo); + } + _forEach(arr, function (x, i, a) { + memo = iterator(memo, x, i, a); + }); + return memo; + }; + + var _keys = function (obj) { + if (Object.keys) { + return Object.keys(obj); + } + var keys = []; + for (var k in obj) { + if (obj.hasOwnProperty(k)) { + keys.push(k); + } + } + return keys; + }; + + var _indexOf = function (arr, item) { + if (arr.indexOf) { + return arr.indexOf(item); + } + for (var i = 0; i < arr.length; i += 1) { + if (arr[i] === item) { + return i; + } + } + return -1; + }; + + //// exported async module functions //// + + //// nextTick implementation with browser-compatible fallback //// + async.nextTick = function (fn) { + if (typeof process === 'undefined' || !(process.nextTick)) { + setTimeout(fn, 0); + } + else { + process.nextTick(fn); + } + }; + + async.forEach = function (arr, iterator, callback) { + if (!arr.length) { + return callback(); + } + var completed = 0; + _forEach(arr, function (x) { + iterator(x, function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + completed += 1; + if (completed === arr.length) { + callback(); + } + } + }); + }); + }; + + async.forEachSeries = function (arr, iterator, callback) { + if (!arr.length) { + return callback(); + } + var completed = 0; + var iterate = function () { + iterator(arr[completed], function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + completed += 1; + if (completed === arr.length) { + callback(); + } + else { + iterate(); + } + } + }); + }; + iterate(); + }; + + + var doParallel = function (fn) { + return function () { + var args = Array.prototype.slice.call(arguments); + return fn.apply(null, [async.forEach].concat(args)); + }; + }; + var doSeries = function (fn) { + return function () { + var args = Array.prototype.slice.call(arguments); + return fn.apply(null, [async.forEachSeries].concat(args)); + }; + }; + + + var _asyncMap = function (eachfn, arr, iterator, callback) { + var results = []; + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + eachfn(arr, function (x, callback) { + iterator(x.value, function (err, v) { + results[x.index] = v; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + }; + async.map = doParallel(_asyncMap); + async.mapSeries = doSeries(_asyncMap); + + + // reduce only has a series version, as doing reduce in parallel won't + // work in many situations. + async.reduce = function (arr, memo, iterator, callback) { + async.forEachSeries(arr, function (x, callback) { + iterator(memo, x, function (err, v) { + memo = v; + callback(err); + }); + }, function (err) { + callback(err, memo); + }); + }; + // inject alias + async.inject = async.reduce; + // foldl alias + async.foldl = async.reduce; + + async.reduceRight = function (arr, memo, iterator, callback) { + var reversed = _map(arr, function (x) { + return x; + }).reverse(); + async.reduce(reversed, memo, iterator, callback); + }; + // foldr alias + async.foldr = async.reduceRight; + + var _filter = function (eachfn, arr, iterator, callback) { + var results = []; + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + eachfn(arr, function (x, callback) { + iterator(x.value, function (v) { + if (v) { + results.push(x); + } + callback(); + }); + }, function (err) { + callback(_map(results.sort(function (a, b) { + return a.index - b.index; + }), function (x) { + return x.value; + })); + }); + }; + async.filter = doParallel(_filter); + async.filterSeries = doSeries(_filter); + // select alias + async.select = async.filter; + async.selectSeries = async.filterSeries; + + var _reject = function (eachfn, arr, iterator, callback) { + var results = []; + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + eachfn(arr, function (x, callback) { + iterator(x.value, function (v) { + if (!v) { + results.push(x); + } + callback(); + }); + }, function (err) { + callback(_map(results.sort(function (a, b) { + return a.index - b.index; + }), function (x) { + return x.value; + })); + }); + }; + async.reject = doParallel(_reject); + async.rejectSeries = doSeries(_reject); + + var _detect = function (eachfn, arr, iterator, main_callback) { + eachfn(arr, function (x, callback) { + iterator(x, function (result) { + if (result) { + main_callback(x); + } + else { + callback(); + } + }); + }, function (err) { + main_callback(); + }); + }; + async.detect = doParallel(_detect); + async.detectSeries = doSeries(_detect); + + async.some = function (arr, iterator, main_callback) { + async.forEach(arr, function (x, callback) { + iterator(x, function (v) { + if (v) { + main_callback(true); + main_callback = function () {}; + } + callback(); + }); + }, function (err) { + main_callback(false); + }); + }; + // any alias + async.any = async.some; + + async.every = function (arr, iterator, main_callback) { + async.forEach(arr, function (x, callback) { + iterator(x, function (v) { + if (!v) { + main_callback(false); + main_callback = function () {}; + } + callback(); + }); + }, function (err) { + main_callback(true); + }); + }; + // all alias + async.all = async.every; + + async.sortBy = function (arr, iterator, callback) { + async.map(arr, function (x, callback) { + iterator(x, function (err, criteria) { + if (err) { + callback(err); + } + else { + callback(null, {value: x, criteria: criteria}); + } + }); + }, function (err, results) { + if (err) { + return callback(err); + } + else { + var fn = function (left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }; + callback(null, _map(results.sort(fn), function (x) { + return x.value; + })); + } + }); + }; + + async.auto = function (tasks, callback) { + callback = callback || function () {}; + var keys = _keys(tasks); + if (!keys.length) { + return callback(null); + } + + var completed = []; + + var listeners = []; + var addListener = function (fn) { + listeners.unshift(fn); + }; + var removeListener = function (fn) { + for (var i = 0; i < listeners.length; i += 1) { + if (listeners[i] === fn) { + listeners.splice(i, 1); + return; + } + } + }; + var taskComplete = function () { + _forEach(listeners, function (fn) { + fn(); + }); + }; + + addListener(function () { + if (completed.length === keys.length) { + callback(null); + } + }); + + _forEach(keys, function (k) { + var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k]; + var taskCallback = function (err) { + if (err) { + callback(err); + // stop subsequent errors hitting callback multiple times + callback = function () {}; + } + else { + completed.push(k); + taskComplete(); + } + }; + var requires = task.slice(0, Math.abs(task.length - 1)) || []; + var ready = function () { + return _reduce(requires, function (a, x) { + return (a && _indexOf(completed, x) !== -1); + }, true); + }; + if (ready()) { + task[task.length - 1](taskCallback); + } + else { + var listener = function () { + if (ready()) { + removeListener(listener); + task[task.length - 1](taskCallback); + } + }; + addListener(listener); + } + }); + }; + + async.waterfall = function (tasks, callback) { + if (!tasks.length) { + return callback(); + } + callback = callback || function () {}; + var wrapIterator = function (iterator) { + return function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + var args = Array.prototype.slice.call(arguments, 1); + var next = iterator.next(); + if (next) { + args.push(wrapIterator(next)); + } + else { + args.push(callback); + } + async.nextTick(function () { + iterator.apply(null, args); + }); + } + }; + }; + wrapIterator(async.iterator(tasks))(); + }; + + async.parallel = function (tasks, callback) { + callback = callback || function () {}; + if (tasks.constructor === Array) { + async.map(tasks, function (fn, callback) { + if (fn) { + fn(function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + callback.call(null, err, args || null); + }); + } + }, callback); + } + else { + var results = {}; + async.forEach(_keys(tasks), function (k, callback) { + tasks[k](function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + + async.series = function (tasks, callback) { + callback = callback || function () {}; + if (tasks.constructor === Array) { + async.mapSeries(tasks, function (fn, callback) { + if (fn) { + fn(function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + callback.call(null, err, args || null); + }); + } + }, callback); + } + else { + var results = {}; + async.forEachSeries(_keys(tasks), function (k, callback) { + tasks[k](function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + + async.iterator = function (tasks) { + var makeCallback = function (index) { + var fn = function () { + if (tasks.length) { + tasks[index].apply(null, arguments); + } + return fn.next(); + }; + fn.next = function () { + return (index < tasks.length - 1) ? makeCallback(index + 1): null; + }; + return fn; + }; + return makeCallback(0); + }; + + async.apply = function (fn) { + var args = Array.prototype.slice.call(arguments, 1); + return function () { + return fn.apply( + null, args.concat(Array.prototype.slice.call(arguments)) + ); + }; + }; + + var _concat = function (eachfn, arr, fn, callback) { + var r = []; + eachfn(arr, function (x, cb) { + fn(x, function (err, y) { + r = r.concat(y || []); + cb(err); + }); + }, function (err) { + callback(err, r); + }); + }; + async.concat = doParallel(_concat); + async.concatSeries = doSeries(_concat); + + async.whilst = function (test, iterator, callback) { + if (test()) { + iterator(function (err) { + if (err) { + return callback(err); + } + async.whilst(test, iterator, callback); + }); + } + else { + callback(); + } + }; + + async.until = function (test, iterator, callback) { + if (!test()) { + iterator(function (err) { + if (err) { + return callback(err); + } + async.until(test, iterator, callback); + }); + } + else { + callback(); + } + }; + + async.queue = function (worker, concurrency) { + var workers = 0; + var tasks = []; + var q = { + concurrency: concurrency, + push: function (data, callback) { + tasks.push({data: data, callback: callback}); + async.nextTick(q.process); + }, + process: function () { + if (workers < q.concurrency && tasks.length) { + var task = tasks.splice(0, 1)[0]; + workers += 1; + worker(task.data, function () { + workers -= 1; + if (task.callback) { + task.callback.apply(task, arguments); + } + q.process(); + }); + } + }, + length: function () { + return tasks.length; + } + }; + return q; + }; + + var _console_fn = function (name) { + return function (fn) { + var args = Array.prototype.slice.call(arguments, 1); + fn.apply(null, args.concat([function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (typeof console !== 'undefined') { + if (err) { + if (console.error) { + console.error(err); + } + } + else if (console[name]) { + _forEach(args, function (x) { + console[name](x); + }); + } + } + }])); + }; + }; + async.log = _console_fn('log'); + async.dir = _console_fn('dir'); + /*async.info = _console_fn('info'); + async.warn = _console_fn('warn'); + async.error = _console_fn('error');*/ + +}()); +(function(exports){ +/** + * This file is based on the node.js assert module, but with some small + * changes for browser-compatibility + * THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! + */ + + +/** + * Added for browser compatibility + */ + +var _keys = function(obj){ + if(Object.keys) return Object.keys(obj); + var keys = []; + for(var k in obj){ + if(obj.hasOwnProperty(k)) keys.push(k); + } + return keys; +}; + + + +// http://wiki.commonjs.org/wiki/Unit_Testing/1.0 +// +// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! +// +// Originally from narwhal.js (http://narwhaljs.org) +// Copyright (c) 2009 Thomas Robinson <280north.com> +// +// 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 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. + + +var pSlice = Array.prototype.slice; + +// 1. The assert module provides functions that throw +// AssertionError's when particular conditions are not met. The +// assert module must conform to the following interface. + +var assert = exports; + +// 2. The AssertionError is defined in assert. +// new assert.AssertionError({message: message, actual: actual, expected: expected}) + +assert.AssertionError = function AssertionError (options) { + this.name = "AssertionError"; + this.message = options.message; + this.actual = options.actual; + this.expected = options.expected; + this.operator = options.operator; + var stackStartFunction = options.stackStartFunction || fail; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, stackStartFunction); + } +}; +// code from util.inherits in node +assert.AssertionError.super_ = Error; + + +// EDITED FOR BROWSER COMPATIBILITY: replaced Object.create call +// TODO: test what effect this may have +var ctor = function () { this.constructor = assert.AssertionError; }; +ctor.prototype = Error.prototype; +assert.AssertionError.prototype = new ctor(); + + +assert.AssertionError.prototype.toString = function() { + if (this.message) { + return [this.name+":", this.message].join(' '); + } else { + return [ this.name+":" + , JSON.stringify(this.expected ) + , this.operator + , JSON.stringify(this.actual) + ].join(" "); + } +}; + +// assert.AssertionError instanceof Error + +assert.AssertionError.__proto__ = Error.prototype; + +// At present only the three keys mentioned above are used and +// understood by the spec. Implementations or sub modules can pass +// other keys to the AssertionError's constructor - they will be +// ignored. + +// 3. All of the following functions must throw an AssertionError +// when a corresponding condition is not met, with a message that +// may be undefined if not provided. All assertion methods provide +// both the actual and expected values to the assertion error for +// display purposes. + +function fail(actual, expected, message, operator, stackStartFunction) { + throw new assert.AssertionError({ + message: message, + actual: actual, + expected: expected, + operator: operator, + stackStartFunction: stackStartFunction + }); +} + +// EXTENSION! allows for well behaved errors defined elsewhere. +assert.fail = fail; + +// 4. Pure assertion tests whether a value is truthy, as determined +// by !!guard. +// assert.ok(guard, message_opt); +// This statement is equivalent to assert.equal(true, guard, +// message_opt);. To test strictly for the value true, use +// assert.strictEqual(true, guard, message_opt);. + +assert.ok = function ok(value, message) { + if (!!!value) fail(value, true, message, "==", assert.ok); +}; + +// 5. The equality assertion tests shallow, coercive equality with +// ==. +// assert.equal(actual, expected, message_opt); + +assert.equal = function equal(actual, expected, message) { + if (actual != expected) fail(actual, expected, message, "==", assert.equal); +}; + +// 6. The non-equality assertion tests for whether two objects are not equal +// with != assert.notEqual(actual, expected, message_opt); + +assert.notEqual = function notEqual(actual, expected, message) { + if (actual == expected) { + fail(actual, expected, message, "!=", assert.notEqual); + } +}; + +// 7. The equivalence assertion tests a deep equality relation. +// assert.deepEqual(actual, expected, message_opt); + +assert.deepEqual = function deepEqual(actual, expected, message) { + if (!_deepEqual(actual, expected)) { + fail(actual, expected, message, "deepEqual", assert.deepEqual); + } +}; + +function _deepEqual(actual, expected) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (actual instanceof Date && expected instanceof Date) { + return actual.getTime() === expected.getTime(); + + // 7.3. Other pairs that do not both pass typeof value == "object", + // equivalence is determined by ==. + } else if (typeof actual != 'object' && typeof expected != 'object') { + return actual == expected; + + // 7.4. For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical "prototype" property. Note: this + // accounts for both named and indexed properties on Arrays. + } else { + return objEquiv(actual, expected); + } +} + +function isUndefinedOrNull (value) { + return value === null || value === undefined; +} + +function isArguments (object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; +} + +function objEquiv (a, b) { + if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) + return false; + // an identical "prototype" property. + if (a.prototype !== b.prototype) return false; + //~~~I've managed to break Object.keys through screwy arguments passing. + // Converting to array solves the problem. + if (isArguments(a)) { + if (!isArguments(b)) { + return false; + } + a = pSlice.call(a); + b = pSlice.call(b); + return _deepEqual(a, b); + } + try{ + var ka = _keys(a), + kb = _keys(b), + key, i; + } catch (e) {//happens when one is a string literal and the other isn't + return false; + } + // having the same number of owned properties (keys incorporates hasOwnProperty) + if (ka.length != kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] != kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!_deepEqual(a[key], b[key] )) + return false; + } + return true; +} + +// 8. The non-equivalence assertion tests for any deep inequality. +// assert.notDeepEqual(actual, expected, message_opt); + +assert.notDeepEqual = function notDeepEqual(actual, expected, message) { + if (_deepEqual(actual, expected)) { + fail(actual, expected, message, "notDeepEqual", assert.notDeepEqual); + } +}; + +// 9. The strict equality assertion tests strict equality, as determined by ===. +// assert.strictEqual(actual, expected, message_opt); + +assert.strictEqual = function strictEqual(actual, expected, message) { + if (actual !== expected) { + fail(actual, expected, message, "===", assert.strictEqual); + } +}; + +// 10. The strict non-equality assertion tests for strict inequality, as determined by !==. +// assert.notStrictEqual(actual, expected, message_opt); + +assert.notStrictEqual = function notStrictEqual(actual, expected, message) { + if (actual === expected) { + fail(actual, expected, message, "!==", assert.notStrictEqual); + } +}; + +function _throws (shouldThrow, block, err, message) { + var exception = null, + threw = false, + typematters = true; + + message = message || ""; + + //handle optional arguments + if (arguments.length == 3) { + if (typeof(err) == "string") { + message = err; + typematters = false; + } + } else if (arguments.length == 2) { + typematters = false; + } + + try { + block(); + } catch (e) { + threw = true; + exception = e; + } + + if (shouldThrow && !threw) { + fail( "Missing expected exception" + + (err && err.name ? " ("+err.name+")." : '.') + + (message ? " " + message : "") + ); + } + if (!shouldThrow && threw && typematters && exception instanceof err) { + fail( "Got unwanted exception" + + (err && err.name ? " ("+err.name+")." : '.') + + (message ? " " + message : "") + ); + } + if ((shouldThrow && threw && typematters && !(exception instanceof err)) || + (!shouldThrow && threw)) { + throw exception; + } +}; + +// 11. Expected to throw an error: +// assert.throws(block, Error_opt, message_opt); + +assert.throws = function(block, /*optional*/error, /*optional*/message) { + _throws.apply(this, [true].concat(pSlice.call(arguments))); +}; + +// EXTENSION! This is annoying to write outside this module. +assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { + _throws.apply(this, [false].concat(pSlice.call(arguments))); +}; + +assert.ifError = function (err) { if (err) {throw err;}}; +})(assert); +(function(exports){ +/*! + * Nodeunit + * Copyright (c) 2010 Caolan McMahon + * MIT Licensed + * + * THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! + * Only code on that line will be removed, its mostly to avoid requiring code + * that is node specific + */ + +/** + * Module dependencies + */ + + + +/** + * Creates assertion objects representing the result of an assert call. + * Accepts an object or AssertionError as its argument. + * + * @param {object} obj + * @api public + */ + +exports.assertion = function (obj) { + return { + method: obj.method || '', + message: obj.message || (obj.error && obj.error.message) || '', + error: obj.error, + passed: function () { + return !this.error; + }, + failed: function () { + return Boolean(this.error); + } + }; +}; + +/** + * Creates an assertion list object representing a group of assertions. + * Accepts an array of assertion objects. + * + * @param {Array} arr + * @param {Number} duration + * @api public + */ + +exports.assertionList = function (arr, duration) { + var that = arr || []; + that.failures = function () { + var failures = 0; + for (var i=0; i(' + + '' + assertions.failures() + ', ' + + '' + assertions.passes() + ', ' + + assertions.length + + ')'; + test.className = assertions.failures() ? 'fail': 'pass'; + test.appendChild(strong); + + var aList = document.createElement('ol'); + aList.style.display = 'none'; + test.onclick = function () { + var d = aList.style.display; + aList.style.display = (d == 'none') ? 'block': 'none'; + }; + for (var i=0; i' + (a.error.stack || a.error) + ''; + li.className = 'fail'; + } + else { + li.innerHTML = a.message || a.method || 'no message'; + li.className = 'pass'; + } + aList.appendChild(li); + } + test.appendChild(aList); + tests.appendChild(test); + }, + done: function (assertions) { + var end = new Date().getTime(); + var duration = end - start; + + var failures = assertions.failures(); + banner.className = failures ? 'fail': 'pass'; + + result.innerHTML = 'Tests completed in ' + duration + + ' milliseconds.
' + + assertions.passes() + ' assertions of ' + + '' + assertions.length + ' passed, ' + + assertions.failures() + ' failed.'; + } + }); +}; +})(reporter); +nodeunit = core; +nodeunit.assert = assert; +nodeunit.reporter = reporter; +nodeunit.run = reporter.run; +return nodeunit; })(); diff --git a/node_modules/async/dist/async.min.js b/node_modules/async/dist/async.min.js new file mode 100644 index 000000000..e4c898b12 --- /dev/null +++ b/node_modules/async/dist/async.min.js @@ -0,0 +1 @@ +/*global setTimeout: false, console: false */(function(){var a={},b=this,c=b.async;typeof module!="undefined"&&module.exports?module.exports=a:b.async=a,a.noConflict=function(){return b.async=c,a};var d=function(a,b){if(a.forEach)return a.forEach(b);for(var c=0;cd?1:0};d(null,e(b.sort(c),function(a){return a.value}))})},a.auto=function(a,b){b=b||function(){};var c=g(a);if(!c.length)return b(null);var e={},h=[],i=function(a){h.unshift(a)},j=function(a){for(var b=0;b b ? 1 : 0; + }; + callback(null, _map(results.sort(fn), function (x) { + return x.value; + })); + } + }); + }; + + async.auto = function (tasks, callback) { + callback = callback || function () {}; + var keys = _keys(tasks); + if (!keys.length) { + return callback(null); + } + + var results = {}; + + var listeners = []; + var addListener = function (fn) { + listeners.unshift(fn); + }; + var removeListener = function (fn) { + for (var i = 0; i < listeners.length; i += 1) { + if (listeners[i] === fn) { + listeners.splice(i, 1); + return; + } + } + }; + var taskComplete = function () { + _forEach(listeners, function (fn) { + fn(); + }); + }; + + addListener(function () { + if (_keys(results).length === keys.length) { + callback(null, results); + } + }); + + _forEach(keys, function (k) { + var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k]; + var taskCallback = function (err) { + if (err) { + callback(err); + // stop subsequent errors hitting callback multiple times + callback = function () {}; + } + else { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + taskComplete(); + } + }; + var requires = task.slice(0, Math.abs(task.length - 1)) || []; + var ready = function () { + return _reduce(requires, function (a, x) { + return (a && results.hasOwnProperty(x)); + }, true); + }; + if (ready()) { + task[task.length - 1](taskCallback, results); + } + else { + var listener = function () { + if (ready()) { + removeListener(listener); + task[task.length - 1](taskCallback, results); + } + }; + addListener(listener); + } + }); + }; + + async.waterfall = function (tasks, callback) { + if (!tasks.length) { + return callback(); + } + callback = callback || function () {}; + var wrapIterator = function (iterator) { + return function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + var args = Array.prototype.slice.call(arguments, 1); + var next = iterator.next(); + if (next) { + args.push(wrapIterator(next)); + } + else { + args.push(callback); + } + async.nextTick(function () { + iterator.apply(null, args); + }); + } + }; + }; + wrapIterator(async.iterator(tasks))(); + }; + + async.parallel = function (tasks, callback) { + callback = callback || function () {}; + if (tasks.constructor === Array) { + async.map(tasks, function (fn, callback) { + if (fn) { + fn(function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + callback.call(null, err, args); + }); + } + }, callback); + } + else { + var results = {}; + async.forEach(_keys(tasks), function (k, callback) { + tasks[k](function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + + async.series = function (tasks, callback) { + callback = callback || function () {}; + if (tasks.constructor === Array) { + async.mapSeries(tasks, function (fn, callback) { + if (fn) { + fn(function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + callback.call(null, err, args); + }); + } + }, callback); + } + else { + var results = {}; + async.forEachSeries(_keys(tasks), function (k, callback) { + tasks[k](function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + + async.iterator = function (tasks) { + var makeCallback = function (index) { + var fn = function () { + if (tasks.length) { + tasks[index].apply(null, arguments); + } + return fn.next(); + }; + fn.next = function () { + return (index < tasks.length - 1) ? makeCallback(index + 1): null; + }; + return fn; + }; + return makeCallback(0); + }; + + async.apply = function (fn) { + var args = Array.prototype.slice.call(arguments, 1); + return function () { + return fn.apply( + null, args.concat(Array.prototype.slice.call(arguments)) + ); + }; + }; + + var _concat = function (eachfn, arr, fn, callback) { + var r = []; + eachfn(arr, function (x, cb) { + fn(x, function (err, y) { + r = r.concat(y || []); + cb(err); + }); + }, function (err) { + callback(err, r); + }); + }; + async.concat = doParallel(_concat); + async.concatSeries = doSeries(_concat); + + async.whilst = function (test, iterator, callback) { + if (test()) { + iterator(function (err) { + if (err) { + return callback(err); + } + async.whilst(test, iterator, callback); + }); + } + else { + callback(); + } + }; + + async.until = function (test, iterator, callback) { + if (!test()) { + iterator(function (err) { + if (err) { + return callback(err); + } + async.until(test, iterator, callback); + }); + } + else { + callback(); + } + }; + + async.queue = function (worker, concurrency) { + var workers = 0; + var q = { + tasks: [], + concurrency: concurrency, + saturated: null, + empty: null, + drain: null, + push: function (data, callback) { + q.tasks.push({data: data, callback: callback}); + if(q.saturated && q.tasks.length == concurrency) q.saturated(); + async.nextTick(q.process); + }, + process: function () { + if (workers < q.concurrency && q.tasks.length) { + var task = q.tasks.shift(); + if(q.empty && q.tasks.length == 0) q.empty(); + workers += 1; + worker(task.data, function () { + workers -= 1; + if (task.callback) { + task.callback.apply(task, arguments); + } + if(q.drain && q.tasks.length + workers == 0) q.drain(); + q.process(); + }); + } + }, + length: function () { + return q.tasks.length; + }, + running: function () { + return workers; + } + }; + return q; + }; + + var _console_fn = function (name) { + return function (fn) { + var args = Array.prototype.slice.call(arguments, 1); + fn.apply(null, args.concat([function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (typeof console !== 'undefined') { + if (err) { + if (console.error) { + console.error(err); + } + } + else if (console[name]) { + _forEach(args, function (x) { + console[name](x); + }); + } + } + }])); + }; + }; + async.log = _console_fn('log'); + async.dir = _console_fn('dir'); + /*async.info = _console_fn('info'); + async.warn = _console_fn('warn'); + async.error = _console_fn('error');*/ + + async.memoize = function (fn, hasher) { + var memo = {}; + var queues = {}; + hasher = hasher || function (x) { + return x; + }; + var memoized = function () { + var args = Array.prototype.slice.call(arguments); + var callback = args.pop(); + var key = hasher.apply(null, args); + if (key in memo) { + callback.apply(null, memo[key]); + } + else if (key in queues) { + queues[key].push(callback); + } + else { + queues[key] = [callback]; + fn.apply(null, args.concat([function () { + memo[key] = arguments; + var q = queues[key]; + delete queues[key]; + for (var i = 0, l = q.length; i < l; i++) { + q[i].apply(null, arguments); + } + }])); + } + }; + memoized.unmemoized = fn; + return memoized; + }; + + async.unmemoize = function (fn) { + return function () { + return (fn.unmemoized || fn).apply(null, arguments); + } + }; + +}()); diff --git a/node_modules/async/nodelint.cfg b/node_modules/async/nodelint.cfg new file mode 100644 index 000000000..457a967e0 --- /dev/null +++ b/node_modules/async/nodelint.cfg @@ -0,0 +1,4 @@ +var options = { + indent: 4, + onevar: false +}; diff --git a/node_modules/async/package.json b/node_modules/async/package.json new file mode 100644 index 000000000..6198943b7 --- /dev/null +++ b/node_modules/async/package.json @@ -0,0 +1,16 @@ +{ "name": "async" +, "description": "Higher-order functions and common patterns for asynchronous code" +, "main": "./index" +, "author": "Caolan McMahon" +, "version": "0.1.15" +, "repository" : + { "type" : "git" + , "url" : "http://github.com/caolan/async.git" + } +, "bugs" : { "url" : "http://github.com/caolan/async/issues" } +, "licenses" : + [ { "type" : "MIT" + , "url" : "http://github.com/caolan/async/raw/master/LICENSE" + } + ] +} diff --git a/node_modules/async/test/test-async.js b/node_modules/async/test/test-async.js new file mode 100644 index 000000000..d3eeddcb5 --- /dev/null +++ b/node_modules/async/test/test-async.js @@ -0,0 +1,1577 @@ +var async = require('../lib/async'); + + +exports['auto'] = function(test){ + var callOrder = []; + var testdata = [{test: 'test'}]; + async.auto({ + task1: ['task2', function(callback){ + setTimeout(function(){ + callOrder.push('task1'); + callback(); + }, 25); + }], + task2: function(callback){ + setTimeout(function(){ + callOrder.push('task2'); + callback(); + }, 50); + }, + task3: ['task2', function(callback){ + callOrder.push('task3'); + callback(); + }], + task4: ['task1', 'task2', function(callback){ + callOrder.push('task4'); + callback(); + }] + }, + function(err){ + test.same(callOrder, ['task2','task3','task1','task4']); + test.done(); + }); +}; + +exports['auto results'] = function(test){ + var callOrder = []; + async.auto({ + task1: ['task2', function(callback, results){ + test.same(results.task2, 'task2'); + setTimeout(function(){ + callOrder.push('task1'); + callback(null, 'task1a', 'task1b'); + }, 25); + }], + task2: function(callback){ + setTimeout(function(){ + callOrder.push('task2'); + callback(null, 'task2'); + }, 50); + }, + task3: ['task2', function(callback, results){ + test.same(results.task2, 'task2'); + callOrder.push('task3'); + callback(null); + }], + task4: ['task1', 'task2', function(callback, results){ + test.same(results.task1, ['task1a','task1b']); + test.same(results.task2, 'task2'); + callOrder.push('task4'); + callback(null, 'task4'); + }] + }, + function(err, results){ + test.same(callOrder, ['task2','task3','task1','task4']); + test.same(results, {task1: ['task1a','task1b'], task2: 'task2', task3: undefined, task4: 'task4'}); + test.done(); + }); +}; + + +exports['auto empty object'] = function(test){ + async.auto({}, function(err){ + test.done(); + }); +}; + +exports['auto error'] = function(test){ + test.expect(1); + async.auto({ + task1: function(callback){ + callback('testerror'); + }, + task2: ['task1', function(callback){ + test.ok(false, 'task2 should not be called'); + callback(); + }], + task3: function(callback){ + callback('testerror2'); + } + }, + function(err){ + test.equals(err, 'testerror'); + }); + setTimeout(test.done, 100); +}; + +exports['auto no callback'] = function(test){ + async.auto({ + task1: function(callback){callback();}, + task2: ['task1', function(callback){callback(); test.done();}] + }); +}; + +exports['waterfall'] = function(test){ + test.expect(6); + var call_order = []; + async.waterfall([ + function(callback){ + call_order.push('fn1'); + setTimeout(function(){callback(null, 'one', 'two');}, 0); + }, + function(arg1, arg2, callback){ + call_order.push('fn2'); + test.equals(arg1, 'one'); + test.equals(arg2, 'two'); + setTimeout(function(){callback(null, arg1, arg2, 'three');}, 25); + }, + function(arg1, arg2, arg3, callback){ + call_order.push('fn3'); + test.equals(arg1, 'one'); + test.equals(arg2, 'two'); + test.equals(arg3, 'three'); + callback(null, 'four'); + }, + function(arg4, callback){ + call_order.push('fn4'); + test.same(call_order, ['fn1','fn2','fn3','fn4']); + callback(null, 'test'); + } + ], function(err){ + test.done(); + }); +}; + +exports['waterfall empty array'] = function(test){ + async.waterfall([], function(err){ + test.done(); + }); +}; + +exports['waterfall no callback'] = function(test){ + async.waterfall([ + function(callback){callback();}, + function(callback){callback(); test.done();} + ]); +}; + +exports['waterfall async'] = function(test){ + var call_order = []; + async.waterfall([ + function(callback){ + call_order.push(1); + callback(); + call_order.push(2); + }, + function(callback){ + call_order.push(3); + callback(); + }, + function(){ + test.same(call_order, [1,2,3]); + test.done(); + } + ]); +}; + +exports['waterfall error'] = function(test){ + test.expect(1); + async.waterfall([ + function(callback){ + callback('error'); + }, + function(callback){ + test.ok(false, 'next function should not be called'); + callback(); + } + ], function(err){ + test.equals(err, 'error'); + }); + setTimeout(test.done, 50); +}; + +exports['waterfall multiple callback calls'] = function(test){ + var call_order = []; + var arr = [ + function(callback){ + call_order.push(1); + // call the callback twice. this should call function 2 twice + callback(null, 'one', 'two'); + callback(null, 'one', 'two'); + }, + function(arg1, arg2, callback){ + call_order.push(2); + callback(null, arg1, arg2, 'three'); + }, + function(arg1, arg2, arg3, callback){ + call_order.push(3); + callback(null, 'four'); + }, + function(arg4){ + call_order.push(4); + arr[3] = function(){ + call_order.push(4); + test.same(call_order, [1,2,2,3,3,4,4]); + test.done(); + }; + } + ]; + async.waterfall(arr); +}; + + +exports['parallel'] = function(test){ + var call_order = []; + async.parallel([ + function(callback){ + setTimeout(function(){ + call_order.push(1); + callback(null, 1); + }, 50); + }, + function(callback){ + setTimeout(function(){ + call_order.push(2); + callback(null, 2); + }, 100); + }, + function(callback){ + setTimeout(function(){ + call_order.push(3); + callback(null, 3,3); + }, 25); + } + ], + function(err, results){ + test.equals(err, null); + test.same(call_order, [3,1,2]); + test.same(results, [1,2,[3,3]]); + test.done(); + }); +}; + +exports['parallel empty array'] = function(test){ + async.parallel([], function(err, results){ + test.equals(err, null); + test.same(results, []); + test.done(); + }); +}; + +exports['parallel error'] = function(test){ + async.parallel([ + function(callback){ + callback('error', 1); + }, + function(callback){ + callback('error2', 2); + } + ], + function(err, results){ + test.equals(err, 'error'); + }); + setTimeout(test.done, 100); +}; + +exports['parallel no callback'] = function(test){ + async.parallel([ + function(callback){callback();}, + function(callback){callback(); test.done();}, + ]); +}; + +exports['parallel object'] = function(test){ + var call_order = []; + async.parallel({ + one: function(callback){ + setTimeout(function(){ + call_order.push(1); + callback(null, 1); + }, 25); + }, + two: function(callback){ + setTimeout(function(){ + call_order.push(2); + callback(null, 2); + }, 50); + }, + three: function(callback){ + setTimeout(function(){ + call_order.push(3); + callback(null, 3,3); + }, 15); + } + }, + function(err, results){ + test.equals(err, null); + test.same(call_order, [3,1,2]); + test.same(results, { + one: 1, + two: 2, + three: [3,3] + }); + test.done(); + }); +}; + +exports['series'] = function(test){ + var call_order = []; + async.series([ + function(callback){ + setTimeout(function(){ + call_order.push(1); + callback(null, 1); + }, 25); + }, + function(callback){ + setTimeout(function(){ + call_order.push(2); + callback(null, 2); + }, 50); + }, + function(callback){ + setTimeout(function(){ + call_order.push(3); + callback(null, 3,3); + }, 15); + } + ], + function(err, results){ + test.equals(err, null); + test.same(results, [1,2,[3,3]]); + test.same(call_order, [1,2,3]); + test.done(); + }); +}; + +exports['series empty array'] = function(test){ + async.series([], function(err, results){ + test.equals(err, null); + test.same(results, []); + test.done(); + }); +}; + +exports['series error'] = function(test){ + test.expect(1); + async.series([ + function(callback){ + callback('error', 1); + }, + function(callback){ + test.ok(false, 'should not be called'); + callback('error2', 2); + } + ], + function(err, results){ + test.equals(err, 'error'); + }); + setTimeout(test.done, 100); +}; + +exports['series no callback'] = function(test){ + async.series([ + function(callback){callback();}, + function(callback){callback(); test.done();}, + ]); +}; + +exports['series object'] = function(test){ + var call_order = []; + async.series({ + one: function(callback){ + setTimeout(function(){ + call_order.push(1); + callback(null, 1); + }, 25); + }, + two: function(callback){ + setTimeout(function(){ + call_order.push(2); + callback(null, 2); + }, 50); + }, + three: function(callback){ + setTimeout(function(){ + call_order.push(3); + callback(null, 3,3); + }, 15); + } + }, + function(err, results){ + test.equals(err, null); + test.same(results, { + one: 1, + two: 2, + three: [3,3] + }); + test.same(call_order, [1,2,3]); + test.done(); + }); +}; + +exports['iterator'] = function(test){ + var call_order = []; + var iterator = async.iterator([ + function(){call_order.push(1);}, + function(arg1){ + test.equals(arg1, 'arg1'); + call_order.push(2); + }, + function(arg1, arg2){ + test.equals(arg1, 'arg1'); + test.equals(arg2, 'arg2'); + call_order.push(3); + } + ]); + iterator(); + test.same(call_order, [1]); + var iterator2 = iterator(); + test.same(call_order, [1,1]); + var iterator3 = iterator2('arg1'); + test.same(call_order, [1,1,2]); + var iterator4 = iterator3('arg1', 'arg2'); + test.same(call_order, [1,1,2,3]); + test.equals(iterator4, undefined); + test.done(); +}; + +exports['iterator empty array'] = function(test){ + var iterator = async.iterator([]); + test.equals(iterator(), undefined); + test.equals(iterator.next(), undefined); + test.done(); +}; + +exports['iterator.next'] = function(test){ + var call_order = []; + var iterator = async.iterator([ + function(){call_order.push(1);}, + function(arg1){ + test.equals(arg1, 'arg1'); + call_order.push(2); + }, + function(arg1, arg2){ + test.equals(arg1, 'arg1'); + test.equals(arg2, 'arg2'); + call_order.push(3); + } + ]); + var fn = iterator.next(); + var iterator2 = fn('arg1'); + test.same(call_order, [2]); + iterator2('arg1','arg2'); + test.same(call_order, [2,3]); + test.equals(iterator2.next(), undefined); + test.done(); +}; + +exports['forEach'] = function(test){ + var args = []; + async.forEach([1,3,2], function(x, callback){ + setTimeout(function(){ + args.push(x); + callback(); + }, x*25); + }, function(err){ + test.same(args, [1,2,3]); + test.done(); + }); +}; + +exports['forEach empty array'] = function(test){ + test.expect(1); + async.forEach([], function(x, callback){ + test.ok(false, 'iterator should not be called'); + callback(); + }, function(err){ + test.ok(true, 'should call callback'); + }); + setTimeout(test.done, 25); +}; + +exports['forEach error'] = function(test){ + test.expect(1); + async.forEach([1,2,3], function(x, callback){ + callback('error'); + }, function(err){ + test.equals(err, 'error'); + }); + setTimeout(test.done, 50); +}; + +exports['forEachSeries'] = function(test){ + var args = []; + async.forEachSeries([1,3,2], function(x, callback){ + setTimeout(function(){ + args.push(x); + callback(); + }, x*25); + }, function(err){ + test.same(args, [1,3,2]); + test.done(); + }); +}; + +exports['forEachSeries empty array'] = function(test){ + test.expect(1); + async.forEachSeries([], function(x, callback){ + test.ok(false, 'iterator should not be called'); + callback(); + }, function(err){ + test.ok(true, 'should call callback'); + }); + setTimeout(test.done, 25); +}; + +exports['forEachSeries error'] = function(test){ + test.expect(2); + var call_order = []; + async.forEachSeries([1,2,3], function(x, callback){ + call_order.push(x); + callback('error'); + }, function(err){ + test.same(call_order, [1]); + test.equals(err, 'error'); + }); + setTimeout(test.done, 50); +}; + +exports['forEachLimit'] = function(test){ + var args = []; + var arr = [0,1,2,3,4,5,6,7,8,9]; + async.forEachLimit(arr, 2, function(x,callback){ + setTimeout(function(){ + args.push(x); + callback(); + }, x*5); + }, function(err){ + test.same(args, arr); + test.done(); + }); +}; + +exports['forEachLimit empty array'] = function(test){ + test.expect(1); + async.forEachLimit([], 2, function(x, callback){ + test.ok(false, 'iterator should not be called'); + callback(); + }, function(err){ + test.ok(true, 'should call callback'); + }); + setTimeout(test.done, 25); +}; + +exports['forEachLimit limit exceeds size'] = function(test){ + var args = []; + var arr = [0,1,2,3,4,5,6,7,8,9]; + async.forEachLimit(arr, 20, function(x,callback){ + setTimeout(function(){ + args.push(x); + callback(); + }, x*5); + }, function(err){ + test.same(args, arr); + test.done(); + }); +}; + +exports['forEachLimit limit equal size'] = function(test){ + var args = []; + var arr = [0,1,2,3,4,5,6,7,8,9]; + async.forEachLimit(arr, 10, function(x,callback){ + setTimeout(function(){ + args.push(x); + callback(); + }, x*5); + }, function(err){ + test.same(args, arr); + test.done(); + }); +}; + +exports['forEachLimit zero limit'] = function(test){ + test.expect(1); + async.forEachLimit([0,1,2,3,4,5], 0, function(x, callback){ + test.ok(false, 'iterator should not be called'); + callback(); + }, function(err){ + test.ok(true, 'should call callback'); + }); + setTimeout(test.done, 25); +}; + +exports['forEachLimit error'] = function(test){ + test.expect(2); + var arr = [0,1,2,3,4,5,6,7,8,9]; + var call_order = []; + + async.forEachLimit(arr, 3, function(x, callback){ + call_order.push(x); + if (x === 2) { + callback('error'); + } + }, function(err){ + test.same(call_order, [0,1,2]); + test.equals(err, 'error'); + }); + setTimeout(test.done, 25); +}; + +exports['map'] = function(test){ + var call_order = []; + async.map([1,3,2], function(x, callback){ + setTimeout(function(){ + call_order.push(x); + callback(null, x*2); + }, x*25); + }, function(err, results){ + test.same(call_order, [1,2,3]); + test.same(results, [2,6,4]); + test.done(); + }); +}; + +exports['map original untouched'] = function(test){ + var a = [1,2,3]; + async.map(a, function(x, callback){ + callback(null, x*2); + }, function(err, results){ + test.same(results, [2,4,6]); + test.same(a, [1,2,3]); + test.done(); + }); +}; + +exports['map error'] = function(test){ + test.expect(1); + async.map([1,2,3], function(x, callback){ + callback('error'); + }, function(err, results){ + test.equals(err, 'error'); + }); + setTimeout(test.done, 50); +}; + +exports['mapSeries'] = function(test){ + var call_order = []; + async.mapSeries([1,3,2], function(x, callback){ + setTimeout(function(){ + call_order.push(x); + callback(null, x*2); + }, x*25); + }, function(err, results){ + test.same(call_order, [1,3,2]); + test.same(results, [2,6,4]); + test.done(); + }); +}; + +exports['mapSeries error'] = function(test){ + test.expect(1); + async.mapSeries([1,2,3], function(x, callback){ + callback('error'); + }, function(err, results){ + test.equals(err, 'error'); + }); + setTimeout(test.done, 50); +}; + +exports['reduce'] = function(test){ + var call_order = []; + async.reduce([1,2,3], 0, function(a, x, callback){ + call_order.push(x); + callback(null, a + x); + }, function(err, result){ + test.equals(result, 6); + test.same(call_order, [1,2,3]); + test.done(); + }); +}; + +exports['reduce async with non-reference memo'] = function(test){ + async.reduce([1,3,2], 0, function(a, x, callback){ + setTimeout(function(){callback(null, a + x)}, Math.random()*100); + }, function(err, result){ + test.equals(result, 6); + test.done(); + }); +}; + +exports['reduce error'] = function(test){ + test.expect(1); + async.reduce([1,2,3], 0, function(a, x, callback){ + callback('error'); + }, function(err, result){ + test.equals(err, 'error'); + }); + setTimeout(test.done, 50); +}; + +exports['inject alias'] = function(test){ + test.equals(async.inject, async.reduce); + test.done(); +}; + +exports['foldl alias'] = function(test){ + test.equals(async.foldl, async.reduce); + test.done(); +}; + +exports['reduceRight'] = function(test){ + var call_order = []; + var a = [1,2,3]; + async.reduceRight(a, 0, function(a, x, callback){ + call_order.push(x); + callback(null, a + x); + }, function(err, result){ + test.equals(result, 6); + test.same(call_order, [3,2,1]); + test.same(a, [1,2,3]); + test.done(); + }); +}; + +exports['foldr alias'] = function(test){ + test.equals(async.foldr, async.reduceRight); + test.done(); +}; + +exports['filter'] = function(test){ + async.filter([3,1,2], function(x, callback){ + setTimeout(function(){callback(x % 2);}, x*25); + }, function(results){ + test.same(results, [3,1]); + test.done(); + }); +}; + +exports['filter original untouched'] = function(test){ + var a = [3,1,2]; + async.filter(a, function(x, callback){ + callback(x % 2); + }, function(results){ + test.same(results, [3,1]); + test.same(a, [3,1,2]); + test.done(); + }); +}; + +exports['filterSeries'] = function(test){ + async.filterSeries([3,1,2], function(x, callback){ + setTimeout(function(){callback(x % 2);}, x*25); + }, function(results){ + test.same(results, [3,1]); + test.done(); + }); +}; + +exports['select alias'] = function(test){ + test.equals(async.select, async.filter); + test.done(); +}; + +exports['selectSeries alias'] = function(test){ + test.equals(async.selectSeries, async.filterSeries); + test.done(); +}; + +exports['reject'] = function(test){ + async.reject([3,1,2], function(x, callback){ + setTimeout(function(){callback(x % 2);}, x*25); + }, function(results){ + test.same(results, [2]); + test.done(); + }); +}; + +exports['reject original untouched'] = function(test){ + var a = [3,1,2]; + async.reject(a, function(x, callback){ + callback(x % 2); + }, function(results){ + test.same(results, [2]); + test.same(a, [3,1,2]); + test.done(); + }); +}; + +exports['rejectSeries'] = function(test){ + async.rejectSeries([3,1,2], function(x, callback){ + setTimeout(function(){callback(x % 2);}, x*25); + }, function(results){ + test.same(results, [2]); + test.done(); + }); +}; + +exports['some true'] = function(test){ + async.some([3,1,2], function(x, callback){ + setTimeout(function(){callback(x === 1);}, 0); + }, function(result){ + test.equals(result, true); + test.done(); + }); +}; + +exports['some false'] = function(test){ + async.some([3,1,2], function(x, callback){ + setTimeout(function(){callback(x === 10);}, 0); + }, function(result){ + test.equals(result, false); + test.done(); + }); +}; + +exports['some early return'] = function(test){ + var call_order = []; + async.some([1,2,3], function(x, callback){ + setTimeout(function(){ + call_order.push(x); + callback(x === 1); + }, x*25); + }, function(result){ + call_order.push('callback'); + }); + setTimeout(function(){ + test.same(call_order, [1,'callback',2,3]); + test.done(); + }, 100); +}; + +exports['any alias'] = function(test){ + test.equals(async.any, async.some); + test.done(); +}; + +exports['every true'] = function(test){ + async.every([1,2,3], function(x, callback){ + setTimeout(function(){callback(true);}, 0); + }, function(result){ + test.equals(result, true); + test.done(); + }); +}; + +exports['every false'] = function(test){ + async.every([1,2,3], function(x, callback){ + setTimeout(function(){callback(x % 2);}, 0); + }, function(result){ + test.equals(result, false); + test.done(); + }); +}; + +exports['every early return'] = function(test){ + var call_order = []; + async.every([1,2,3], function(x, callback){ + setTimeout(function(){ + call_order.push(x); + callback(x === 1); + }, x*25); + }, function(result){ + call_order.push('callback'); + }); + setTimeout(function(){ + test.same(call_order, [1,2,'callback',3]); + test.done(); + }, 100); +}; + +exports['all alias'] = function(test){ + test.equals(async.all, async.every); + test.done(); +}; + +exports['detect'] = function(test){ + var call_order = []; + async.detect([3,2,1], function(x, callback){ + setTimeout(function(){ + call_order.push(x); + callback(x == 2); + }, x*25); + }, function(result){ + call_order.push('callback'); + test.equals(result, 2); + }); + setTimeout(function(){ + test.same(call_order, [1,2,'callback',3]); + test.done(); + }, 100); +}; + +exports['detect - mulitple matches'] = function(test){ + var call_order = []; + async.detect([3,2,2,1,2], function(x, callback){ + setTimeout(function(){ + call_order.push(x); + callback(x == 2); + }, x*25); + }, function(result){ + call_order.push('callback'); + test.equals(result, 2); + }); + setTimeout(function(){ + test.same(call_order, [1,2,'callback',2,2,3]); + test.done(); + }, 100); +}; + +exports['detectSeries'] = function(test){ + var call_order = []; + async.detectSeries([3,2,1], function(x, callback){ + setTimeout(function(){ + call_order.push(x); + callback(x == 2); + }, x*25); + }, function(result){ + call_order.push('callback'); + test.equals(result, 2); + }); + setTimeout(function(){ + test.same(call_order, [3,2,'callback']); + test.done(); + }, 200); +}; + +exports['detectSeries - multiple matches'] = function(test){ + var call_order = []; + async.detectSeries([3,2,2,1,2], function(x, callback){ + setTimeout(function(){ + call_order.push(x); + callback(x == 2); + }, x*25); + }, function(result){ + call_order.push('callback'); + test.equals(result, 2); + }); + setTimeout(function(){ + test.same(call_order, [3,2,'callback']); + test.done(); + }, 200); +}; + +exports['sortBy'] = function(test){ + async.sortBy([{a:1},{a:15},{a:6}], function(x, callback){ + setTimeout(function(){callback(null, x.a);}, 0); + }, function(err, result){ + test.same(result, [{a:1},{a:6},{a:15}]); + test.done(); + }); +}; + +exports['apply'] = function(test){ + test.expect(6); + var fn = function(){ + test.same(Array.prototype.slice.call(arguments), [1,2,3,4]) + }; + async.apply(fn, 1, 2, 3, 4)(); + async.apply(fn, 1, 2, 3)(4); + async.apply(fn, 1, 2)(3, 4); + async.apply(fn, 1)(2, 3, 4); + async.apply(fn)(1, 2, 3, 4); + test.equals( + async.apply(function(name){return 'hello ' + name}, 'world')(), + 'hello world' + ); + test.done(); +}; + + +// generates tests for console functions such as async.log +var console_fn_tests = function(name){ + + if (typeof console !== 'undefined') { + exports[name] = function(test){ + test.expect(5); + var fn = function(arg1, callback){ + test.equals(arg1, 'one'); + setTimeout(function(){callback(null, 'test');}, 0); + }; + var fn_err = function(arg1, callback){ + test.equals(arg1, 'one'); + setTimeout(function(){callback('error');}, 0); + }; + var _console_fn = console[name]; + var _error = console.error; + console[name] = function(val){ + test.equals(val, 'test'); + test.equals(arguments.length, 1); + console.error = function(val){ + test.equals(val, 'error'); + console[name] = _console_fn; + console.error = _error; + test.done(); + }; + async[name](fn_err, 'one'); + }; + async[name](fn, 'one'); + }; + + exports[name + ' with multiple result params'] = function(test){ + var fn = function(callback){callback(null,'one','two','three');}; + var _console_fn = console[name]; + var called_with = []; + console[name] = function(x){ + called_with.push(x); + }; + async[name](fn); + test.same(called_with, ['one','two','three']); + console[name] = _console_fn; + test.done(); + }; + } + + // browser-only test + exports[name + ' without console.' + name] = function(test){ + if (typeof window !== 'undefined') { + var _console = window.console; + window.console = undefined; + var fn = function(callback){callback(null, 'val');}; + var fn_err = function(callback){callback('error');}; + async[name](fn); + async[name](fn_err); + window.console = _console; + } + test.done(); + }; + +}; + +console_fn_tests('log'); +console_fn_tests('dir'); +/*console_fn_tests('info'); +console_fn_tests('warn'); +console_fn_tests('error');*/ + +exports['nextTick'] = function(test){ + var call_order = []; + async.nextTick(function(){call_order.push('two');}); + call_order.push('one'); + setTimeout(function(){ + test.same(call_order, ['one','two']); + test.done(); + }, 50); +}; + +exports['nextTick in the browser'] = function(test){ + if (typeof process !== 'undefined') { + // skip this test in node + return test.done(); + } + test.expect(1); + + var call_order = []; + async.nextTick(function(){call_order.push('two');}); + + call_order.push('one'); + setTimeout(function(){ + if (typeof process !== 'undefined') { + process.nextTick = _nextTick; + } + test.same(call_order, ['one','two']); + }, 50); + setTimeout(test.done, 100); +}; + +exports['noConflict - node only'] = function(test){ + if (typeof process !== 'undefined') { + // node only test + test.expect(3); + var fs = require('fs'); + var filename = __dirname + '/../lib/async.js'; + fs.readFile(filename, function(err, content){ + if(err) return test.done(); + var Script = process.binding('evals').Script; + + var s = new Script(content, filename); + var s2 = new Script( + content + 'this.async2 = this.async.noConflict();', + filename + ); + + var sandbox1 = {async: 'oldvalue'}; + s.runInNewContext(sandbox1); + test.ok(sandbox1.async); + + var sandbox2 = {async: 'oldvalue'}; + s2.runInNewContext(sandbox2); + test.equals(sandbox2.async, 'oldvalue'); + test.ok(sandbox2.async2); + + test.done(); + }); + } + else test.done(); +}; + +exports['concat'] = function(test){ + var call_order = []; + var iterator = function (x, cb) { + setTimeout(function(){ + call_order.push(x); + var r = []; + while (x > 0) { + r.push(x); + x--; + } + cb(null, r); + }, x*25); + }; + async.concat([1,3,2], iterator, function(err, results){ + test.same(results, [1,2,1,3,2,1]); + test.same(call_order, [1,2,3]); + test.ok(!err); + test.done(); + }); +}; + +exports['concat error'] = function(test){ + var iterator = function (x, cb) { + cb(new Error('test error')); + }; + async.concat([1,2,3], iterator, function(err, results){ + test.ok(err); + test.done(); + }); +}; + +exports['concatSeries'] = function(test){ + var call_order = []; + var iterator = function (x, cb) { + setTimeout(function(){ + call_order.push(x); + var r = []; + while (x > 0) { + r.push(x); + x--; + } + cb(null, r); + }, x*25); + }; + async.concatSeries([1,3,2], iterator, function(err, results){ + test.same(results, [1,3,2,1,2,1]); + test.same(call_order, [1,3,2]); + test.ok(!err); + test.done(); + }); +}; + +exports['until'] = function (test) { + var call_order = []; + + var count = 0; + async.until( + function () { + call_order.push(['test', count]); + return (count == 5); + }, + function (cb) { + call_order.push(['iterator', count]); + count++; + cb(); + }, + function (err) { + test.same(call_order, [ + ['test', 0], + ['iterator', 0], ['test', 1], + ['iterator', 1], ['test', 2], + ['iterator', 2], ['test', 3], + ['iterator', 3], ['test', 4], + ['iterator', 4], ['test', 5], + ]); + test.equals(count, 5); + test.done(); + } + ); +}; + +exports['whilst'] = function (test) { + var call_order = []; + + var count = 0; + async.whilst( + function () { + call_order.push(['test', count]); + return (count < 5); + }, + function (cb) { + call_order.push(['iterator', count]); + count++; + cb(); + }, + function (err) { + test.same(call_order, [ + ['test', 0], + ['iterator', 0], ['test', 1], + ['iterator', 1], ['test', 2], + ['iterator', 2], ['test', 3], + ['iterator', 3], ['test', 4], + ['iterator', 4], ['test', 5], + ]); + test.equals(count, 5); + test.done(); + } + ); +}; + +exports['queue'] = function (test) { + var call_order = [], + delays = [40,20,60,20]; + + // worker1: --1-4 + // worker2: -2---3 + // order of completion: 2,1,4,3 + + var q = async.queue(function (task, callback) { + setTimeout(function () { + call_order.push('process ' + task); + callback('error', 'arg'); + }, delays.splice(0,1)[0]); + }, 2); + + q.push(1, function (err, arg) { + test.equal(err, 'error'); + test.equal(arg, 'arg'); + test.equal(q.length(), 1); + call_order.push('callback ' + 1); + }); + q.push(2, function (err, arg) { + test.equal(err, 'error'); + test.equal(arg, 'arg'); + test.equal(q.length(), 2); + call_order.push('callback ' + 2); + }); + q.push(3, function (err, arg) { + test.equal(err, 'error'); + test.equal(arg, 'arg'); + test.equal(q.length(), 0); + call_order.push('callback ' + 3); + }); + q.push(4, function (err, arg) { + test.equal(err, 'error'); + test.equal(arg, 'arg'); + test.equal(q.length(), 0); + call_order.push('callback ' + 4); + }); + test.equal(q.length(), 4); + test.equal(q.concurrency, 2); + + setTimeout(function () { + test.same(call_order, [ + 'process 2', 'callback 2', + 'process 1', 'callback 1', + 'process 4', 'callback 4', + 'process 3', 'callback 3' + ]); + test.equal(q.concurrency, 2); + test.equal(q.length(), 0); + test.done(); + }, 200); +}; + +exports['queue changing concurrency'] = function (test) { + var call_order = [], + delays = [40,20,60,20]; + + // worker1: --1-2---3-4 + // order of completion: 1,2,3,4 + + var q = async.queue(function (task, callback) { + setTimeout(function () { + call_order.push('process ' + task); + callback('error', 'arg'); + }, delays.splice(0,1)[0]); + }, 2); + + q.push(1, function (err, arg) { + test.equal(err, 'error'); + test.equal(arg, 'arg'); + test.equal(q.length(), 3); + call_order.push('callback ' + 1); + }); + q.push(2, function (err, arg) { + test.equal(err, 'error'); + test.equal(arg, 'arg'); + test.equal(q.length(), 2); + call_order.push('callback ' + 2); + }); + q.push(3, function (err, arg) { + test.equal(err, 'error'); + test.equal(arg, 'arg'); + test.equal(q.length(), 1); + call_order.push('callback ' + 3); + }); + q.push(4, function (err, arg) { + test.equal(err, 'error'); + test.equal(arg, 'arg'); + test.equal(q.length(), 0); + call_order.push('callback ' + 4); + }); + test.equal(q.length(), 4); + test.equal(q.concurrency, 2); + q.concurrency = 1; + + setTimeout(function () { + test.same(call_order, [ + 'process 1', 'callback 1', + 'process 2', 'callback 2', + 'process 3', 'callback 3', + 'process 4', 'callback 4' + ]); + test.equal(q.concurrency, 1); + test.equal(q.length(), 0); + test.done(); + }, 250); +}; + +exports['queue push without callback'] = function (test) { + var call_order = [], + delays = [40,20,60,20]; + + // worker1: --1-4 + // worker2: -2---3 + // order of completion: 2,1,4,3 + + var q = async.queue(function (task, callback) { + setTimeout(function () { + call_order.push('process ' + task); + callback('error', 'arg'); + }, delays.splice(0,1)[0]); + }, 2); + + q.push(1); + q.push(2); + q.push(3); + q.push(4); + + setTimeout(function () { + test.same(call_order, [ + 'process 2', + 'process 1', + 'process 4', + 'process 3' + ]); + test.done(); + }, 200); +}; + +exports['memoize'] = function (test) { + test.expect(4); + var call_order = []; + + var fn = function (arg1, arg2, callback) { + call_order.push(['fn', arg1, arg2]); + callback(null, arg1 + arg2); + }; + + var fn2 = async.memoize(fn); + fn2(1, 2, function (err, result) { + test.equal(result, 3); + }); + fn2(1, 2, function (err, result) { + test.equal(result, 3); + }); + fn2(2, 2, function (err, result) { + test.equal(result, 4); + }); + + test.same(call_order, [['fn',1,2], ['fn',2,2]]); + test.done(); +}; + +exports['unmemoize'] = function(test) { + test.expect(4); + var call_order = []; + + var fn = function (arg1, arg2, callback) { + call_order.push(['fn', arg1, arg2]); + callback(null, arg1 + arg2); + }; + + var fn2 = async.memoize(fn); + var fn3 = async.unmemoize(fn2); + fn3(1, 2, function (err, result) { + test.equal(result, 3); + }); + fn3(1, 2, function (err, result) { + test.equal(result, 3); + }); + fn3(2, 2, function (err, result) { + test.equal(result, 4); + }); + + test.same(call_order, [['fn',1,2], ['fn',1,2], ['fn',2,2]]); + + test.done(); +} + +exports['unmemoize a not memoized function'] = function(test) { + test.expect(1); + + var fn = function (arg1, arg2, callback) { + callback(null, arg1 + arg2); + }; + + var fn2 = async.unmemoize(fn); + fn2(1, 2, function(err, result) { + test.equal(result, 3); + }); + + test.done(); +} + +exports['memoize error'] = function (test) { + test.expect(1); + var testerr = new Error('test'); + var fn = function (arg1, arg2, callback) { + callback(testerr, arg1 + arg2); + }; + async.memoize(fn)(1, 2, function (err, result) { + test.equal(err, testerr); + }); + test.done(); +}; + +exports['memoize multiple calls'] = function (test) { + test.expect(3); + var fn = function (arg1, arg2, callback) { + test.ok(true); + setTimeout(function(){ + callback(null, arg1, arg2); + }, 10); + }; + var fn2 = async.memoize(fn); + fn2(1, 2, function(err, result) { + test.equal(result, 1, 2); + }); + fn2(1, 2, function(err, result) { + test.equal(result, 1, 2); + test.done(); + }); +}; + +exports['memoize custom hash function'] = function (test) { + test.expect(2); + var testerr = new Error('test'); + + var fn = function (arg1, arg2, callback) { + callback(testerr, arg1 + arg2); + }; + var fn2 = async.memoize(fn, function () { + return 'custom hash'; + }); + fn2(1, 2, function (err, result) { + test.equal(result, 3); + }); + fn2(2, 2, function (err, result) { + test.equal(result, 3); + }); + test.done(); +}; + +// Issue 10 on github: https://github.com/caolan/async/issues#issue/10 +exports['falsy return values in series'] = function (test) { + function taskFalse(callback) { + async.nextTick(function() { + callback(null, false); + }); + }; + function taskUndefined(callback) { + async.nextTick(function() { + callback(null, undefined); + }); + }; + function taskEmpty(callback) { + async.nextTick(function() { + callback(null); + }); + }; + function taskNull(callback) { + async.nextTick(function() { + callback(null, null); + }); + }; + async.series( + [taskFalse, taskUndefined, taskEmpty, taskNull], + function(err, results) { + test.equal(results.length, 4); + test.strictEqual(results[0], false); + test.strictEqual(results[1], undefined); + test.strictEqual(results[2], undefined); + test.strictEqual(results[3], null); + test.done(); + } + ); +}; + +// Issue 10 on github: https://github.com/caolan/async/issues#issue/10 +exports['falsy return values in parallel'] = function (test) { + function taskFalse(callback) { + async.nextTick(function() { + callback(null, false); + }); + }; + function taskUndefined(callback) { + async.nextTick(function() { + callback(null, undefined); + }); + }; + function taskEmpty(callback) { + async.nextTick(function() { + callback(null); + }); + }; + function taskNull(callback) { + async.nextTick(function() { + callback(null, null); + }); + }; + async.parallel( + [taskFalse, taskUndefined, taskEmpty, taskNull], + function(err, results) { + test.equal(results.length, 4); + test.strictEqual(results[0], false); + test.strictEqual(results[1], undefined); + test.strictEqual(results[2], undefined); + test.strictEqual(results[3], null); + test.done(); + } + ); +}; + +exports['queue events'] = function(test) { + var calls = []; + var q = async.queue(function(task, cb) { + // nop + calls.push('process ' + task); + cb(); + }, 3); + + q.saturated = function() { + test.ok(q.length() == 3, 'queue should be saturated now'); + calls.push('saturated'); + }; + q.empty = function() { + test.ok(q.length() == 0, 'queue should be empty now'); + calls.push('empty'); + }; + q.drain = function() { + test.ok( + q.length() == 0 && q.running() == 0, + 'queue should be empty now and no more workers should be running' + ); + calls.push('drain'); + test.same(calls, [ + 'saturated', + 'process foo', + 'foo cb', + 'process bar', + 'bar cb', + 'process zoo', + 'zoo cb', + 'process poo', + 'poo cb', + 'empty', + 'process moo', + 'moo cb', + 'drain', + ]); + test.done(); + }; + q.push('foo', function () {calls.push('foo cb');}); + q.push('bar', function () {calls.push('bar cb');}); + q.push('zoo', function () {calls.push('zoo cb');}); + q.push('poo', function () {calls.push('poo cb');}); + q.push('moo', function () {calls.push('moo cb');}); +}; diff --git a/node_modules/async/test/test.html b/node_modules/async/test/test.html new file mode 100644 index 000000000..2450e2dcf --- /dev/null +++ b/node_modules/async/test/test.html @@ -0,0 +1,24 @@ + + + Async.js Test Suite + + + + + + + + +

Async.js Test Suite

+ + +