diff options
Diffstat (limited to 'build/async.js')
-rw-r--r-- | build/async.js | 1838 |
1 files changed, 919 insertions, 919 deletions
diff --git a/build/async.js b/build/async.js index 84513d7..e5d60e3 100644 --- a/build/async.js +++ b/build/async.js @@ -1,10 +1,31 @@ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : - factory((global.async = {})); + (factory((global.async = {}))); }(this, function (exports) { 'use strict'; /** + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. + * + * @private + * @param {Function} func The function to invoke. + * @param {*} thisArg The `this` binding of `func`. + * @param {...*} [args] The arguments to invoke `func` with. + * @returns {*} Returns the result of `func`. + */ + function apply$1(func, thisArg, args) { + var length = args ? args.length : 0; + switch (length) { + case 0: return func.call(thisArg); + case 1: return func.call(thisArg, args[0]); + case 2: return func.call(thisArg, args[0], args[1]); + case 3: return func.call(thisArg, args[0], args[1], args[2]); + } + return func.apply(thisArg, args); + } + + /** * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * @@ -34,27 +55,6 @@ return !!value && (type == 'object' || type == 'function'); } - /** - * A faster alternative to `Function#apply`, this function invokes `func` - * with the `this` binding of `thisArg` and the arguments of `args`. - * - * @private - * @param {Function} func The function to invoke. - * @param {*} thisArg The `this` binding of `func`. - * @param {...*} [args] The arguments to invoke `func` with. - * @returns {*} Returns the result of `func`. - */ - function apply$1(func, thisArg, args) { - var length = args ? args.length : 0; - switch (length) { - case 0: return func.call(thisArg); - case 1: return func.call(thisArg, args[0]); - case 2: return func.call(thisArg, args[0], args[1]); - case 3: return func.call(thisArg, args[0], args[1], args[2]); - } - return func.apply(thisArg, args); - } - var funcTag = '[object Function]'; var genTag = '[object GeneratorFunction]'; /** Used for built-in method references. */ @@ -241,77 +241,23 @@ }; } - function asyncify(func) { - return rest(function (args) { - var callback = args.pop(); - var result; - try { - result = func.apply(this, args); - } catch (e) { - return callback(e); - } - // if result is Promise object - if (isObject(result) && typeof result.then === 'function') { - result.then(function (value) { - callback(null, value); - })['catch'](function (err) { - callback(err.message ? err : new Error(err)); - }); + function applyEach$1(eachfn) { + return rest(function (fns, args) { + var go = rest(function (args) { + var that = this; + var callback = args.pop(); + return eachfn(fns, function (fn, _, cb) { + fn.apply(that, args.concat([cb])); + }, callback); + }); + if (args.length) { + return go.apply(this, args); } else { - callback(null, result); + return go; } }); } - /** - * A specialized version of `_.map` for arrays without support for iteratee - * shorthands. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ - function arrayMap(array, iteratee) { - var index = -1, - length = array.length, - result = Array(length); - - while (++index < length) { - result[index] = iteratee(array[index], index, array); - } - return result; - } - - /** - * The base implementation of `_.property` without support for deep paths. - * - * @private - * @param {string} key The key of the property to get. - * @returns {Function} Returns the new function. - */ - function baseProperty(key) { - return function(object) { - return object == null ? undefined : object[key]; - }; - } - - function _filter(eachfn, arr, iterator, callback) { - var results = []; - eachfn(arr, function (x, index, callback) { - iterator(x, function (v) { - if (v) { - results.push({ index: index, value: x }); - } - callback(); - }); - }, function () { - callback(arrayMap(results.sort(function (a, b) { - return a.index - b.index; - }), baseProperty('value'))); - }); - } - /** Used as the `TypeError` message for "Functions" methods. */ var FUNC_ERROR_TEXT$1 = 'Expected a function'; @@ -388,6 +334,19 @@ } /** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new function. + */ + function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; + } + + /** * Gets the "length" property value of `object`. * * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) @@ -799,6 +758,36 @@ }; } + function eachOf(object, iterator, callback) { + callback = once(callback || noop); + object = object || []; + + var iter = keyIterator(object); + var key, + completed = 0; + + while ((key = iter()) != null) { + completed += 1; + iterator(object[key], key, onlyOnce(done)); + } + + if (completed === 0) callback(null); + + function done(err) { + completed--; + if (err) { + callback(err); + } + // Check key is null in case iterator isn't exhausted + // and done resolved synchronously. + else if (key === null && completed <= 0) { + callback(null); + } + } + } + + var applyEach = applyEach$1(eachOf); + var _setImmediate = typeof setImmediate === 'function' && setImmediate; var _delay; @@ -849,137 +838,126 @@ iterate(); } - function doSeries(fn) { - return function (obj, iterator, callback) { - return fn(eachOfSeries, obj, iterator, callback); - }; - } + var applyEachSeries = applyEach$1(eachOfSeries); - var filterSeries = doSeries(_filter); + var apply = rest(function (fn, args) { + return rest(function (callArgs) { + return fn.apply(null, args.concat(callArgs)); + }); + }); - function _eachOfLimit(limit) { - return function (obj, iterator, callback) { - callback = once(callback || noop); - obj = obj || []; - var nextKey = keyIterator(obj); - if (limit <= 0) { - return callback(null); + function asyncify(func) { + return rest(function (args) { + var callback = args.pop(); + var result; + try { + result = func.apply(this, args); + } catch (e) { + return callback(e); } - 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, onlyOnce(function (err) { - running -= 1; - if (err) { - callback(err); - errored = true; - } else { - replenish(); - } - })); - } - })(); - }; - } - - function doParallelLimit(fn) { - return function (obj, limit, iterator, callback) { - return fn(_eachOfLimit(limit), obj, iterator, callback); - }; - } - - var filterLimit = doParallelLimit(_filter); - - function eachOf(object, iterator, callback) { - callback = once(callback || noop); - object = object || []; - - var iter = keyIterator(object); - var key, - completed = 0; - - while ((key = iter()) != null) { - completed += 1; - iterator(object[key], key, onlyOnce(done)); - } - - if (completed === 0) callback(null); - - function done(err) { - completed--; - if (err) { - callback(err); + // if result is Promise object + if (isObject(result) && typeof result.then === 'function') { + result.then(function (value) { + callback(null, value); + })['catch'](function (err) { + callback(err.message ? err : new Error(err)); + }); + } else { + callback(null, result); } - // Check key is null in case iterator isn't exhausted - // and done resolved synchronously. - else if (key === null && completed <= 0) { - callback(null); - } - } - } - - function doParallel(fn) { - return function (obj, iterator, callback) { - return fn(eachOf, obj, iterator, callback); - }; - } - - var filter = doParallel(_filter); - - function reduce(arr, memo, iterator, cb) { - eachOfSeries(arr, function (x, i, cb) { - iterator(memo, x, function (err, v) { - memo = v; - cb(err); - }); - }, function (err) { - cb(err, memo); }); } - var slice = Array.prototype.slice; + /** + * A specialized version of `_.forEach` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ + function arrayEach(array, iteratee) { + var index = -1, + length = array.length; - function reduceRight(arr, memo, iterator, cb) { - var reversed = slice.call(arr).reverse(); - reduce(reversed, memo, iterator, cb); + while (++index < length) { + if (iteratee(array[index], index, array) === false) { + break; + } + } + return array; } - function eachOfLimit(obj, limit, iterator, cb) { - _eachOfLimit(limit)(obj, iterator, cb); - } + /** + * A specialized version of `_.every` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, else `false`. + */ + function arrayEvery(array, predicate) { + var index = -1, + length = array.length; - function _withoutIndex(iterator) { - return function (value, index, callback) { - return iterator(value, callback); - }; + while (++index < length) { + if (!predicate(array[index], index, array)) { + return false; + } + } + return true; } - function eachLimit(arr, limit, iterator, cb) { - return _eachOfLimit(limit)(arr, _withoutIndex(iterator), cb); - } + /** + * Creates a base function for methods like `_.forIn`. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ + function createBaseFor(fromRight) { + return function(object, iteratee, keysFunc) { + var index = -1, + iterable = Object(object), + props = keysFunc(object), + length = props.length; - function eachSeries(arr, iterator, cb) { - return eachOfSeries(arr, _withoutIndex(iterator), cb); + while (length--) { + var key = props[fromRight ? length : ++index]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; + }; } - function each(arr, iterator, cb) { - return eachOf(arr, _withoutIndex(iterator), cb); + /** + * The base implementation of `baseForIn` and `baseForOwn` which iterates + * over `object` properties returned by `keysFunc` invoking `iteratee` for + * each property. Iteratee functions may exit iteration early by explicitly + * returning `false`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ + var baseFor = createBaseFor(); + + /** + * The base implementation of `_.forOwn` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForOwn(object, iteratee) { + return object && baseFor(object, iteratee, keys); } /** @@ -1001,362 +979,241 @@ return value; } - function _createTester(eachfn, check, getResult) { - return function (arr, limit, iterator, cb) { - function done() { - if (cb) cb(getResult(false, void 0)); - } - function iteratee(x, _, callback) { - if (!cb) return callback(); - iterator(x, function (v) { - if (cb && check(v)) { - cb(getResult(true, x)); - cb = iterator = false; - } - callback(); - }); - } - if (arguments.length > 3) { - eachfn(arr, limit, iteratee, done); - } else { - cb = iterator; - iterator = limit; - eachfn(arr, iteratee, done); - } - }; - } - - var some = _createTester(eachOf, Boolean, identity); - - function notId(v) { - return !v; - } - - var every = _createTester(eachOf, notId, notId); - - function whilst(test, iterator, cb) { - cb = cb || noop; - if (!test()) return cb(null); - var next = rest(function (err, args) { - if (err) return cb(err); - if (test.apply(this, args)) return iterator(next); - cb.apply(null, [null].concat(args)); - }); - iterator(next); - } - - function ensureAsync(fn) { - return rest(function (args) { - var callback = args.pop(); - var sync = true; - args.push(function () { - var innerArgs = arguments; - if (sync) { - setImmediate$1(function () { - callback.apply(null, innerArgs); - }); - } else { - callback.apply(null, innerArgs); - } - }); - fn.apply(this, args); - sync = false; - }); - } - - function iterator (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); - } - - function waterfall (tasks, cb) { - cb = once(cb || noop); - if (!isArray(tasks)) return cb(new Error('First argument to waterfall must be an array of functions')); - if (!tasks.length) return cb(); - - function wrapIterator(iterator) { - return rest(function (err, args) { - if (err) { - cb.apply(null, [err].concat(args)); - } else { - var next = iterator.next(); - if (next) { - args.push(wrapIterator(next)); - } else { - args.push(cb); - } - ensureAsync(iterator).apply(null, args); - } - }); - } - wrapIterator(iterator(tasks))(); + /** + * Converts `value` to a function if it's not one. + * + * @private + * @param {*} value The value to process. + * @returns {Function} Returns the function. + */ + function toFunction(value) { + return typeof value == 'function' ? value : identity; } - function until(test, iterator, cb) { - return whilst(function () { - return !test.apply(this, arguments); - }, iterator, cb); + /** + * Iterates over own enumerable properties of an object invoking `iteratee` + * for each property. The iteratee is invoked with three arguments: + * (value, key, object). Iteratee functions may exit iteration early by + * explicitly returning `false`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forOwn(new Foo, function(value, key) { + * console.log(key); + * }); + * // => logs 'a' then 'b' (iteration order is not guaranteed) + */ + function forOwn(object, iteratee) { + return object && baseForOwn(object, toFunction(iteratee)); } - function unmemoize(fn) { - return function () { - return (fn.unmemoized || fn).apply(null, arguments); - }; - } + /** + * Gets the index at which the first occurrence of `NaN` is found in `array`. + * + * @private + * @param {Array} array The array to search. + * @param {number} fromIndex The index to search from. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {number} Returns the index of the matched `NaN`, else `-1`. + */ + function indexOfNaN(array, fromIndex, fromRight) { + var length = array.length, + index = fromIndex + (fromRight ? 0 : -1); - function transform(arr, memo, iterator, callback) { - if (arguments.length === 3) { - callback = iterator; - iterator = memo; - memo = isArray(arr) ? [] : {}; + while ((fromRight ? index-- : ++index < length)) { + var other = array[index]; + if (other !== other) { + return index; } - - eachOf(arr, function (v, k, cb) { - iterator(memo, v, k, cb); - }, function (err) { - callback(err, memo); - }); - } - - function _asyncMap(eachfn, arr, iterator, callback) { - callback = once(callback || noop); - arr = arr || []; - var results = isArrayLike(arr) ? [] : {}; - eachfn(arr, function (value, index, callback) { - iterator(value, function (err, v) { - results[index] = v; - callback(err); - }); - }, function (err) { - callback(err, results); - }); + } + return -1; } - var mapSeries = doSeries(_asyncMap); - - /* Built-in method references for those with the same name as other `lodash` methods. */ - var nativeCeil = Math.ceil; - var nativeMax$2 = Math.max; /** - * The base implementation of `_.range` and `_.rangeRight` which doesn't - * coerce arguments to numbers. + * The base implementation of `_.indexOf` without `fromIndex` bounds checks. * * @private - * @param {number} start The start of the range. - * @param {number} end The end of the range. - * @param {number} step The value to increment or decrement by. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Array} Returns the new array of numbers. + * @param {Array} array The array to search. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. */ - function baseRange(start, end, step, fromRight) { - var index = -1, - length = nativeMax$2(nativeCeil((end - start) / (step || 1)), 0), - result = Array(length); - - while (length--) { - result[fromRight ? length : ++index] = start; - start += step; + function baseIndexOf(array, value, fromIndex) { + if (value !== value) { + return indexOfNaN(array, fromIndex); } - return result; - } + var index = fromIndex - 1, + length = array.length; - function timesSeries (count, iterator, callback) { - mapSeries(baseRange(0, count, 1), iterator, callback); + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; } - var mapLimit = doParallelLimit(_asyncMap); + /* Built-in method references for those with the same name as other `lodash` methods. */ + var nativeMax$1 = Math.max; - function timeLimit(count, limit, iterator, cb) { - return mapLimit(baseRange(0, count, 1), limit, iterator, cb); + /** + * Gets the index at which the first occurrence of `value` is found in `array` + * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) + * for equality comparisons. If `fromIndex` is negative, it's used as the offset + * from the end of `array`. If `array` is sorted providing `true` for `fromIndex` + * performs a faster binary search. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to search. + * @param {*} value The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.indexOf([1, 2, 1, 2], 2); + * // => 1 + * + * // using `fromIndex` + * _.indexOf([1, 2, 1, 2], 2, 2); + * // => 3 + */ + function indexOf(array, value, fromIndex) { + var length = array ? array.length : 0; + if (!length) { + return -1; + } + fromIndex = toInteger(fromIndex); + if (fromIndex < 0) { + fromIndex = nativeMax$1(length + fromIndex, 0); + } + return baseIndexOf(array, value, fromIndex); } - var map = doParallel(_asyncMap); + function auto (tasks, concurrency, callback) { + if (typeof arguments[1] === 'function') { + // concurrency is optional, shift the args. + callback = concurrency; + concurrency = null; + } + callback = once(callback || noop); + var keys$$ = keys(tasks); + var remainingTasks = keys$$.length; + if (!remainingTasks) { + return callback(null); + } + if (!concurrency) { + concurrency = remainingTasks; + } - function times (count, iterator, callback) { - map(baseRange(0, count, 1), iterator, callback); - } + var results = {}; + var runningTasks = 0; - function sortBy(arr, iterator, cb) { - map(arr, function (x, cb) { - iterator(x, function (err, criteria) { - if (err) return cb(err); - cb(null, { value: x, criteria: criteria }); + var listeners = []; + function addListener(fn) { + listeners.unshift(fn); + } + function removeListener(fn) { + var idx = indexOf(listeners, fn); + if (idx >= 0) listeners.splice(idx, 1); + } + function taskComplete() { + remainingTasks--; + arrayEach(listeners.slice(), function (fn) { + fn(); }); - }, function (err, results) { - if (err) return cb(err); - cb(null, arrayMap(results.sort(comparator), baseProperty('value'))); - }); - - function comparator(left, right) { - var a = left.criteria, - b = right.criteria; - return a < b ? -1 : a > b ? 1 : 0; } - } - var someLimit = _createTester(eachOfLimit, Boolean, identity); - - function _parallel(eachfn, tasks, callback) { - callback = callback || noop; - var results = isArrayLike(tasks) ? [] : {}; + addListener(function () { + if (!remainingTasks) { + callback(null, results); + } + }); - eachfn(tasks, function (task, key, callback) { - task(rest(function (err, args) { + arrayEach(keys$$, function (k) { + var task = isArray(tasks[k]) ? tasks[k] : [tasks[k]]; + var taskCallback = rest(function (err, args) { + runningTasks--; if (args.length <= 1) { args = args[0]; } - results[key] = args; - callback(err); - })); - }, function (err) { - callback(err, results); - }); - } - - function series(tasks, cb) { - return _parallel(eachOfSeries, tasks, cb); - } - - function seq() /* functions... */{ - var fns = arguments; - return rest(function (args) { - var that = this; - - var cb = args[args.length - 1]; - if (typeof cb == 'function') { - args.pop(); - } else { - cb = noop; - } - - reduce(fns, args, function (newargs, fn, cb) { - fn.apply(that, newargs.concat([rest(function (err, nextargs) { - cb(err, nextargs); - })])); - }, function (err, results) { - cb.apply(that, [err].concat(results)); + if (err) { + var safeResults = {}; + forOwn(results, function (val, rkey) { + safeResults[rkey] = val; + }); + safeResults[k] = args; + callback(err, safeResults); + } else { + results[k] = args; + setImmediate$1(taskComplete); + } }); - }); - } - - function retry(times, task, callback) { - var DEFAULT_TIMES = 5; - var DEFAULT_INTERVAL = 0; - - var attempts = []; - - var opts = { - times: DEFAULT_TIMES, - interval: DEFAULT_INTERVAL - }; - - function parseTimes(acc, t) { - if (typeof t === 'number') { - acc.times = parseInt(t, 10) || DEFAULT_TIMES; - } else if (typeof t === 'object') { - acc.times = parseInt(t.times, 10) || DEFAULT_TIMES; - acc.interval = parseInt(t.interval, 10) || DEFAULT_INTERVAL; - } else { - throw new Error('Unsupported argument type for \'times\': ' + typeof t); + var requires = task.slice(0, 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) && indexOf(dep, k) >= 0) { + throw new Error('Has cyclic dependencies'); + } } - } - - var length = arguments.length; - if (length < 1 || length > 3) { - throw new Error('Invalid arguments - must be either (task), (task, callback), (times, task) or (times, task, callback)'); - } else if (length <= 2 && typeof times === 'function') { - callback = task; - task = times; - } - if (typeof times !== 'function') { - parseTimes(opts, times); - } - opts.callback = callback; - opts.task = task; - - function wrappedTask(wrappedCallback, wrappedResults) { - function retryAttempt(task, finalAttempt) { - return function (seriesCallback) { - task(function (err, result) { - seriesCallback(!err || finalAttempt, { - err: err, - result: result - }); - }, wrappedResults); - }; + function ready() { + return runningTasks < concurrency && !baseHas(results, k) && arrayEvery(requires, function (x) { + return baseHas(results, x); + }); } - - function retryInterval(interval) { - return function (seriesCallback) { - setTimeout(function () { - seriesCallback(null); - }, interval); - }; + if (ready()) { + runningTasks++; + task[task.length - 1](taskCallback, results); + } else { + addListener(listener); } - - while (opts.times) { - - var finalAttempt = !(opts.times -= 1); - attempts.push(retryAttempt(opts.task, finalAttempt)); - if (!finalAttempt && opts.interval > 0) { - attempts.push(retryInterval(opts.interval)); + function listener() { + if (ready()) { + runningTasks++; + removeListener(listener); + task[task.length - 1](taskCallback, results); } } - - series(attempts, function (done, data) { - data = data[data.length - 1]; - (wrappedCallback || opts.callback)(data.err, data.result); - }); - } - - // If a callback is passed, run this as a controll flow - return opts.callback ? wrappedTask() : wrappedTask; - } - - function reject$1(eachfn, arr, iterator, callback) { - _filter(eachfn, arr, function (value, cb) { - iterator(value, function (v) { - cb(!v); - }); - }, callback); + }); } - var rejectSeries = doSeries(reject$1); - - var rejectLimit = doParallelLimit(reject$1); - - var reject = doParallel(reject$1); - /** - * A specialized version of `_.forEach` for arrays without support for - * iteratee shorthands. + * A specialized version of `_.map` for arrays without support for iteratee + * shorthands. * * @private * @param {Array} array The array to iterate over. * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns `array`. + * @returns {Array} Returns the new mapped array. */ - function arrayEach(array, iteratee) { + function arrayMap(array, iteratee) { var index = -1, - length = array.length; + length = array.length, + result = Array(length); while (++index < length) { - if (iteratee(array[index], index, array) === false) { - break; - } + result[index] = iteratee(array[index], index, array); } - return array; + return result; } function queue$1(worker, concurrency, payload) { @@ -1488,115 +1345,164 @@ return q; } - function queue (worker, concurrency) { - return queue$1(function (items, cb) { - worker(items[0], cb); - }, concurrency, 1); + function cargo(worker, payload) { + return queue$1(worker, 1, payload); } - function priorityQueue (worker, concurrency) { - function _compareTasks(a, b) { - return a.priority - b.priority; - } + function reduce(arr, memo, iterator, cb) { + eachOfSeries(arr, function (x, i, cb) { + iterator(memo, x, function (err, v) { + memo = v; + cb(err); + }); + }, function (err) { + cb(err, memo); + }); + } - 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 seq() /* functions... */{ + var fns = arguments; + return rest(function (args) { + var that = this; - 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 setImmediate$1(function () { - q.drain(); - }); + var cb = args[args.length - 1]; + if (typeof cb == 'function') { + args.pop(); + } else { + cb = noop; } - 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(); - } - setImmediate$1(q.process); + reduce(fns, args, function (newargs, fn, cb) { + fn.apply(that, newargs.concat([rest(function (err, nextargs) { + cb(err, nextargs); + })])); + }, function (err, results) { + cb.apply(that, [err].concat(results)); }); - } - - // Start with a normal queue - var q = queue(worker, concurrency); + }); + } - // Override push to accept second parameter representing priority - q.push = function (data, priority, callback) { - _insert(q, data, priority, callback); - }; + var reverse = Array.prototype.reverse; - // Remove unshift function - delete q.unshift; + function compose() /* functions... */{ + return seq.apply(null, reverse.call(arguments)); + } - return q; + function concat$1(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); + }); } - function parallelLimit(tasks, limit, cb) { - return _parallel(_eachOfLimit(limit), tasks, cb); + function doParallel(fn) { + return function (obj, iterator, callback) { + return fn(eachOf, obj, iterator, callback); + }; } - function parallel(tasks, cb) { - return _parallel(eachOf, tasks, cb); + var concat = doParallel(concat$1); + + function doSeries(fn) { + return function (obj, iterator, callback) { + return fn(eachOfSeries, obj, iterator, callback); + }; } - var nexTick = typeof process === 'object' && typeof process.nextTick === 'function' ? process.nextTick : setImmediate$1; + var concatSeries = doSeries(concat$1); - function memoize(fn, hasher) { - var memo = {}; - var queues = {}; - hasher = hasher || identity; - var memoized = rest(function memoized(args) { - var callback = args.pop(); - var key = hasher.apply(null, args); - if (key in memo) { - setImmediate$1(function () { - callback.apply(null, memo[key]); + var constant = rest(function (values) { + var args = [null].concat(values); + return function (cb) { + return cb.apply(this, args); + }; + }); + + function _createTester(eachfn, check, getResult) { + return function (arr, limit, iterator, cb) { + function done() { + if (cb) cb(getResult(false, void 0)); + } + function iteratee(x, _, callback) { + if (!cb) return callback(); + iterator(x, function (v) { + if (cb && check(v)) { + cb(getResult(true, x)); + cb = iterator = false; + } + callback(); }); - } else if (key in queues) { - queues[key].push(callback); + } + if (arguments.length > 3) { + eachfn(arr, limit, iteratee, done); } else { - queues[key] = [callback]; - fn.apply(null, args.concat([rest(function (args) { - memo[key] = args; - var q = queues[key]; - delete queues[key]; - for (var i = 0, l = q.length; i < l; i++) { - q[i].apply(null, args); - } - })])); + cb = iterator; + iterator = limit; + eachfn(arr, iteratee, done); } - }); - memoized.memo = memo; - memoized.unmemoized = fn; - return memoized; + }; } + function _findGetResult(v, x) { + return x; + } + + var detect = _createTester(eachOf, identity, _findGetResult); + + 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, onlyOnce(function (err) { + running -= 1; + if (err) { + callback(err); + errored = true; + } else { + replenish(); + } + })); + } + })(); + }; + } + + function eachOfLimit(obj, limit, iterator, cb) { + _eachOfLimit(limit)(obj, iterator, cb); + } + + var detectLimit = _createTester(eachOfLimit, identity, _findGetResult); + + var detectSeries = _createTester(eachOfSeries, identity, _findGetResult); + function consoleFunc(name) { return rest(function (fn, args) { fn.apply(null, args.concat([rest(function (err, args) { @@ -1615,20 +1521,7 @@ }); } - var log = consoleFunc('log'); - - function forever(fn, cb) { - var done = onlyOnce(cb || noop); - var task = ensureAsync(fn); - - function next(err) { - if (err) return done(err); - task(next); - } - next(); - } - - var everyLimit = _createTester(eachOfLimit, notId, notId); + var dir = consoleFunc('dir'); function during(test, iterator, cb) { cb = cb || noop; @@ -1651,6 +1544,26 @@ test(check); } + function doDuring(iterator, test, cb) { + var calls = 0; + + during(function (next) { + if (calls++ < 1) return next(null, true); + test.apply(this, arguments); + }, iterator, cb); + } + + function whilst(test, iterator, cb) { + cb = cb || noop; + if (!test()) return cb(null); + var next = rest(function (err, args) { + if (err) return cb(err); + if (test.apply(this, args)) return iterator(next); + cb.apply(null, [null].concat(args)); + }); + iterator(next); + } + function doWhilst(iterator, test, cb) { var calls = 0; return whilst(function () { @@ -1664,374 +1577,461 @@ }, cb); } - function doDuring(iterator, test, cb) { - var calls = 0; + function _withoutIndex(iterator) { + return function (value, index, callback) { + return iterator(value, callback); + }; + } - during(function (next) { - if (calls++ < 1) return next(null, true); - test.apply(this, arguments); - }, iterator, cb); + function each(arr, iterator, cb) { + return eachOf(arr, _withoutIndex(iterator), cb); } - var dir = consoleFunc('dir'); + function eachLimit(arr, limit, iterator, cb) { + return _eachOfLimit(limit)(arr, _withoutIndex(iterator), cb); + } - function _findGetResult(v, x) { - return x; + function eachSeries(arr, iterator, cb) { + return eachOfSeries(arr, _withoutIndex(iterator), cb); } - var detectSeries = _createTester(eachOfSeries, identity, _findGetResult); + function ensureAsync(fn) { + return rest(function (args) { + var callback = args.pop(); + var sync = true; + args.push(function () { + var innerArgs = arguments; + if (sync) { + setImmediate$1(function () { + callback.apply(null, innerArgs); + }); + } else { + callback.apply(null, innerArgs); + } + }); + fn.apply(this, args); + sync = false; + }); + } - var detectLimit = _createTester(eachOfLimit, identity, _findGetResult); + function notId(v) { + return !v; + } - var detect = _createTester(eachOf, identity, _findGetResult); + var every = _createTester(eachOf, notId, notId); - var constant = rest(function (values) { - var args = [null].concat(values); - return function (cb) { - return cb.apply(this, args); - }; - }); + var everyLimit = _createTester(eachOfLimit, notId, notId); - function concat$1(eachfn, arr, fn, callback) { - var result = []; - eachfn(arr, function (x, index, cb) { - fn(x, function (err, y) { - result = result.concat(y || []); - cb(err); + function _filter(eachfn, arr, iterator, callback) { + var results = []; + eachfn(arr, function (x, index, callback) { + iterator(x, function (v) { + if (v) { + results.push({ index: index, value: x }); + } + callback(); }); - }, function (err) { - callback(err, result); + }, function () { + callback(arrayMap(results.sort(function (a, b) { + return a.index - b.index; + }), baseProperty('value'))); }); } - var concatSeries = doSeries(concat$1); + var filter = doParallel(_filter); - var concat = doParallel(concat$1); + function doParallelLimit(fn) { + return function (obj, limit, iterator, callback) { + return fn(_eachOfLimit(limit), obj, iterator, callback); + }; + } - var reverse = Array.prototype.reverse; + var filterLimit = doParallelLimit(_filter); - function compose() /* functions... */{ - return seq.apply(null, reverse.call(arguments)); + var filterSeries = doSeries(_filter); + + function forever(fn, cb) { + var done = onlyOnce(cb || noop); + var task = ensureAsync(fn); + + function next(err) { + if (err) return done(err); + task(next); + } + next(); } - function cargo(worker, payload) { - return queue$1(worker, 1, payload); + function iterator (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); } - /** - * A specialized version of `_.every` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if all elements pass the predicate check, else `false`. - */ - function arrayEvery(array, predicate) { - var index = -1, - length = array.length; + var log = consoleFunc('log'); - while (++index < length) { - if (!predicate(array[index], index, array)) { - return false; - } - } - return true; + function _asyncMap(eachfn, arr, iterator, callback) { + callback = once(callback || noop); + arr = arr || []; + var results = isArrayLike(arr) ? [] : {}; + eachfn(arr, function (value, index, callback) { + iterator(value, function (err, v) { + results[index] = v; + callback(err); + }); + }, function (err) { + callback(err, results); + }); } - /** - * Creates a base function for methods like `_.forIn`. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ - function createBaseFor(fromRight) { - return function(object, iteratee, keysFunc) { - var index = -1, - iterable = Object(object), - props = keysFunc(object), - length = props.length; + var map = doParallel(_asyncMap); - while (length--) { - var key = props[fromRight ? length : ++index]; - if (iteratee(iterable[key], key, iterable) === false) { - break; - } - } - return object; - }; + var mapLimit = doParallelLimit(_asyncMap); + + var mapSeries = doSeries(_asyncMap); + + function memoize(fn, hasher) { + var memo = {}; + var queues = {}; + hasher = hasher || identity; + var memoized = rest(function memoized(args) { + var callback = args.pop(); + var key = hasher.apply(null, args); + if (key in memo) { + setImmediate$1(function () { + callback.apply(null, memo[key]); + }); + } else if (key in queues) { + queues[key].push(callback); + } else { + queues[key] = [callback]; + fn.apply(null, args.concat([rest(function (args) { + memo[key] = args; + var q = queues[key]; + delete queues[key]; + for (var i = 0, l = q.length; i < l; i++) { + q[i].apply(null, args); + } + })])); + } + }); + memoized.memo = memo; + memoized.unmemoized = fn; + return memoized; } - /** - * The base implementation of `baseForIn` and `baseForOwn` which iterates - * over `object` properties returned by `keysFunc` invoking `iteratee` for - * each property. Iteratee functions may exit iteration early by explicitly - * returning `false`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} keysFunc The function to get the keys of `object`. - * @returns {Object} Returns `object`. - */ - var baseFor = createBaseFor(); + var nexTick = typeof process === 'object' && typeof process.nextTick === 'function' ? process.nextTick : setImmediate$1; - /** - * The base implementation of `_.forOwn` without support for iteratee shorthands. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForOwn(object, iteratee) { - return object && baseFor(object, iteratee, keys); + function _parallel(eachfn, tasks, callback) { + callback = callback || noop; + var results = isArrayLike(tasks) ? [] : {}; + + eachfn(tasks, function (task, key, callback) { + task(rest(function (err, args) { + if (args.length <= 1) { + args = args[0]; + } + results[key] = args; + callback(err); + })); + }, function (err) { + callback(err, results); + }); } - /** - * Converts `value` to a function if it's not one. - * - * @private - * @param {*} value The value to process. - * @returns {Function} Returns the function. - */ - function toFunction(value) { - return typeof value == 'function' ? value : identity; + function parallel(tasks, cb) { + return _parallel(eachOf, tasks, cb); } - /** - * Iterates over own enumerable properties of an object invoking `iteratee` - * for each property. The iteratee is invoked with three arguments: - * (value, key, object). Iteratee functions may exit iteration early by - * explicitly returning `false`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns `object`. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forOwn(new Foo, function(value, key) { - * console.log(key); - * }); - * // => logs 'a' then 'b' (iteration order is not guaranteed) - */ - function forOwn(object, iteratee) { - return object && baseForOwn(object, toFunction(iteratee)); + function parallelLimit(tasks, limit, cb) { + return _parallel(_eachOfLimit(limit), tasks, cb); } - /** - * Gets the index at which the first occurrence of `NaN` is found in `array`. - * - * @private - * @param {Array} array The array to search. - * @param {number} fromIndex The index to search from. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {number} Returns the index of the matched `NaN`, else `-1`. - */ - function indexOfNaN(array, fromIndex, fromRight) { - var length = array.length, - index = fromIndex + (fromRight ? 0 : -1); + function queue (worker, concurrency) { + return queue$1(function (items, cb) { + worker(items[0], cb); + }, concurrency, 1); + } - while ((fromRight ? index-- : ++index < length)) { - var other = array[index]; - if (other !== other) { - return index; + function priorityQueue (worker, concurrency) { + function _compareTasks(a, b) { + return a.priority - b.priority; } - } - return -1; - } - /** - * The base implementation of `_.indexOf` without `fromIndex` bounds checks. - * - * @private - * @param {Array} array The array to search. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseIndexOf(array, value, fromIndex) { - if (value !== value) { - return indexOfNaN(array, fromIndex); - } - var index = fromIndex - 1, - length = array.length; + 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; + } - while (++index < length) { - if (array[index] === value) { - return index; + 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 setImmediate$1(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(); + } + setImmediate$1(q.process); + }); } - } - return -1; + + // Start with a normal queue + var q = 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; } - /* Built-in method references for those with the same name as other `lodash` methods. */ - var nativeMax$1 = Math.max; + var slice = Array.prototype.slice; - /** - * Gets the index at which the first occurrence of `value` is found in `array` - * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) - * for equality comparisons. If `fromIndex` is negative, it's used as the offset - * from the end of `array`. If `array` is sorted providing `true` for `fromIndex` - * performs a faster binary search. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to search. - * @param {*} value The value to search for. - * @param {number} [fromIndex=0] The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.indexOf([1, 2, 1, 2], 2); - * // => 1 - * - * // using `fromIndex` - * _.indexOf([1, 2, 1, 2], 2, 2); - * // => 3 - */ - function indexOf(array, value, fromIndex) { - var length = array ? array.length : 0; - if (!length) { - return -1; - } - fromIndex = toInteger(fromIndex); - if (fromIndex < 0) { - fromIndex = nativeMax$1(length + fromIndex, 0); - } - return baseIndexOf(array, value, fromIndex); + function reduceRight(arr, memo, iterator, cb) { + var reversed = slice.call(arr).reverse(); + reduce(reversed, memo, iterator, cb); } - function auto (tasks, concurrency, callback) { - if (typeof arguments[1] === 'function') { - // concurrency is optional, shift the args. - callback = concurrency; - concurrency = null; - } - callback = once(callback || noop); - var keys$$ = keys(tasks); - var remainingTasks = keys$$.length; - if (!remainingTasks) { - return callback(null); - } - if (!concurrency) { - concurrency = remainingTasks; - } + function reject$1(eachfn, arr, iterator, callback) { + _filter(eachfn, arr, function (value, cb) { + iterator(value, function (v) { + cb(!v); + }); + }, callback); + } - var results = {}; - var runningTasks = 0; + var reject = doParallel(reject$1); - var listeners = []; - function addListener(fn) { - listeners.unshift(fn); + var rejectLimit = doParallelLimit(reject$1); + + var rejectSeries = doSeries(reject$1); + + function series(tasks, cb) { + return _parallel(eachOfSeries, tasks, cb); + } + + function retry(times, task, callback) { + var DEFAULT_TIMES = 5; + var DEFAULT_INTERVAL = 0; + + var attempts = []; + + var opts = { + times: DEFAULT_TIMES, + interval: DEFAULT_INTERVAL + }; + + function parseTimes(acc, t) { + if (typeof t === 'number') { + acc.times = parseInt(t, 10) || DEFAULT_TIMES; + } else if (typeof t === 'object') { + acc.times = parseInt(t.times, 10) || DEFAULT_TIMES; + acc.interval = parseInt(t.interval, 10) || DEFAULT_INTERVAL; + } else { + throw new Error('Unsupported argument type for \'times\': ' + typeof t); + } } - function removeListener(fn) { - var idx = indexOf(listeners, fn); - if (idx >= 0) listeners.splice(idx, 1); + + var length = arguments.length; + if (length < 1 || length > 3) { + throw new Error('Invalid arguments - must be either (task), (task, callback), (times, task) or (times, task, callback)'); + } else if (length <= 2 && typeof times === 'function') { + callback = task; + task = times; } - function taskComplete() { - remainingTasks--; - arrayEach(listeners.slice(), function (fn) { - fn(); - }); + if (typeof times !== 'function') { + parseTimes(opts, times); } + opts.callback = callback; + opts.task = task; - addListener(function () { - if (!remainingTasks) { - callback(null, results); + function wrappedTask(wrappedCallback, wrappedResults) { + function retryAttempt(task, finalAttempt) { + return function (seriesCallback) { + task(function (err, result) { + seriesCallback(!err || finalAttempt, { + err: err, + result: result + }); + }, wrappedResults); + }; } - }); - arrayEach(keys$$, function (k) { - var task = isArray(tasks[k]) ? tasks[k] : [tasks[k]]; - var taskCallback = rest(function (err, args) { - runningTasks--; - if (args.length <= 1) { - args = args[0]; - } - if (err) { - var safeResults = {}; - forOwn(results, function (val, rkey) { - safeResults[rkey] = val; - }); - safeResults[k] = args; - callback(err, safeResults); - } else { - results[k] = args; - setImmediate$1(taskComplete); - } - }); - var requires = task.slice(0, 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) && indexOf(dep, k) >= 0) { - throw new Error('Has cyclic dependencies'); - } - } - function ready() { - return runningTasks < concurrency && !baseHas(results, k) && arrayEvery(requires, function (x) { - return baseHas(results, x); - }); - } - if (ready()) { - runningTasks++; - task[task.length - 1](taskCallback, results); - } else { - addListener(listener); + function retryInterval(interval) { + return function (seriesCallback) { + setTimeout(function () { + seriesCallback(null); + }, interval); + }; } - function listener() { - if (ready()) { - runningTasks++; - removeListener(listener); - task[task.length - 1](taskCallback, results); + + while (opts.times) { + + var finalAttempt = !(opts.times -= 1); + attempts.push(retryAttempt(opts.task, finalAttempt)); + if (!finalAttempt && opts.interval > 0) { + attempts.push(retryInterval(opts.interval)); } } - }); + + series(attempts, function (done, data) { + data = data[data.length - 1]; + (wrappedCallback || opts.callback)(data.err, data.result); + }); + } + + // If a callback is passed, run this as a controll flow + return opts.callback ? wrappedTask() : wrappedTask; } - var apply = rest(function (fn, args) { - return rest(function (callArgs) { - return fn.apply(null, args.concat(callArgs)); - }); - }); + var some = _createTester(eachOf, Boolean, identity); - function applyEach$1(eachfn) { - return rest(function (fns, args) { - var go = rest(function (args) { - var that = this; - var callback = args.pop(); - return eachfn(fns, function (fn, _, cb) { - fn.apply(that, args.concat([cb])); - }, callback); + var someLimit = _createTester(eachOfLimit, Boolean, identity); + + function sortBy(arr, iterator, cb) { + map(arr, function (x, cb) { + iterator(x, function (err, criteria) { + if (err) return cb(err); + cb(null, { value: x, criteria: criteria }); }); - if (args.length) { - return go.apply(this, args); - } else { - return go; - } + }, function (err, results) { + if (err) return cb(err); + cb(null, arrayMap(results.sort(comparator), baseProperty('value'))); }); + + function comparator(left, right) { + var a = left.criteria, + b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + } } - var applyEachSeries = applyEach$1(eachOfSeries); + /* Built-in method references for those with the same name as other `lodash` methods. */ + var nativeCeil = Math.ceil; + var nativeMax$2 = Math.max; + /** + * The base implementation of `_.range` and `_.rangeRight` which doesn't + * coerce arguments to numbers. + * + * @private + * @param {number} start The start of the range. + * @param {number} end The end of the range. + * @param {number} step The value to increment or decrement by. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Array} Returns the new array of numbers. + */ + function baseRange(start, end, step, fromRight) { + var index = -1, + length = nativeMax$2(nativeCeil((end - start) / (step || 1)), 0), + result = Array(length); - var applyEach = applyEach$1(eachOf); + while (length--) { + result[fromRight ? length : ++index] = start; + start += step; + } + return result; + } + + function times (count, iterator, callback) { + map(baseRange(0, count, 1), iterator, callback); + } + + function timeLimit(count, limit, iterator, cb) { + return mapLimit(baseRange(0, count, 1), limit, iterator, cb); + } + + function timesSeries (count, iterator, callback) { + mapSeries(baseRange(0, count, 1), iterator, callback); + } + + function transform(arr, memo, iterator, callback) { + if (arguments.length === 3) { + callback = iterator; + iterator = memo; + memo = isArray(arr) ? [] : {}; + } + + eachOf(arr, function (v, k, cb) { + iterator(memo, v, k, cb); + }, function (err) { + callback(err, memo); + }); + } + + function unmemoize(fn) { + return function () { + return (fn.unmemoized || fn).apply(null, arguments); + }; + } + + function until(test, iterator, cb) { + return whilst(function () { + return !test.apply(this, arguments); + }, iterator, cb); + } + + function waterfall (tasks, cb) { + cb = once(cb || noop); + if (!isArray(tasks)) return cb(new Error('First argument to waterfall must be an array of functions')); + if (!tasks.length) return cb(); + + function wrapIterator(iterator) { + return rest(function (err, args) { + if (err) { + cb.apply(null, [err].concat(args)); + } else { + var next = iterator.next(); + if (next) { + args.push(wrapIterator(next)); + } else { + args.push(cb); + } + ensureAsync(iterator).apply(null, args); + } + }); + } + wrapIterator(iterator(tasks))(); + } var index = { applyEach: applyEach, |