blob: 07ffd84237c40eb49801f4aed24adc35f2454ad1 [file] [log] [blame]
/*!
* async
* https://github.com/caolan/async
*
* Copyright 2010-2014 Caolan McMahon
* Released under the MIT license
*/
(function () {
var async = {};
function noop() {}
// global on the server, window in the browser
var root, previous_async;
if (typeof window == 'object' && this === window) {
root = window;
}
else if (typeof global == 'object' && this === global) {
root = global;
}
else {
root = this;
}
if (root != null) {
previous_async = root.async;
}
async.noConflict = function () {
root.async = previous_async;
return async;
};
function only_once(fn) {
var called = false;
return function() {
if (called) throw new Error("Callback was already called.");
called = true;
fn.apply(this, arguments);
};
}
function _once(fn) {
var called = false;
return function() {
if (called) return;
called = true;
fn.apply(this, arguments);
};
}
//// cross-browser compatiblity functions ////
var _toString = Object.prototype.toString;
var _isArray = Array.isArray || function (obj) {
return _toString.call(obj) === '[object Array]';
};
function _isArrayLike(arr) {
return _isArray(arr) || (
// has a positive integer length property
typeof arr.length === "number" &&
arr.length >= 0 &&
arr.length % 1 === 0
);
}
function _each(coll, iterator) {
return _isArrayLike(coll) ?
_arrayEach(coll, iterator) :
_forEachOf(coll, iterator);
}
function _arrayEach(arr, iterator) {
var index = -1,
length = arr.length;
while (++index < length) {
iterator(arr[index], index, arr);
}
}
function _map(arr, iterator) {
var index = -1,
length = arr.length,
result = Array(length);
while (++index < length) {
result[index] = iterator(arr[index], index, arr);
}
return result;
}
function _range(count) {
return _map(Array(count), function (v, i) { return i; });
}
function _reduce(arr, iterator, memo) {
_arrayEach(arr, function (x, i, a) {
memo = iterator(memo, x, i, a);
});
return memo;
}
function _forEachOf(object, iterator) {
_arrayEach(_keys(object), function (key) {
iterator(object[key], key);
});
}
var _keys = Object.keys || function (obj) {
var keys = [];
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
keys.push(k);
}
}
return keys;
};
function _keyIterator(coll) {
var i = -1;
var len;
var keys;
if (_isArrayLike(coll)) {
len = coll.length;
return function next() {
i++;
return i < len ? i : null;
};
} else {
keys = _keys(coll);
len = keys.length;
return function next() {
i++;
return i < len ? keys[i] : null;
};
}
}
function _baseSlice(arr, start) {
start = start || 0;
var index = -1;
var length = arr.length;
if (start) {
length -= start;
length = length < 0 ? 0 : length;
}
var result = Array(length);
while (++index < length) {
result[index] = arr[index + start];
}
return result;
}
function _withoutIndex(iterator) {
return function (value, index, callback) {
return iterator(value, callback);
};
}
//// exported async module functions ////
//// nextTick implementation with browser-compatible fallback ////
// capture the global reference to guard against fakeTimer mocks
var _setImmediate;
if (typeof setImmediate === 'function') {
_setImmediate = setImmediate;
}
if (typeof process === 'undefined' || !(process.nextTick)) {
if (_setImmediate) {
async.nextTick = function (fn) {
// not a direct alias for IE10 compatibility
_setImmediate(fn);
};
async.setImmediate = async.nextTick;
}
else {
async.nextTick = function (fn) {
setTimeout(fn, 0);
};
async.setImmediate = async.nextTick;
}
}
else {
async.nextTick = process.nextTick;
if (_setImmediate) {
async.setImmediate = function (fn) {
// not a direct alias for IE10 compatibility
_setImmediate(fn);
};
}
else {
async.setImmediate = async.nextTick;
}
}
async.forEach =
async.each = function (arr, iterator, callback) {
return async.eachOf(arr, _withoutIndex(iterator), callback);
};
async.forEachSeries =
async.eachSeries = function (arr, iterator, callback) {
return async.eachOfSeries(arr, _withoutIndex(iterator), callback);
};
async.forEachLimit =
async.eachLimit = function (arr, limit, iterator, callback) {
return _eachOfLimit(limit)(arr, _withoutIndex(iterator), callback);
};
async.forEachOf =
async.eachOf = function (object, iterator, callback) {
callback = _once(callback || noop);
object = object || [];
var size = _isArrayLike(object) ? object.length : _keys(object).length;
var completed = 0;
if (!size) {
return callback(null);
}
_each(object, function (value, key) {
iterator(object[key], key, only_once(done));
});
function done(err) {
if (err) {
callback(err);
}
else {
completed += 1;
if (completed >= size) {
callback(null);
}
}
}
};
async.forEachOfSeries =
async.eachOfSeries = function (obj, iterator, callback) {
callback = _once(callback || noop);
obj = obj || [];
var nextKey = _keyIterator(obj);
var key = nextKey();
function iterate() {
var sync = true;
if (key === null) {
return callback(null);
}
iterator(obj[key], key, only_once(function (err) {
if (err) {
callback(err);
}
else {
key = nextKey();
if (key === null) {
return callback(null);
} else {
if (sync) {
async.nextTick(iterate);
} else {
iterate();
}
}
}
}));
sync = false;
}
iterate();
};
async.forEachOfLimit =
async.eachOfLimit = function (obj, limit, iterator, callback) {
_eachOfLimit(limit)(obj, iterator, callback);
};
function _eachOfLimit(limit) {
return function (obj, iterator, callback) {
callback = _once(callback || noop);
obj = obj || [];
var nextKey = _keyIterator(obj);
if (limit <= 0) {
return callback(null);
}
var done = false;
var running = 0;
var errored = false;
(function replenish () {
if (done && running <= 0) {
return callback(null);
}
while (running < limit && !errored) {
var key = nextKey();
if (key === null) {
done = true;
if (running <= 0) {
callback(null);
}
return;
}
running += 1;
iterator(obj[key], key, only_once(function (err) {
running -= 1;
if (err) {
callback(err);
errored = true;
}
else {
replenish();
}
}));
}
})();
};
}
function doParallel(fn) {
return function (obj, iterator, callback) {
return fn(async.eachOf, obj, iterator, callback);
};
}
function doParallelLimit(limit, fn) {
return function (obj, iterator, callback) {
return fn(_eachOfLimit(limit), obj, iterator, callback);
};
}
function doSeries(fn) {
return function (obj, iterator, callback) {
return fn(async.eachOfSeries, obj, iterator, callback);
};
}
function _asyncMap(eachfn, arr, iterator, callback) {
callback = _once(callback || noop);
var results = [];
eachfn(arr, function (value, index, callback) {
iterator(value, function (err, v) {
results[index] = v;
callback(err);
});
}, function (err) {
callback(err, results);
});
}
async.map = doParallel(_asyncMap);
async.mapSeries = doSeries(_asyncMap);
async.mapLimit = function (arr, limit, iterator, callback) {
return _mapLimit(limit)(arr, iterator, callback);
};
function _mapLimit(limit) {
return doParallelLimit(limit, _asyncMap);
}
// reduce only has a series version, as doing reduce in parallel won't
// work in many situations.
async.inject =
async.foldl =
async.reduce = function (arr, memo, iterator, callback) {
async.eachOfSeries(arr, function (x, i, callback) {
iterator(memo, x, function (err, v) {
memo = v;
callback(err);
});
}, function (err) {
callback(err || null, memo);
});
};
async.foldr =
async.reduceRight = function (arr, memo, iterator, callback) {
var reversed = _map(arr, function (x) {
return x;
}).reverse();
async.reduce(reversed, memo, iterator, callback);
};
function _filter(eachfn, arr, iterator, callback) {
var results = [];
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
eachfn(arr, function (x, index, callback) {
iterator(x.value, function (v) {
if (v) {
results.push(x);
}
callback();
});
}, function () {
callback(_map(results.sort(function (a, b) {
return a.index - b.index;
}), function (x) {
return x.value;
}));
});
}
async.select =
async.filter = doParallel(_filter);
async.selectSeries =
async.filterSeries = doSeries(_filter);
function _reject(eachfn, arr, iterator, callback) {
var results = [];
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
eachfn(arr, function (x, index, callback) {
iterator(x.value, function (v) {
if (!v) {
results.push(x);
}
callback();
});
}, function () {
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);
function _detect(eachfn, arr, iterator, main_callback) {
eachfn(arr, function (x, index, callback) {
iterator(x, function (result) {
if (result) {
main_callback(x);
main_callback = noop;
}
else {
callback();
}
});
}, function () {
main_callback();
});
}
async.detect = doParallel(_detect);
async.detectSeries = doSeries(_detect);
async.any =
async.some = function (arr, iterator, main_callback) {
async.eachOf(arr, function (x, _, callback) {
iterator(x, function (v) {
if (v) {
main_callback(true);
main_callback = noop;
}
callback();
});
}, function () {
main_callback(false);
});
};
async.all =
async.every = function (arr, iterator, main_callback) {
async.eachOf(arr, function (x, _, callback) {
iterator(x, function (v) {
if (!v) {
main_callback(false);
main_callback = noop;
}
callback();
});
}, function () {
main_callback(true);
});
};
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 {
callback(null, _map(results.sort(comparator), function (x) {
return x.value;
}));
}
});
function comparator(left, right) {
var a = left.criteria, b = right.criteria;
return a < b ? -1 : a > b ? 1 : 0;
}
};
async.auto = function (tasks, callback) {
callback = _once(callback || noop);
var keys = _keys(tasks);
var remainingTasks = keys.length;
if (!remainingTasks) {
return callback(null);
}
var results = {};
var listeners = [];
function addListener(fn) {
listeners.unshift(fn);
}
function removeListener(fn) {
for (var i = 0; i < listeners.length; i += 1) {
if (listeners[i] === fn) {
listeners.splice(i, 1);
return;
}
}
}
function taskComplete() {
remainingTasks--;
_arrayEach(listeners.slice(0), function (fn) {
fn();
});
}
addListener(function () {
if (!remainingTasks) {
callback(null, results);
}
});
_arrayEach(keys, function (k) {
var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]];
function taskCallback(err) {
var args = _baseSlice(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
if (err) {
var safeResults = {};
_arrayEach(_keys(results), function(rkey) {
safeResults[rkey] = results[rkey];
});
safeResults[k] = args;
callback(err, safeResults);
}
else {
results[k] = args;
async.setImmediate(taskComplete);
}
}
var requires = task.slice(0, Math.abs(task.length - 1)) || [];
// prevent dead-locks
var len = requires.length;
var dep;
while (len--) {
if (!(dep = tasks[requires[len]])) {
throw new Error('Has inexistant dependency');
}
if (_isArray(dep) && !!~dep.indexOf(k)) {
throw new Error('Has cyclic dependencies');
}
}
function ready() {
return _reduce(requires, function (a, x) {
return (a && results.hasOwnProperty(x));
}, true) && !results.hasOwnProperty(k);
}
if (ready()) {
task[task.length - 1](taskCallback, results);
}
else {
addListener(listener);
}
function listener() {
if (ready()) {
removeListener(listener);
task[task.length - 1](taskCallback, results);
}
}
});
};
async.retry = function(times, task, callback) {
var DEFAULT_TIMES = 5;
var attempts = [];
// Use defaults if times not passed
if (typeof times === 'function') {
callback = task;
task = times;
times = DEFAULT_TIMES;
}
// Make sure times is a number
times = parseInt(times, 10) || DEFAULT_TIMES;
function wrappedTask(wrappedCallback, wrappedResults) {
function retryAttempt(task, finalAttempt) {
return function(seriesCallback) {
task(function(err, result){
seriesCallback(!err || finalAttempt, {err: err, result: result});
}, wrappedResults);
};
}
while (times) {
attempts.push(retryAttempt(task, !(times-=1)));
}
async.series(attempts, function(done, data){
data = data[data.length - 1];
(wrappedCallback || callback)(data.err, data.result);
});
}
// If a callback is passed, run this as a controll flow
return callback ? wrappedTask() : wrappedTask;
};
async.waterfall = function (tasks, callback) {
callback = _once(callback || noop);
if (!_isArray(tasks)) {
var err = new Error('First argument to waterfall must be an array of functions');
return callback(err);
}
if (!tasks.length) {
return callback();
}
function wrapIterator(iterator) {
return function (err) {
if (err) {
callback.apply(null, arguments);
}
else {
var args = _baseSlice(arguments, 1);
var next = iterator.next();
if (next) {
args.push(wrapIterator(next));
}
else {
args.push(callback);
}
ensureAsync(iterator).apply(null, args);
}
};
}
wrapIterator(async.iterator(tasks))();
};
function _parallel(eachfn, tasks, callback) {
callback = callback || noop;
var results = _isArrayLike(tasks) ? [] : {};
eachfn(tasks, function (task, key, callback) {
task(function (err) {
var args = _baseSlice(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
results[key] = args;
callback(err);
});
}, function (err) {
callback(err, results);
});
}
async.parallel = function (tasks, callback) {
_parallel(async.eachOf, tasks, callback);
};
async.parallelLimit = function(tasks, limit, callback) {
_parallel(_eachOfLimit(limit), tasks, callback);
};
async.series = function (tasks, callback) {
callback = callback || noop;
var results = _isArrayLike(tasks) ? [] : {};
async.eachOfSeries(tasks, function (task, key, callback) {
task(function (err) {
var args = _baseSlice(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
results[key] = args;
callback(err);
});
}, function (err) {
callback(err, results);
});
};
async.iterator = function (tasks) {
function makeCallback(index) {
function fn() {
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 = _baseSlice(arguments, 1);
return function () {
return fn.apply(
null, args.concat(_baseSlice(arguments))
);
};
};
function _concat(eachfn, arr, fn, callback) {
var result = [];
eachfn(arr, function (x, index, cb) {
fn(x, function (err, y) {
result = result.concat(y || []);
cb(err);
});
}, function (err) {
callback(err, result);
});
}
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(null);
}
};
async.doWhilst = function (iterator, test, callback) {
iterator(function (err) {
if (err) {
return callback(err);
}
var args = _baseSlice(arguments, 1);
if (test.apply(null, args)) {
async.doWhilst(iterator, test, callback);
}
else {
callback(null);
}
});
};
async.until = function (test, iterator, callback) {
if (!test()) {
iterator(function (err) {
if (err) {
return callback(err);
}
async.until(test, iterator, callback);
});
}
else {
callback(null);
}
};
async.doUntil = function (iterator, test, callback) {
iterator(function (err) {
if (err) {
return callback(err);
}
var args = _baseSlice(arguments, 1);
if (!test.apply(null, args)) {
async.doUntil(iterator, test, callback);
}
else {
callback(null);
}
});
};
function _queue(worker, concurrency, payload) {
if (concurrency == null) {
concurrency = 1;
}
else if(concurrency === 0) {
throw new Error('Concurrency must not be zero');
}
function _insert(q, data, pos, callback) {
if (callback != null && typeof callback !== "function") {
throw new Error("task callback must be a function");
}
q.started = true;
if (!_isArray(data)) {
data = [data];
}
if(data.length === 0 && q.idle()) {
// call drain immediately if there are no tasks
return async.setImmediate(function() {
q.drain();
});
}
_arrayEach(data, function(task) {
var item = {
data: task,
callback: callback || noop
};
if (pos) {
q.tasks.unshift(item);
} else {
q.tasks.push(item);
}
if (q.tasks.length === q.concurrency) {
q.saturated();
}
});
async.setImmediate(q.process);
}
function _next(q, tasks) {
return function(){
workers -= 1;
var args = arguments;
_arrayEach(tasks, function (task) {
task.callback.apply(task, args);
});
if (q.tasks.length + workers === 0) {
q.drain();
}
q.process();
};
}
var workers = 0;
var q = {
tasks: [],
concurrency: concurrency,
saturated: noop,
empty: noop,
drain: noop,
started: false,
paused: false,
push: function (data, callback) {
_insert(q, data, false, callback);
},
kill: function () {
q.drain = noop;
q.tasks = [];
},
unshift: function (data, callback) {
_insert(q, data, true, callback);
},
process: function () {
if (!q.paused && workers < q.concurrency && q.tasks.length) {
while(workers < q.concurrency && q.tasks.length){
var tasks = payload ?
q.tasks.splice(0, payload) :
q.tasks.splice(0, q.tasks.length);
var data = _map(tasks, function (task) {
return task.data;
});
if (q.tasks.length === 0) {
q.empty();
}
workers += 1;
var cb = only_once(_next(q, tasks));
worker(data, cb);
}
}
},
length: function () {
return q.tasks.length;
},
running: function () {
return workers;
},
idle: function() {
return q.tasks.length + workers === 0;
},
pause: function () {
q.paused = true;
},
resume: function () {
if (q.paused === false) { return; }
q.paused = false;
var resumeCount = Math.min(q.concurrency, q.tasks.length);
// Need to call q.process once per concurrent
// worker to preserve full concurrency after pause
for (var w = 1; w <= resumeCount; w++) {
async.setImmediate(q.process);
}
}
};
return q;
}
async.queue = function (worker, concurrency) {
var q = _queue(function (items, cb) {
worker(items[0], cb);
}, concurrency, 1);
return q;
};
async.priorityQueue = function (worker, concurrency) {
function _compareTasks(a, b){
return a.priority - b.priority;
}
function _binarySearch(sequence, item, compare) {
var beg = -1,
end = sequence.length - 1;
while (beg < end) {
var mid = beg + ((end - beg + 1) >>> 1);
if (compare(item, sequence[mid]) >= 0) {
beg = mid;
} else {
end = mid - 1;
}
}
return beg;
}
function _insert(q, data, priority, callback) {
if (callback != null && typeof callback !== "function") {
throw new Error("task callback must be a function");
}
q.started = true;
if (!_isArray(data)) {
data = [data];
}
if(data.length === 0) {
// call drain immediately if there are no tasks
return async.setImmediate(function() {
q.drain();
});
}
_arrayEach(data, function(task) {
var item = {
data: task,
priority: priority,
callback: typeof callback === 'function' ? callback : noop
};
q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item);
if (q.tasks.length === q.concurrency) {
q.saturated();
}
async.setImmediate(q.process);
});
}
// Start with a normal queue
var q = async.queue(worker, concurrency);
// Override push to accept second parameter representing priority
q.push = function (data, priority, callback) {
_insert(q, data, priority, callback);
};
// Remove unshift function
delete q.unshift;
return q;
};
async.cargo = function (worker, payload) {
return _queue(worker, 1, payload);
};
function _console_fn(name) {
return function (fn) {
var args = _baseSlice(arguments, 1);
fn.apply(null, args.concat([function (err) {
var args = _baseSlice(arguments, 1);
if (typeof console !== 'undefined') {
if (err) {
if (console.error) {
console.error(err);
}
}
else if (console[name]) {
_arrayEach(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;
};
function memoized() {
var args = _baseSlice(arguments);
var callback = args.pop();
var key = hasher.apply(null, args);
if (key in memo) {
async.nextTick(function () {
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] = _baseSlice(arguments);
var q = queues[key];
delete queues[key];
for (var i = 0, l = q.length; i < l; i++) {
q[i].apply(null, arguments);
}
}]));
}
}
memoized.memo = memo;
memoized.unmemoized = fn;
return memoized;
};
async.unmemoize = function (fn) {
return function () {
return (fn.unmemoized || fn).apply(null, arguments);
};
};
function _times(mapper) {
return function (count, iterator, callback) {
mapper(_range(count), iterator, callback);
};
}
async.times = _times(async.map);
async.timesSeries = _times(async.mapSeries);
async.timesLimit = function (count, limit, iterator, callback) {
return async.mapLimit(_range(count), limit, iterator, callback);
};
async.seq = function (/* functions... */) {
var fns = arguments;
return function () {
var that = this;
var args = _baseSlice(arguments);
var callback = args.slice(-1)[0];
if (typeof callback == 'function') {
args.pop();
} else {
callback = noop;
}
async.reduce(fns, args, function (newargs, fn, cb) {
fn.apply(that, newargs.concat([function () {
var err = arguments[0];
var nextargs = _baseSlice(arguments, 1);
cb(err, nextargs);
}]));
},
function (err, results) {
callback.apply(that, [err].concat(results));
});
};
};
async.compose = function (/* functions... */) {
return async.seq.apply(null, Array.prototype.reverse.call(arguments));
};
function _applyEach(eachfn, fns /*args...*/) {
function go() {
var that = this;
var args = _baseSlice(arguments);
var callback = args.pop();
return eachfn(fns, function (fn, _, cb) {
fn.apply(that, args.concat([cb]));
},
callback);
}
if (arguments.length > 2) {
var args = _baseSlice(arguments, 2);
return go.apply(this, args);
}
else {
return go;
}
}
async.applyEach = function (/*fns, args...*/) {
var args = _baseSlice(arguments);
return _applyEach.apply(null, [async.eachOf].concat(args));
};
async.applyEachSeries = function (/*fns, args...*/) {
var args = _baseSlice(arguments);
return _applyEach.apply(null, [async.eachOfSeries].concat(args));
};
async.forever = function (fn, callback) {
var done = only_once(callback || noop);
var task = ensureAsync(fn);
function next(err) {
if (err) {
return done(err);
}
task(next);
}
next();
};
function ensureAsync(fn) {
return function (/*...args, callback*/) {
var args = _baseSlice(arguments);
var callback = args.pop();
args.push(function () {
var innerArgs = arguments;
if (sync) {
async.setImmediate(function () {
callback.apply(null, innerArgs);
});
} else {
callback.apply(null, innerArgs);
}
});
var sync = true;
fn.apply(this, args);
sync = false;
};
}
async.ensureAsync = ensureAsync;
// Node.js
if (typeof module !== 'undefined' && module.exports) {
module.exports = async;
}
// AMD / RequireJS
else if (typeof define !== 'undefined' && define.amd) {
define([], function () {
return async;
});
}
// included directly via <script> tag
else {
root.async = async;
}
}());