Initial commit
[yaffs-website] / node_modules / async / dist / async.js
1 /*!
2  * async
3  * https://github.com/caolan/async
4  *
5  * Copyright 2010-2014 Caolan McMahon
6  * Released under the MIT license
7  */
8 (function () {
9
10     var async = {};
11     function noop() {}
12     function identity(v) {
13         return v;
14     }
15     function toBool(v) {
16         return !!v;
17     }
18     function notId(v) {
19         return !v;
20     }
21
22     // global on the server, window in the browser
23     var previous_async;
24
25     // Establish the root object, `window` (`self`) in the browser, `global`
26     // on the server, or `this` in some virtual machines. We use `self`
27     // instead of `window` for `WebWorker` support.
28     var root = typeof self === 'object' && self.self === self && self ||
29             typeof global === 'object' && global.global === global && global ||
30             this;
31
32     if (root != null) {
33         previous_async = root.async;
34     }
35
36     async.noConflict = function () {
37         root.async = previous_async;
38         return async;
39     };
40
41     function only_once(fn) {
42         return function() {
43             if (fn === null) throw new Error("Callback was already called.");
44             fn.apply(this, arguments);
45             fn = null;
46         };
47     }
48
49     function _once(fn) {
50         return function() {
51             if (fn === null) return;
52             fn.apply(this, arguments);
53             fn = null;
54         };
55     }
56
57     //// cross-browser compatiblity functions ////
58
59     var _toString = Object.prototype.toString;
60
61     var _isArray = Array.isArray || function (obj) {
62         return _toString.call(obj) === '[object Array]';
63     };
64
65     // Ported from underscore.js isObject
66     var _isObject = function(obj) {
67         var type = typeof obj;
68         return type === 'function' || type === 'object' && !!obj;
69     };
70
71     function _isArrayLike(arr) {
72         return _isArray(arr) || (
73             // has a positive integer length property
74             typeof arr.length === "number" &&
75             arr.length >= 0 &&
76             arr.length % 1 === 0
77         );
78     }
79
80     function _arrayEach(arr, iterator) {
81         var index = -1,
82             length = arr.length;
83
84         while (++index < length) {
85             iterator(arr[index], index, arr);
86         }
87     }
88
89     function _map(arr, iterator) {
90         var index = -1,
91             length = arr.length,
92             result = Array(length);
93
94         while (++index < length) {
95             result[index] = iterator(arr[index], index, arr);
96         }
97         return result;
98     }
99
100     function _range(count) {
101         return _map(Array(count), function (v, i) { return i; });
102     }
103
104     function _reduce(arr, iterator, memo) {
105         _arrayEach(arr, function (x, i, a) {
106             memo = iterator(memo, x, i, a);
107         });
108         return memo;
109     }
110
111     function _forEachOf(object, iterator) {
112         _arrayEach(_keys(object), function (key) {
113             iterator(object[key], key);
114         });
115     }
116
117     function _indexOf(arr, item) {
118         for (var i = 0; i < arr.length; i++) {
119             if (arr[i] === item) return i;
120         }
121         return -1;
122     }
123
124     var _keys = Object.keys || function (obj) {
125         var keys = [];
126         for (var k in obj) {
127             if (obj.hasOwnProperty(k)) {
128                 keys.push(k);
129             }
130         }
131         return keys;
132     };
133
134     function _keyIterator(coll) {
135         var i = -1;
136         var len;
137         var keys;
138         if (_isArrayLike(coll)) {
139             len = coll.length;
140             return function next() {
141                 i++;
142                 return i < len ? i : null;
143             };
144         } else {
145             keys = _keys(coll);
146             len = keys.length;
147             return function next() {
148                 i++;
149                 return i < len ? keys[i] : null;
150             };
151         }
152     }
153
154     // Similar to ES6's rest param (http://ariya.ofilabs.com/2013/03/es6-and-rest-parameter.html)
155     // This accumulates the arguments passed into an array, after a given index.
156     // From underscore.js (https://github.com/jashkenas/underscore/pull/2140).
157     function _restParam(func, startIndex) {
158         startIndex = startIndex == null ? func.length - 1 : +startIndex;
159         return function() {
160             var length = Math.max(arguments.length - startIndex, 0);
161             var rest = Array(length);
162             for (var index = 0; index < length; index++) {
163                 rest[index] = arguments[index + startIndex];
164             }
165             switch (startIndex) {
166                 case 0: return func.call(this, rest);
167                 case 1: return func.call(this, arguments[0], rest);
168             }
169             // Currently unused but handle cases outside of the switch statement:
170             // var args = Array(startIndex + 1);
171             // for (index = 0; index < startIndex; index++) {
172             //     args[index] = arguments[index];
173             // }
174             // args[startIndex] = rest;
175             // return func.apply(this, args);
176         };
177     }
178
179     function _withoutIndex(iterator) {
180         return function (value, index, callback) {
181             return iterator(value, callback);
182         };
183     }
184
185     //// exported async module functions ////
186
187     //// nextTick implementation with browser-compatible fallback ////
188
189     // capture the global reference to guard against fakeTimer mocks
190     var _setImmediate = typeof setImmediate === 'function' && setImmediate;
191
192     var _delay = _setImmediate ? function(fn) {
193         // not a direct alias for IE10 compatibility
194         _setImmediate(fn);
195     } : function(fn) {
196         setTimeout(fn, 0);
197     };
198
199     if (typeof process === 'object' && typeof process.nextTick === 'function') {
200         async.nextTick = process.nextTick;
201     } else {
202         async.nextTick = _delay;
203     }
204     async.setImmediate = _setImmediate ? _delay : async.nextTick;
205
206
207     async.forEach =
208     async.each = function (arr, iterator, callback) {
209         return async.eachOf(arr, _withoutIndex(iterator), callback);
210     };
211
212     async.forEachSeries =
213     async.eachSeries = function (arr, iterator, callback) {
214         return async.eachOfSeries(arr, _withoutIndex(iterator), callback);
215     };
216
217
218     async.forEachLimit =
219     async.eachLimit = function (arr, limit, iterator, callback) {
220         return _eachOfLimit(limit)(arr, _withoutIndex(iterator), callback);
221     };
222
223     async.forEachOf =
224     async.eachOf = function (object, iterator, callback) {
225         callback = _once(callback || noop);
226         object = object || [];
227
228         var iter = _keyIterator(object);
229         var key, completed = 0;
230
231         while ((key = iter()) != null) {
232             completed += 1;
233             iterator(object[key], key, only_once(done));
234         }
235
236         if (completed === 0) callback(null);
237
238         function done(err) {
239             completed--;
240             if (err) {
241                 callback(err);
242             }
243             // Check key is null in case iterator isn't exhausted
244             // and done resolved synchronously.
245             else if (key === null && completed <= 0) {
246                 callback(null);
247             }
248         }
249     };
250
251     async.forEachOfSeries =
252     async.eachOfSeries = function (obj, iterator, callback) {
253         callback = _once(callback || noop);
254         obj = obj || [];
255         var nextKey = _keyIterator(obj);
256         var key = nextKey();
257         function iterate() {
258             var sync = true;
259             if (key === null) {
260                 return callback(null);
261             }
262             iterator(obj[key], key, only_once(function (err) {
263                 if (err) {
264                     callback(err);
265                 }
266                 else {
267                     key = nextKey();
268                     if (key === null) {
269                         return callback(null);
270                     } else {
271                         if (sync) {
272                             async.setImmediate(iterate);
273                         } else {
274                             iterate();
275                         }
276                     }
277                 }
278             }));
279             sync = false;
280         }
281         iterate();
282     };
283
284
285
286     async.forEachOfLimit =
287     async.eachOfLimit = function (obj, limit, iterator, callback) {
288         _eachOfLimit(limit)(obj, iterator, callback);
289     };
290
291     function _eachOfLimit(limit) {
292
293         return function (obj, iterator, callback) {
294             callback = _once(callback || noop);
295             obj = obj || [];
296             var nextKey = _keyIterator(obj);
297             if (limit <= 0) {
298                 return callback(null);
299             }
300             var done = false;
301             var running = 0;
302             var errored = false;
303
304             (function replenish () {
305                 if (done && running <= 0) {
306                     return callback(null);
307                 }
308
309                 while (running < limit && !errored) {
310                     var key = nextKey();
311                     if (key === null) {
312                         done = true;
313                         if (running <= 0) {
314                             callback(null);
315                         }
316                         return;
317                     }
318                     running += 1;
319                     iterator(obj[key], key, only_once(function (err) {
320                         running -= 1;
321                         if (err) {
322                             callback(err);
323                             errored = true;
324                         }
325                         else {
326                             replenish();
327                         }
328                     }));
329                 }
330             })();
331         };
332     }
333
334
335     function doParallel(fn) {
336         return function (obj, iterator, callback) {
337             return fn(async.eachOf, obj, iterator, callback);
338         };
339     }
340     function doParallelLimit(fn) {
341         return function (obj, limit, iterator, callback) {
342             return fn(_eachOfLimit(limit), obj, iterator, callback);
343         };
344     }
345     function doSeries(fn) {
346         return function (obj, iterator, callback) {
347             return fn(async.eachOfSeries, obj, iterator, callback);
348         };
349     }
350
351     function _asyncMap(eachfn, arr, iterator, callback) {
352         callback = _once(callback || noop);
353         arr = arr || [];
354         var results = _isArrayLike(arr) ? [] : {};
355         eachfn(arr, function (value, index, callback) {
356             iterator(value, function (err, v) {
357                 results[index] = v;
358                 callback(err);
359             });
360         }, function (err) {
361             callback(err, results);
362         });
363     }
364
365     async.map = doParallel(_asyncMap);
366     async.mapSeries = doSeries(_asyncMap);
367     async.mapLimit = doParallelLimit(_asyncMap);
368
369     // reduce only has a series version, as doing reduce in parallel won't
370     // work in many situations.
371     async.inject =
372     async.foldl =
373     async.reduce = function (arr, memo, iterator, callback) {
374         async.eachOfSeries(arr, function (x, i, callback) {
375             iterator(memo, x, function (err, v) {
376                 memo = v;
377                 callback(err);
378             });
379         }, function (err) {
380             callback(err, memo);
381         });
382     };
383
384     async.foldr =
385     async.reduceRight = function (arr, memo, iterator, callback) {
386         var reversed = _map(arr, identity).reverse();
387         async.reduce(reversed, memo, iterator, callback);
388     };
389
390     async.transform = function (arr, memo, iterator, callback) {
391         if (arguments.length === 3) {
392             callback = iterator;
393             iterator = memo;
394             memo = _isArray(arr) ? [] : {};
395         }
396
397         async.eachOf(arr, function(v, k, cb) {
398             iterator(memo, v, k, cb);
399         }, function(err) {
400             callback(err, memo);
401         });
402     };
403
404     function _filter(eachfn, arr, iterator, callback) {
405         var results = [];
406         eachfn(arr, function (x, index, callback) {
407             iterator(x, function (v) {
408                 if (v) {
409                     results.push({index: index, value: x});
410                 }
411                 callback();
412             });
413         }, function () {
414             callback(_map(results.sort(function (a, b) {
415                 return a.index - b.index;
416             }), function (x) {
417                 return x.value;
418             }));
419         });
420     }
421
422     async.select =
423     async.filter = doParallel(_filter);
424
425     async.selectLimit =
426     async.filterLimit = doParallelLimit(_filter);
427
428     async.selectSeries =
429     async.filterSeries = doSeries(_filter);
430
431     function _reject(eachfn, arr, iterator, callback) {
432         _filter(eachfn, arr, function(value, cb) {
433             iterator(value, function(v) {
434                 cb(!v);
435             });
436         }, callback);
437     }
438     async.reject = doParallel(_reject);
439     async.rejectLimit = doParallelLimit(_reject);
440     async.rejectSeries = doSeries(_reject);
441
442     function _createTester(eachfn, check, getResult) {
443         return function(arr, limit, iterator, cb) {
444             function done() {
445                 if (cb) cb(getResult(false, void 0));
446             }
447             function iteratee(x, _, callback) {
448                 if (!cb) return callback();
449                 iterator(x, function (v) {
450                     if (cb && check(v)) {
451                         cb(getResult(true, x));
452                         cb = iterator = false;
453                     }
454                     callback();
455                 });
456             }
457             if (arguments.length > 3) {
458                 eachfn(arr, limit, iteratee, done);
459             } else {
460                 cb = iterator;
461                 iterator = limit;
462                 eachfn(arr, iteratee, done);
463             }
464         };
465     }
466
467     async.any =
468     async.some = _createTester(async.eachOf, toBool, identity);
469
470     async.someLimit = _createTester(async.eachOfLimit, toBool, identity);
471
472     async.all =
473     async.every = _createTester(async.eachOf, notId, notId);
474
475     async.everyLimit = _createTester(async.eachOfLimit, notId, notId);
476
477     function _findGetResult(v, x) {
478         return x;
479     }
480     async.detect = _createTester(async.eachOf, identity, _findGetResult);
481     async.detectSeries = _createTester(async.eachOfSeries, identity, _findGetResult);
482     async.detectLimit = _createTester(async.eachOfLimit, identity, _findGetResult);
483
484     async.sortBy = function (arr, iterator, callback) {
485         async.map(arr, function (x, callback) {
486             iterator(x, function (err, criteria) {
487                 if (err) {
488                     callback(err);
489                 }
490                 else {
491                     callback(null, {value: x, criteria: criteria});
492                 }
493             });
494         }, function (err, results) {
495             if (err) {
496                 return callback(err);
497             }
498             else {
499                 callback(null, _map(results.sort(comparator), function (x) {
500                     return x.value;
501                 }));
502             }
503
504         });
505
506         function comparator(left, right) {
507             var a = left.criteria, b = right.criteria;
508             return a < b ? -1 : a > b ? 1 : 0;
509         }
510     };
511
512     async.auto = function (tasks, concurrency, callback) {
513         if (typeof arguments[1] === 'function') {
514             // concurrency is optional, shift the args.
515             callback = concurrency;
516             concurrency = null;
517         }
518         callback = _once(callback || noop);
519         var keys = _keys(tasks);
520         var remainingTasks = keys.length;
521         if (!remainingTasks) {
522             return callback(null);
523         }
524         if (!concurrency) {
525             concurrency = remainingTasks;
526         }
527
528         var results = {};
529         var runningTasks = 0;
530
531         var hasError = false;
532
533         var listeners = [];
534         function addListener(fn) {
535             listeners.unshift(fn);
536         }
537         function removeListener(fn) {
538             var idx = _indexOf(listeners, fn);
539             if (idx >= 0) listeners.splice(idx, 1);
540         }
541         function taskComplete() {
542             remainingTasks--;
543             _arrayEach(listeners.slice(0), function (fn) {
544                 fn();
545             });
546         }
547
548         addListener(function () {
549             if (!remainingTasks) {
550                 callback(null, results);
551             }
552         });
553
554         _arrayEach(keys, function (k) {
555             if (hasError) return;
556             var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]];
557             var taskCallback = _restParam(function(err, args) {
558                 runningTasks--;
559                 if (args.length <= 1) {
560                     args = args[0];
561                 }
562                 if (err) {
563                     var safeResults = {};
564                     _forEachOf(results, function(val, rkey) {
565                         safeResults[rkey] = val;
566                     });
567                     safeResults[k] = args;
568                     hasError = true;
569
570                     callback(err, safeResults);
571                 }
572                 else {
573                     results[k] = args;
574                     async.setImmediate(taskComplete);
575                 }
576             });
577             var requires = task.slice(0, task.length - 1);
578             // prevent dead-locks
579             var len = requires.length;
580             var dep;
581             while (len--) {
582                 if (!(dep = tasks[requires[len]])) {
583                     throw new Error('Has nonexistent dependency in ' + requires.join(', '));
584                 }
585                 if (_isArray(dep) && _indexOf(dep, k) >= 0) {
586                     throw new Error('Has cyclic dependencies');
587                 }
588             }
589             function ready() {
590                 return runningTasks < concurrency && _reduce(requires, function (a, x) {
591                     return (a && results.hasOwnProperty(x));
592                 }, true) && !results.hasOwnProperty(k);
593             }
594             if (ready()) {
595                 runningTasks++;
596                 task[task.length - 1](taskCallback, results);
597             }
598             else {
599                 addListener(listener);
600             }
601             function listener() {
602                 if (ready()) {
603                     runningTasks++;
604                     removeListener(listener);
605                     task[task.length - 1](taskCallback, results);
606                 }
607             }
608         });
609     };
610
611
612
613     async.retry = function(times, task, callback) {
614         var DEFAULT_TIMES = 5;
615         var DEFAULT_INTERVAL = 0;
616
617         var attempts = [];
618
619         var opts = {
620             times: DEFAULT_TIMES,
621             interval: DEFAULT_INTERVAL
622         };
623
624         function parseTimes(acc, t){
625             if(typeof t === 'number'){
626                 acc.times = parseInt(t, 10) || DEFAULT_TIMES;
627             } else if(typeof t === 'object'){
628                 acc.times = parseInt(t.times, 10) || DEFAULT_TIMES;
629                 acc.interval = parseInt(t.interval, 10) || DEFAULT_INTERVAL;
630             } else {
631                 throw new Error('Unsupported argument type for \'times\': ' + typeof t);
632             }
633         }
634
635         var length = arguments.length;
636         if (length < 1 || length > 3) {
637             throw new Error('Invalid arguments - must be either (task), (task, callback), (times, task) or (times, task, callback)');
638         } else if (length <= 2 && typeof times === 'function') {
639             callback = task;
640             task = times;
641         }
642         if (typeof times !== 'function') {
643             parseTimes(opts, times);
644         }
645         opts.callback = callback;
646         opts.task = task;
647
648         function wrappedTask(wrappedCallback, wrappedResults) {
649             function retryAttempt(task, finalAttempt) {
650                 return function(seriesCallback) {
651                     task(function(err, result){
652                         seriesCallback(!err || finalAttempt, {err: err, result: result});
653                     }, wrappedResults);
654                 };
655             }
656
657             function retryInterval(interval){
658                 return function(seriesCallback){
659                     setTimeout(function(){
660                         seriesCallback(null);
661                     }, interval);
662                 };
663             }
664
665             while (opts.times) {
666
667                 var finalAttempt = !(opts.times-=1);
668                 attempts.push(retryAttempt(opts.task, finalAttempt));
669                 if(!finalAttempt && opts.interval > 0){
670                     attempts.push(retryInterval(opts.interval));
671                 }
672             }
673
674             async.series(attempts, function(done, data){
675                 data = data[data.length - 1];
676                 (wrappedCallback || opts.callback)(data.err, data.result);
677             });
678         }
679
680         // If a callback is passed, run this as a controll flow
681         return opts.callback ? wrappedTask() : wrappedTask;
682     };
683
684     async.waterfall = function (tasks, callback) {
685         callback = _once(callback || noop);
686         if (!_isArray(tasks)) {
687             var err = new Error('First argument to waterfall must be an array of functions');
688             return callback(err);
689         }
690         if (!tasks.length) {
691             return callback();
692         }
693         function wrapIterator(iterator) {
694             return _restParam(function (err, args) {
695                 if (err) {
696                     callback.apply(null, [err].concat(args));
697                 }
698                 else {
699                     var next = iterator.next();
700                     if (next) {
701                         args.push(wrapIterator(next));
702                     }
703                     else {
704                         args.push(callback);
705                     }
706                     ensureAsync(iterator).apply(null, args);
707                 }
708             });
709         }
710         wrapIterator(async.iterator(tasks))();
711     };
712
713     function _parallel(eachfn, tasks, callback) {
714         callback = callback || noop;
715         var results = _isArrayLike(tasks) ? [] : {};
716
717         eachfn(tasks, function (task, key, callback) {
718             task(_restParam(function (err, args) {
719                 if (args.length <= 1) {
720                     args = args[0];
721                 }
722                 results[key] = args;
723                 callback(err);
724             }));
725         }, function (err) {
726             callback(err, results);
727         });
728     }
729
730     async.parallel = function (tasks, callback) {
731         _parallel(async.eachOf, tasks, callback);
732     };
733
734     async.parallelLimit = function(tasks, limit, callback) {
735         _parallel(_eachOfLimit(limit), tasks, callback);
736     };
737
738     async.series = function(tasks, callback) {
739         _parallel(async.eachOfSeries, tasks, callback);
740     };
741
742     async.iterator = function (tasks) {
743         function makeCallback(index) {
744             function fn() {
745                 if (tasks.length) {
746                     tasks[index].apply(null, arguments);
747                 }
748                 return fn.next();
749             }
750             fn.next = function () {
751                 return (index < tasks.length - 1) ? makeCallback(index + 1): null;
752             };
753             return fn;
754         }
755         return makeCallback(0);
756     };
757
758     async.apply = _restParam(function (fn, args) {
759         return _restParam(function (callArgs) {
760             return fn.apply(
761                 null, args.concat(callArgs)
762             );
763         });
764     });
765
766     function _concat(eachfn, arr, fn, callback) {
767         var result = [];
768         eachfn(arr, function (x, index, cb) {
769             fn(x, function (err, y) {
770                 result = result.concat(y || []);
771                 cb(err);
772             });
773         }, function (err) {
774             callback(err, result);
775         });
776     }
777     async.concat = doParallel(_concat);
778     async.concatSeries = doSeries(_concat);
779
780     async.whilst = function (test, iterator, callback) {
781         callback = callback || noop;
782         if (test()) {
783             var next = _restParam(function(err, args) {
784                 if (err) {
785                     callback(err);
786                 } else if (test.apply(this, args)) {
787                     iterator(next);
788                 } else {
789                     callback.apply(null, [null].concat(args));
790                 }
791             });
792             iterator(next);
793         } else {
794             callback(null);
795         }
796     };
797
798     async.doWhilst = function (iterator, test, callback) {
799         var calls = 0;
800         return async.whilst(function() {
801             return ++calls <= 1 || test.apply(this, arguments);
802         }, iterator, callback);
803     };
804
805     async.until = function (test, iterator, callback) {
806         return async.whilst(function() {
807             return !test.apply(this, arguments);
808         }, iterator, callback);
809     };
810
811     async.doUntil = function (iterator, test, callback) {
812         return async.doWhilst(iterator, function() {
813             return !test.apply(this, arguments);
814         }, callback);
815     };
816
817     async.during = function (test, iterator, callback) {
818         callback = callback || noop;
819
820         var next = _restParam(function(err, args) {
821             if (err) {
822                 callback(err);
823             } else {
824                 args.push(check);
825                 test.apply(this, args);
826             }
827         });
828
829         var check = function(err, truth) {
830             if (err) {
831                 callback(err);
832             } else if (truth) {
833                 iterator(next);
834             } else {
835                 callback(null);
836             }
837         };
838
839         test(check);
840     };
841
842     async.doDuring = function (iterator, test, callback) {
843         var calls = 0;
844         async.during(function(next) {
845             if (calls++ < 1) {
846                 next(null, true);
847             } else {
848                 test.apply(this, arguments);
849             }
850         }, iterator, callback);
851     };
852
853     function _queue(worker, concurrency, payload) {
854         if (concurrency == null) {
855             concurrency = 1;
856         }
857         else if(concurrency === 0) {
858             throw new Error('Concurrency must not be zero');
859         }
860         function _insert(q, data, pos, callback) {
861             if (callback != null && typeof callback !== "function") {
862                 throw new Error("task callback must be a function");
863             }
864             q.started = true;
865             if (!_isArray(data)) {
866                 data = [data];
867             }
868             if(data.length === 0 && q.idle()) {
869                 // call drain immediately if there are no tasks
870                 return async.setImmediate(function() {
871                     q.drain();
872                 });
873             }
874             _arrayEach(data, function(task) {
875                 var item = {
876                     data: task,
877                     callback: callback || noop
878                 };
879
880                 if (pos) {
881                     q.tasks.unshift(item);
882                 } else {
883                     q.tasks.push(item);
884                 }
885
886                 if (q.tasks.length === q.concurrency) {
887                     q.saturated();
888                 }
889             });
890             async.setImmediate(q.process);
891         }
892         function _next(q, tasks) {
893             return function(){
894                 workers -= 1;
895
896                 var removed = false;
897                 var args = arguments;
898                 _arrayEach(tasks, function (task) {
899                     _arrayEach(workersList, function (worker, index) {
900                         if (worker === task && !removed) {
901                             workersList.splice(index, 1);
902                             removed = true;
903                         }
904                     });
905
906                     task.callback.apply(task, args);
907                 });
908                 if (q.tasks.length + workers === 0) {
909                     q.drain();
910                 }
911                 q.process();
912             };
913         }
914
915         var workers = 0;
916         var workersList = [];
917         var q = {
918             tasks: [],
919             concurrency: concurrency,
920             payload: payload,
921             saturated: noop,
922             empty: noop,
923             drain: noop,
924             started: false,
925             paused: false,
926             push: function (data, callback) {
927                 _insert(q, data, false, callback);
928             },
929             kill: function () {
930                 q.drain = noop;
931                 q.tasks = [];
932             },
933             unshift: function (data, callback) {
934                 _insert(q, data, true, callback);
935             },
936             process: function () {
937                 while(!q.paused && workers < q.concurrency && q.tasks.length){
938
939                     var tasks = q.payload ?
940                         q.tasks.splice(0, q.payload) :
941                         q.tasks.splice(0, q.tasks.length);
942
943                     var data = _map(tasks, function (task) {
944                         return task.data;
945                     });
946
947                     if (q.tasks.length === 0) {
948                         q.empty();
949                     }
950                     workers += 1;
951                     workersList.push(tasks[0]);
952                     var cb = only_once(_next(q, tasks));
953                     worker(data, cb);
954                 }
955             },
956             length: function () {
957                 return q.tasks.length;
958             },
959             running: function () {
960                 return workers;
961             },
962             workersList: function () {
963                 return workersList;
964             },
965             idle: function() {
966                 return q.tasks.length + workers === 0;
967             },
968             pause: function () {
969                 q.paused = true;
970             },
971             resume: function () {
972                 if (q.paused === false) { return; }
973                 q.paused = false;
974                 var resumeCount = Math.min(q.concurrency, q.tasks.length);
975                 // Need to call q.process once per concurrent
976                 // worker to preserve full concurrency after pause
977                 for (var w = 1; w <= resumeCount; w++) {
978                     async.setImmediate(q.process);
979                 }
980             }
981         };
982         return q;
983     }
984
985     async.queue = function (worker, concurrency) {
986         var q = _queue(function (items, cb) {
987             worker(items[0], cb);
988         }, concurrency, 1);
989
990         return q;
991     };
992
993     async.priorityQueue = function (worker, concurrency) {
994
995         function _compareTasks(a, b){
996             return a.priority - b.priority;
997         }
998
999         function _binarySearch(sequence, item, compare) {
1000             var beg = -1,
1001                 end = sequence.length - 1;
1002             while (beg < end) {
1003                 var mid = beg + ((end - beg + 1) >>> 1);
1004                 if (compare(item, sequence[mid]) >= 0) {
1005                     beg = mid;
1006                 } else {
1007                     end = mid - 1;
1008                 }
1009             }
1010             return beg;
1011         }
1012
1013         function _insert(q, data, priority, callback) {
1014             if (callback != null && typeof callback !== "function") {
1015                 throw new Error("task callback must be a function");
1016             }
1017             q.started = true;
1018             if (!_isArray(data)) {
1019                 data = [data];
1020             }
1021             if(data.length === 0) {
1022                 // call drain immediately if there are no tasks
1023                 return async.setImmediate(function() {
1024                     q.drain();
1025                 });
1026             }
1027             _arrayEach(data, function(task) {
1028                 var item = {
1029                     data: task,
1030                     priority: priority,
1031                     callback: typeof callback === 'function' ? callback : noop
1032                 };
1033
1034                 q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item);
1035
1036                 if (q.tasks.length === q.concurrency) {
1037                     q.saturated();
1038                 }
1039                 async.setImmediate(q.process);
1040             });
1041         }
1042
1043         // Start with a normal queue
1044         var q = async.queue(worker, concurrency);
1045
1046         // Override push to accept second parameter representing priority
1047         q.push = function (data, priority, callback) {
1048             _insert(q, data, priority, callback);
1049         };
1050
1051         // Remove unshift function
1052         delete q.unshift;
1053
1054         return q;
1055     };
1056
1057     async.cargo = function (worker, payload) {
1058         return _queue(worker, 1, payload);
1059     };
1060
1061     function _console_fn(name) {
1062         return _restParam(function (fn, args) {
1063             fn.apply(null, args.concat([_restParam(function (err, args) {
1064                 if (typeof console === 'object') {
1065                     if (err) {
1066                         if (console.error) {
1067                             console.error(err);
1068                         }
1069                     }
1070                     else if (console[name]) {
1071                         _arrayEach(args, function (x) {
1072                             console[name](x);
1073                         });
1074                     }
1075                 }
1076             })]));
1077         });
1078     }
1079     async.log = _console_fn('log');
1080     async.dir = _console_fn('dir');
1081     /*async.info = _console_fn('info');
1082     async.warn = _console_fn('warn');
1083     async.error = _console_fn('error');*/
1084
1085     async.memoize = function (fn, hasher) {
1086         var memo = {};
1087         var queues = {};
1088         var has = Object.prototype.hasOwnProperty;
1089         hasher = hasher || identity;
1090         var memoized = _restParam(function memoized(args) {
1091             var callback = args.pop();
1092             var key = hasher.apply(null, args);
1093             if (has.call(memo, key)) {   
1094                 async.setImmediate(function () {
1095                     callback.apply(null, memo[key]);
1096                 });
1097             }
1098             else if (has.call(queues, key)) {
1099                 queues[key].push(callback);
1100             }
1101             else {
1102                 queues[key] = [callback];
1103                 fn.apply(null, args.concat([_restParam(function (args) {
1104                     memo[key] = args;
1105                     var q = queues[key];
1106                     delete queues[key];
1107                     for (var i = 0, l = q.length; i < l; i++) {
1108                         q[i].apply(null, args);
1109                     }
1110                 })]));
1111             }
1112         });
1113         memoized.memo = memo;
1114         memoized.unmemoized = fn;
1115         return memoized;
1116     };
1117
1118     async.unmemoize = function (fn) {
1119         return function () {
1120             return (fn.unmemoized || fn).apply(null, arguments);
1121         };
1122     };
1123
1124     function _times(mapper) {
1125         return function (count, iterator, callback) {
1126             mapper(_range(count), iterator, callback);
1127         };
1128     }
1129
1130     async.times = _times(async.map);
1131     async.timesSeries = _times(async.mapSeries);
1132     async.timesLimit = function (count, limit, iterator, callback) {
1133         return async.mapLimit(_range(count), limit, iterator, callback);
1134     };
1135
1136     async.seq = function (/* functions... */) {
1137         var fns = arguments;
1138         return _restParam(function (args) {
1139             var that = this;
1140
1141             var callback = args[args.length - 1];
1142             if (typeof callback == 'function') {
1143                 args.pop();
1144             } else {
1145                 callback = noop;
1146             }
1147
1148             async.reduce(fns, args, function (newargs, fn, cb) {
1149                 fn.apply(that, newargs.concat([_restParam(function (err, nextargs) {
1150                     cb(err, nextargs);
1151                 })]));
1152             },
1153             function (err, results) {
1154                 callback.apply(that, [err].concat(results));
1155             });
1156         });
1157     };
1158
1159     async.compose = function (/* functions... */) {
1160         return async.seq.apply(null, Array.prototype.reverse.call(arguments));
1161     };
1162
1163
1164     function _applyEach(eachfn) {
1165         return _restParam(function(fns, args) {
1166             var go = _restParam(function(args) {
1167                 var that = this;
1168                 var callback = args.pop();
1169                 return eachfn(fns, function (fn, _, cb) {
1170                     fn.apply(that, args.concat([cb]));
1171                 },
1172                 callback);
1173             });
1174             if (args.length) {
1175                 return go.apply(this, args);
1176             }
1177             else {
1178                 return go;
1179             }
1180         });
1181     }
1182
1183     async.applyEach = _applyEach(async.eachOf);
1184     async.applyEachSeries = _applyEach(async.eachOfSeries);
1185
1186
1187     async.forever = function (fn, callback) {
1188         var done = only_once(callback || noop);
1189         var task = ensureAsync(fn);
1190         function next(err) {
1191             if (err) {
1192                 return done(err);
1193             }
1194             task(next);
1195         }
1196         next();
1197     };
1198
1199     function ensureAsync(fn) {
1200         return _restParam(function (args) {
1201             var callback = args.pop();
1202             args.push(function () {
1203                 var innerArgs = arguments;
1204                 if (sync) {
1205                     async.setImmediate(function () {
1206                         callback.apply(null, innerArgs);
1207                     });
1208                 } else {
1209                     callback.apply(null, innerArgs);
1210                 }
1211             });
1212             var sync = true;
1213             fn.apply(this, args);
1214             sync = false;
1215         });
1216     }
1217
1218     async.ensureAsync = ensureAsync;
1219
1220     async.constant = _restParam(function(values) {
1221         var args = [null].concat(values);
1222         return function (callback) {
1223             return callback.apply(this, args);
1224         };
1225     });
1226
1227     async.wrapSync =
1228     async.asyncify = function asyncify(func) {
1229         return _restParam(function (args) {
1230             var callback = args.pop();
1231             var result;
1232             try {
1233                 result = func.apply(this, args);
1234             } catch (e) {
1235                 return callback(e);
1236             }
1237             // if result is Promise object
1238             if (_isObject(result) && typeof result.then === "function") {
1239                 result.then(function(value) {
1240                     callback(null, value);
1241                 })["catch"](function(err) {
1242                     callback(err.message ? err : new Error(err));
1243                 });
1244             } else {
1245                 callback(null, result);
1246             }
1247         });
1248     };
1249
1250     // Node.js
1251     if (typeof module === 'object' && module.exports) {
1252         module.exports = async;
1253     }
1254     // AMD / RequireJS
1255     else if (typeof define === 'function' && define.amd) {
1256         define([], function () {
1257             return async;
1258         });
1259     }
1260     // included directly via <script> tag
1261     else {
1262         root.async = async;
1263     }
1264
1265 }());