[
  {
    "path": ".editorconfig",
    "content": "# http://editorconfig.org\nroot = true\n\n[*]\nend_of_line = lf\ncharset = utf-8\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[{*.js,*.mjs,*.ts,*.json,*.yml}]\nindent_size = 2\nindent_style = space\n"
  },
  {
    "path": ".gitattributes",
    "content": "* -text\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "patreon: tshemsedinov\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior: usage example or test.\n\n**Expected behavior**\nA clear and concise description of what you expected.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Desktop (please complete the following information):**\n\n- OS: [e.g. Fedora 30 64-bit]\n- Node.js version [e.g. 14.15.1]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/question.md",
    "content": "---\nname: Question\nabout: Please don't open an issue to ask questions\n---\n\nIssues on GitHub are intended to be related to problems and feature requests\nso we recommend not using this medium to ask them here grin. Thanks for\nunderstanding!\n\nIf you have a question, please check out our support groups and channels for\ndevelopers community:\n\nTelegram:\n\n- Channel for Metarhia community: https://t.me/metarhia\n- Group for Metarhia technology stack community: https://t.me/metaserverless\n- Group for NodeUA community: https://t.me/nodeua\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!--\nThank you for your pull request.\nCheck following steps to help us land your changes:\nChange [ ] to [x] for completed items.\n-->\n\n- [ ] tests and linter show no problems (`npm t`)\n- [ ] tests are added/updated for bug fixes and new features\n- [ ] code is properly formatted (`npm run fix`)\n- [ ] description of changes is added in CHANGELOG.md\n- [ ] update .d.ts typings\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Testing CI\non: pull_request\njobs:\n  build:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        node:\n          - 18\n          - 20\n          - 22\n          - 24\n          - 25\n        os:\n          - ubuntu-latest\n          - windows-latest\n          - macos-latest\n    steps:\n      - uses: actions/checkout@v4\n      - name: Use Node.js ${{ matrix.node }}\n        uses: actions/setup-node@v4\n        with:\n          node-version: ${{ matrix.node }}\n      - uses: actions/cache@v4\n        with:\n          path: ~/.npm\n          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}\n          restore-keys: |\n            ${{ runner.os }}-node-\n      - run: npm ci\n      - run: npm test\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\ndist\n*.log\n.DS_Store\ncoverage\n.nyc_output\n"
  },
  {
    "path": ".npmignore",
    "content": "node_modules\n*.log\n.DS_Store\n"
  },
  {
    "path": ".prettierignore",
    "content": "/dist\npackage.json\npackage-lock.json\n"
  },
  {
    "path": "AUTHORS",
    "content": "Timur Shemsedinov <timur.shemsedinov@gmail.com>\nAlexey Orlenko <eaglexrlnk@gmail.com>\nVlad Dziuba <dzyubavlad@gmail.com>\nDmytro Nechai <nechaido@gmail.com>\nOleksandr Kovalchuk <anxolerd@outlook.com>\nVladyslav Dukhin <vladyslav.dukhin@gmail.com>\nArthur Myronenko <gibslp69@gmail.com>\nAlexey Kachan <alexkachan@mail.ru>\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2016-2025 Metarhia contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Asynchronous Programming Library\n\n[![ci status](https://github.com/metarhia/metasync/workflows/Testing%20CI/badge.svg)](https://github.com/metarhia/metasync/actions?query=workflow%3A%22Testing+CI%22+branch%3Amaster)\n[![snyk](https://snyk.io/test/github/metarhia/metasync/badge.svg)](https://snyk.io/test/github/metarhia/metasync)\n[![npm version](https://badge.fury.io/js/metasync.svg)](https://badge.fury.io/js/metasync)\n[![npm downloads/month](https://img.shields.io/npm/dm/metasync.svg)](https://www.npmjs.com/package/metasync)\n[![npm downloads](https://img.shields.io/npm/dt/metasync.svg)](https://www.npmjs.com/package/metasync)\n[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/metarhia/metasync/blob/master/LICENSE)\n\n## Installation\n\n```bash\n$ npm install metasync\n```\n\n## Asynchronous functions composition\n\n`metasync(fns)(data, done)`\n\n- `fns` - array of callback-last functions, callback contranct err-first\n- `data` - input data (optional)\n- `done` - err-first callback\n- Returns: composed callback-last / err-first function\n\n![composition](https://cloud.githubusercontent.com/assets/4405297/16968374/1b81f160-4e17-11e6-96fa-9d7e2b422396.png)\n\n```js\nconst composed = metasync([f1, f2, f3, [[f4, f5, [f6, f7], f8]], f9]);\n```\n\n- Array of functions gives sequential execution: `[f1, f2, f3]`\n- Double brackets array of functions gives parallel execution: `[[f1, f2, f3]]`\n\n_Example:_\n\n```js\nconst metasync = require('metasync');\nconst fs = require('fs');\n\n// Data collector (collect keys by count)\nconst dc = metasync.collect(4);\n\ndc.pick('user', { name: 'Marcus Aurelius' });\nfs.readFile('HISTORY.md', (err, data) => dc.collect('history', err, data));\ndc.take('readme', fs.readFile, 'README.md');\nsetTimeout(() => dc.pick('timer', { date: new Date() }), 1000);\n\n// Key collector (collect certain keys by names)\nconst kc = metasync\n  .collect(['user', 'history', 'readme', 'timer'])\n  .timeout(2000)\n  .distinct()\n  .done((err, data) => console.log(data));\n\nkc.pick('user', { name: 'Marcus Aurelius' });\nkc.take('history', fs.readFile, 'HISTORY.md');\nkc.take('readme', fs.readFile, 'README.md');\nsetTimeout(() => kc.pick('timer', { date: new Date() }), 1000);\n```\n\n## API\n\n### callbackify(fn)\n\n- `fn`: [`<Function>`][function] promise-returning function\n\n_Returns:_ [`<Function>`][function]\n\nConvert Promise-returning to callback-last / error-first contract\n\n### asyncify(fn)\n\n- `fn`: [`<Function>`][function] regular synchronous function\n\n_Returns:_ [`<Function>`][function] with contract: callback-last / error-first\n\nConvert sync function to callback-last / error-first contract\n\n### promiseToCallbackLast(promise, callback)\n\n- `promise`: [`<Promise>`][promise]\n- `callback`: [`<Function>`][function]\n\nConvert Promise to callback-last\n\n### promisify(fn)\n\n- `fn`: [`<Function>`][function] callback-last function\n\n_Returns:_ [`<Function>`][function] Promise-returning function\n\nConvert async function to Promise-returning function\n\n### promisifySync(fn)\n\n- `fn`: [`<Function>`][function] regular synchronous function\n\n_Returns:_ [`<Function>`][function] Promise-returning function\n\nConvert sync function to Promise object\n\n### map(items, fn, done)\n\n- `items`: [`<Array>`][array] incoming\n- `fn`: [`<Function>`][function] to be executed for each value in the array\n  - `current`: `<any>` current element being processed in the array\n  - `callback`: [`<Function>`][function]\n    - `err`: [`<Error>`][error]|[`<null>`][null]\n    - `value`: `<any>`\n- `done`: [`<Function>`][function] on done\n  - `err`: [`<Error>`][error]|[`<null>`][null]\n  - `result`: [`<Array>`][array]\n\nAsynchronous map (iterate parallel)\n\n### filter(items, fn, done)\n\n- `items`: [`<Array>`][array] incoming\n- `fn`: [`<Function>`][function] to be executed for each value in the array\n  - `value`: `<any>` item from items array\n  - `callback`: [`<Function>`][function]\n    - `err`: [`<Error>`][error]|[`<null>`][null]\n    - `accepted`: [`<boolean>`][boolean]\n- `done`: [`<Function>`][function] on done\n  - `err`: [`<Error>`][error]|[`<null>`][null]\n  - `result`: [`<Array>`][array]\n\nAsynchrous filter (iterate parallel)\n\n_Example:_\n\n```js\nmetasync.filter(\n  ['data', 'to', 'filter'],\n  (item, callback) => callback(item.length > 2),\n  (err, result) => console.dir(result),\n);\n```\n\n### reduce(items, fn, done\\[, initial\\])\n\n- `items`: [`<Array>`][array] incoming\n- `fn`: [`<Function>`][function] to be executed for each value in array\n  - `previous`: `<any>` value previously returned in the last iteration\n  - `current`: `<any>` current element being processed in the array\n  - `callback`: [`<Function>`][function] callback for returning value back to\n    reduce function\n    - `err`: [`<Error>`][error]|[`<null>`][null]\n    - `data`: `<any>` resulting value\n  - `counter`: [`<number>`][number] index of the current element being processed\n    in array\n  - `items`: [`<Array>`][array] the array reduce was called upon\n- `done`: [`<Function>`][function] on done\n  - `err`: [`<Error>`][error]|[`<null>`][null]\n  - `result`: [`<Array>`][array]\n- `initial`: `<any>` optional value to be used as first argument in first\n  iteration\n\nAsynchronous reduce\n\n### reduceRight(items, fn, done\\[, initial\\])\n\n- `items`: [`<Array>`][array] incoming\n- `fn`: [`<Function>`][function] to be executed for each value in array\n  - `previous`: `<any>` value previously returned in the last iteration\n  - `current`: `<any>` current element being processed in the array\n  - `callback`: [`<Function>`][function] callback for returning value back to\n    reduce function\n    - `err`: [`<Error>`][error]|[`<null>`][null]\n    - `data`: `<any>` resulting value\n  - `counter`: [`<number>`][number] index of the current element being processed\n    in array\n  - `items`: [`<Array>`][array] the array reduce was called upon\n- `done`: [`<Function>`][function] on done\n  - `err`: [`<Error>`][error]|[`<null>`][null]\n  - `result`: [`<Array>`][array]\n- `initial`: `<any>` optional value to be used as first argument in first\n  iteration\n\nAsynchronous reduceRight\n\n### each(items, fn, done)\n\n- `items`: [`<Array>`][array] incoming\n- `fn`: [`<Function>`][function]\n  - `value`: `<any>` item from items array\n  - `callback`: [`<Function>`][function]\n    - `err`: [`<Error>`][error]|[`<null>`][null]\n- `done`: [`<Function>`][function] on done\n  - `err`: [`<Error>`][error]|[`<null>`][null]\n  - `items`: [`<Array>`][array]\n\nAsynchronous each (iterate in parallel)\n\n_Example:_\n\n```js\nmetasync.each(\n  ['a', 'b', 'c'],\n  (item, callback) => {\n    console.dir({ each: item });\n    callback();\n  },\n  (err, data) => console.dir('each done'),\n);\n```\n\n### series(items, fn, done)\n\n- `items`: [`<Array>`][array] incoming\n- `fn`: [`<Function>`][function]\n  - `value`: `<any>` item from items array\n  - `callback`: [`<Function>`][function]\n    - `err`: [`<Error>`][error]|[`<null>`][null]\n- `done`: [`<Function>`][function] on done\n  - `err`: [`<Error>`][error]|[`<null>`][null]\n  - `items`: [`<Array>`][array]\n\nAsynchronous series\n\n_Example:_\n\n```js\nmetasync.series(\n  ['a', 'b', 'c'],\n  (item, callback) => {\n    console.dir({ series: item });\n    callback();\n  },\n  (err, data) => {\n    console.dir('series done');\n  },\n);\n```\n\n### find(items, fn, done)\n\n- `items`: [`<Array>`][array] incoming\n- `fn`: [`<Function>`][function]\n  - `value`: `<any>` item from items array\n  - `callback`: [`<Function>`][function]\n    - `err`: [`<Error>`][error]|[`<null>`][null]\n    - `accepted`: [`<boolean>`][boolean]\n- `done`: [`<Function>`][function] on done\n  - `err`: [`<Error>`][error]|[`<null>`][null]\n  - `result`: `<any>`\n\nAsynchronous find (iterate in series)\n\n_Example:_\n\n```js\nmetasync.find(\n  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],\n  (item, callback) => callback(null, item % 3 === 0 && item % 5 === 0),\n  (err, result) => {\n    console.dir(result);\n  },\n);\n```\n\n### every(items, fn, done)\n\n- `items`: [`<Array>`][array] incoming\n- `fn`: [`<Function>`][function]\n  - `value`: `<any>` item from items array\n  - `callback`: [`<Function>`][function]\n    - `err`: [`<Error>`][error]|[`<null>`][null]\n    - `accepted`: [`<boolean>`][boolean]\n- `done`: [`<Function>`][function] on done\n  - `err`: [`<Error>`][error]|[`<null>`][null]\n  - `result`: [`<boolean>`][boolean]\n\nAsynchronous every\n\n### some(items, fn, done)\n\n- `items`: [`<Array>`][array] incoming\n- `fn`: [`<Function>`][function]\n  - `value`: `<any>` item from items array\n  - `callback`: [`<Function>`][function]\n    - `err`: [`<Error>`][error]|[`<null>`][null]\n    - `accepted`: [`<boolean>`][boolean]\n- `done`: [`<Function>`][function] on done\n  - `err`: [`<Error>`][error]|[`<null>`][null]\n  - `result`: [`<boolean>`][boolean]\n\nAsynchronous some (iterate in series)\n\n### asyncMap(items, fn\\[, options\\]\\[, done\\])\n\n- `items`: [`<Array>`][array] incoming dataset\n- `fn`: [`<Function>`][function]\n  - `item`: `<any>`\n  - `index`: [`<number>`][number]\n- `options`: [`<Object>`][object] map params, optional\n  - `min`: [`<number>`][number] min number of items in one next call\n  - `percent`: [`<number>`][number] ratio of map time to all time\n- `done`: [`<Function>`][function] call on done, optional\n  - `err`: [`<Error>`][error]|[`<null>`][null]\n  - `result`: [`<Array>`][array]\n\nNon-blocking synchronous map\n\n### asyncIter(base)\n\n- `base`: [`<Iterable>`][iterable]|[`<AsyncIterable>`][asynciterable] an\n  iterable that is wrapped in [`<AsyncIterator>`][asynciterator]\n\n_Returns:_ [`<AsyncIterator>`][asynciterator]\n\nCreate an AsyncIterator instance\n\n### class AsyncIterator\n\n#### AsyncIterator.prototype.constructor(base)\n\n#### async AsyncIterator.prototype.next()\n\n#### async AsyncIterator.prototype.count()\n\n#### async AsyncIterator.prototype.each(fn, thisArg)\n\n#### async AsyncIterator.prototype.forEach(fn, thisArg)\n\n#### async AsyncIterator.prototype.parallel(fn, thisArg)\n\n#### async AsyncIterator.prototype.every(predicate, thisArg)\n\n#### async AsyncIterator.prototype.find(predicate, thisArg)\n\n#### async AsyncIterator.prototype.includes(element)\n\n#### async AsyncIterator.prototype.reduce(reducer, initialValue)\n\n#### async AsyncIterator.prototype.some(predicate, thisArg)\n\n#### async AsyncIterator.prototype.someCount(predicate, count, thisArg)\n\n#### async AsyncIterator.prototype.collectTo(CollectionClass)\n\n#### async AsyncIterator.prototype.collectWith(obj, collector)\n\n#### async AsyncIterator.prototype.join(sep = ', ', prefix = '', suffix = '')\n\n#### async AsyncIterator.prototype.toArray()\n\n#### AsyncIterator.prototype.map(mapper, thisArg)\n\n#### AsyncIterator.prototype.filter(predicate, thisArg)\n\n#### AsyncIterator.prototype.flat(depth = 1)\n\n#### AsyncIterator.prototype.flatMap(mapper, thisArg)\n\n#### AsyncIterator.prototype.zip(...iterators)\n\n#### AsyncIterator.prototype.chain(...iterators)\n\n#### AsyncIterator.prototype.take(amount)\n\n#### AsyncIterator.prototype.takeWhile(predicate, thisArg)\n\n#### AsyncIterator.prototype.skip(amount)\n\n#### AsyncIterator.prototype.throttle(percent, min)\n\n#### AsyncIterator.prototype.enumerate()\n\n### collect(expected)\n\n- `expected`: [`<number>`][number]|[`<string[]>`][string]\n\n_Returns:_ [`<Collector>`][collector]\n\nCreate Collector instance\n\n### class Collector\n\nData collector\n\n#### Collector.prototype.constructor(expected)\n\n- `expected`: [`<number>`][number]|[`<string[]>`][string] count or keys\n\nData collector\n\n#### Collector.prototype.collect(key, err, value)\n\n- `key`: [`<string>`][string]\n- `err`: [`<Error>`][error]\n- `value`: `<any>`\n\n_Returns:_ [`<this>`][this]\n\nPick or fail key\n\n#### Collector.prototype.pick(key, value)\n\n- `key`: [`<string>`][string]\n- `value`: `<any>`\n\n_Returns:_ [`<this>`][this]\n\nPick key\n\n#### Collector.prototype.fail(key, err)\n\n- `key`: [`<string>`][string]\n- `err`: [`<Error>`][error]\n\n_Returns:_ [`<this>`][this]\n\nFail key\n\n#### Collector.prototype.take(key, fn, args)\n\n- `key`: [`<string>`][string]\n- `fn`: [`<Function>`][function]\n- `args`: [`<Array>`][array] rest arguments, to be passed in fn\n\n_Returns:_ [`<this>`][this]\n\nTake method result\n\n#### Collector.prototype.timeout(msec)\n\n- `msec`: [`<number>`][number]\n\n_Returns:_ [`<this>`][this]\n\nSet timeout\n\n#### Collector.prototype.done(callback)\n\n- `callback`: [`<Function>`][function]\n  - `err`: [`<Error>`][error]\n  - `data`: `<any>`\n\n_Returns:_ [`<this>`][this]\n\nSet on done listener\n\n#### Collector.prototype.finalize(key, err, data)\n\n#### Collector.prototype.distinct(value)\n\n- `value`: [`<boolean>`][boolean]\n\n_Returns:_ [`<this>`][this]\n\nDeny or allow unlisted keys\n\n#### Collector.prototype.cancel(err)\n\n#### Collector.prototype.then(fulfill, reject)\n\n### compose(flow)\n\n- `flow`: [`<Function[]>`][function] callback-last / err-first\n\n_Returns:_ [`<Function>`][function] composed callback-last / err-first\n\nAsynchronous functions composition\n\nArray of functions results in sequential execution: `[f1, f2, f3]` Double\nbrackets array of functions results in parallel execution: `[[f1, f2, f3]]`\n\n_Example:_\n\n```js\nconst composed = metasync([f1, f2, f3, [[f4, f5, [f6, f7], f8]], f9]);\n```\n\n### class Composition\n\n#### Composition.prototype.constructor()\n\n#### Composition.prototype.on(name, callback)\n\n#### Composition.prototype.finalize(err)\n\n#### Composition.prototype.collect(err, result)\n\n#### Composition.prototype.parallel()\n\n#### Composition.prototype.sequential()\n\n#### Composition.prototype.then(fulfill, reject)\n\n#### Composition.prototype.clone()\n\nClone composed\n\n#### Composition.prototype.pause()\n\nPause execution\n\n#### Composition.prototype.resume()\n\nResume execution\n\n#### Composition.prototype.timeout(msec)\n\n- `msec`: [`<number>`][number]\n\nSet timeout\n\n#### Composition.prototype.cancel()\n\nCancel execution where possible\n\n### firstOf(fns, callback)\n\n- `fns`: [`<Function[]>`][function] callback-last / err-first\n- `callback`: [`<Function>`][function] on done, err-first\n\nExecutes all asynchronous functions and pass first result to callback\n\n### parallel(fns\\[, context\\], callback)\n\n- `fns`: [`<Function[]>`][function] callback-last / err-first\n- `context`: [`<Object>`][object] incoming data, optional\n- `callback`: [`<Function>`][function] on done, err-first\n\nParallel execution\n\n_Example:_\n\n```js\nmetasync.parallel([f1, f2, f3], (err, data) => {});\n```\n\n### sequential(fns\\[, context\\], callback)\n\n- `fns`: [`<Function[]>`][function] callback-last with err-first contract\n- `context`: [`<Object>`][object] incoming data, optional\n- `callback`: [`<Function>`][function] err-first on done\n\nSequential execution\n\n_Example:_\n\n```js\nmetasync.sequential([f1, f2, f3], (err, data) => {});\n```\n\n### runIf(condition\\[, defaultVal\\], asyncFn, ...args)\n\n- `condition`: `<any>`\n- `defaultVal`: `<any>` optional, value that will be returned to callback if\n  `condition` is falsy.\n- `asyncFn`: [`<Function>`][function] callback-last function that will be\n  executed if `condition` if truthy\n- `args`: `<any[]>` args to pass to `asyncFn`\n\nRun `asyncFn` if `condition` is truthy, else return `defaultVal` to callback.\n\n### runIfFn(asyncFn, ...args)\n\n- `asyncFn`: [`<Function>`][function] callback-last function that will be\n  executed if it is provided\n- `args`: `<any[]>` args to pass to `asyncFn`\n\nRun `asyncFn` if it is provided\n\n### class do\n\n#### do.prototype.constructor(fn, ...args)\n\n### toAsync(fn)\n\n- `fn`: [`<Function>`][function] callback-last / err-first\n\n_Returns:_ [`<Function>`][function]\n\nConvert synchronous function to asynchronous\n\nTransform function with args arguments and callback to function with args as\nseparate values and callback\n\n### asAsync(fn, args)\n\n- `fn`: [`<Function>`][function] asynchronous\n- `args`: [`<Array>`][array] its arguments\n\nWrap function adding async chain methods\n\n### of(args)\n\n- `args`: [`<Array>`][array]\n\nApplicative f => a -> f a\n\n### concat(fn1, fn2)\n\n- `fn1`: [`<Function>`][function]\n- `fn2`: [`<Function>`][function]\n\nMonoid m => a -> a -> a\n\n### fmap(fn1, f)\n\n- `fn1`: [`<Function>`][function]\n- `f`: [`<Function>`][function]\n\nFunctor f => (a -> b) -> f a -> f b\n\n### ap(fn, funcA)\n\n- `fn`: [`<Function>`][function]\n- `funcA`: [`<Function>`][function]\n\nApplicative f => f (a -> b) -> f a -> f b\n\n### memoize(fn)\n\n- `fn`: [`<Function>`][function] sync or async\n\n_Returns:_ [`<Function>`][function] memoized\n\nCreate memoized function\n\n### class Memoized\n\n#### Memoized.prototype.constructor()\n\n#### Memoized.prototype.clear()\n\n#### Memoized.prototype.add(key, err, data)\n\n#### Memoized.prototype.del(key)\n\n#### Memoized.prototype.get(key, callback)\n\n#### Memoized.prototype.on(eventName, listener)\n\n- `eventName`: [`<string>`][string]\n- `listener`: [`<Function>`][function] handler\n\nAdd event listener\n\n_Example:_\n\n```js\nconst memoized = new Memoized();\nmemoized.on('memoize', (err, data) => { ... });\nmemoized.on('add', (key, err, data) => { ... });\nmemoized.on('del', (key) => { ... })\nmemoized.on('clear', () => { ... });\n```\n\n#### Memoized.prototype.emit(eventName, args)\n\n- `eventName`: [`<string>`][string]\n- `args`: `<any>` rest arguments\n\nEmit Memoized events\n\n### poolify(factory, min, norm, max)\n\n### queue(concurrency)\n\n- `concurrency`: [`<number>`][number] simultaneous and asynchronously executing\n  tasks\n\n_Returns:_ [`<Queue>`][queue]\n\nCreate Queue instance\n\n### class Queue\n\nQueue constructor\n\n#### Queue.prototype.constructor(concurrency)\n\n- `concurrency`: [`<number>`][number] asynchronous concurrency\n\nQueue constructor\n\n#### Queue.prototype.wait(msec)\n\n- `msec`: [`<number>`][number] wait timeout for single item\n\n_Returns:_ [`<this>`][this]\n\nSet wait before processing timeout\n\n#### Queue.prototype.throttle(count\\[, interval\\])\n\n- `count`: [`<number>`][number] item count\n- `interval`: [`<number>`][number] per interval, optional default: 1000 msec\n\n_Returns:_ [`<this>`][this]\n\nThrottle to limit throughput\n\n#### Queue.prototype.add(item\\[, factor\\[, priority\\]\\])\n\n- `item`: [`<Object>`][object] to be added\n- `factor`: [`<number>`][number]|[`<string>`][string] type, source, destination\n  or path, optional\n- `priority`: [`<number>`][number] optional\n\n_Returns:_ [`<this>`][this]\n\nAdd item to queue\n\n#### Queue.prototype.next(task)\n\n- `task`: [`<Array>`][array] next task [item, factor, priority]\n\n_Returns:_ [`<this>`][this]\n\nProcess next item\n\n#### Queue.prototype.takeNext()\n\n_Returns:_ [`<this>`][this]\n\nPrepare next item for processing\n\n#### Queue.prototype.pause()\n\n_Returns:_ [`<this>`][this]\n\nPause queue\n\nThis function is not completely implemented yet\n\n#### Queue.prototype.resume()\n\n_Returns:_ [`<this>`][this]\n\nResume queue\n\nThis function is not completely implemented yet\n\n#### Queue.prototype.clear()\n\n_Returns:_ [`<this>`][this]\n\nClear queue\n\n#### Queue.prototype.timeout(msec, onTimeout)\n\n- `msec`: [`<number>`][number] process timeout for single item\n- `onTimeout`: [`<Function>`][function]\n\n_Returns:_ [`<this>`][this]\n\nSet timeout interval and listener\n\n#### Queue.prototype.process(fn)\n\n- `fn`: [`<Function>`][function]\n  - `item`: [`<Object>`][object]\n  - `callback`: [`<Function>`][function]\n    - `err`: [`<Error>`][error]|[`<null>`][null]\n    - `result`: `<any>`\n\n_Returns:_ [`<this>`][this]\n\nSet processing function\n\n#### Queue.prototype.done(fn)\n\n- `fn`: [`<Function>`][function] done listener\n  - `err`: [`<Error>`][error]|[`<null>`][null]\n  - `result`: `<any>`\n\n_Returns:_ [`<this>`][this]\n\nSet listener on processing done\n\n#### Queue.prototype.success(listener)\n\n- `listener`: [`<Function>`][function] on success\n  - `item`: `<any>`\n\n_Returns:_ [`<this>`][this]\n\nSet listener on processing success\n\n#### Queue.prototype.failure(listener)\n\n- `listener`: [`<Function>`][function] on failure\n  - `err`: [`<Error>`][error]|[`<null>`][null]\n\n_Returns:_ [`<this>`][this]\n\nSet listener on processing error\n\n#### Queue.prototype.drain(listener)\n\n- `listener`: [`<Function>`][function] on drain\n\n_Returns:_ [`<this>`][this]\n\nSet listener on drain Queue\n\n#### Queue.prototype.fifo()\n\n_Returns:_ [`<this>`][this]\n\nSwitch to FIFO mode (default for Queue)\n\n#### Queue.prototype.lifo()\n\n_Returns:_ [`<this>`][this]\n\nSwitch to LIFO mode\n\n#### Queue.prototype.priority(flag)\n\n- `flag`: [`<boolean>`][boolean] default: true, false will disable priority mode\n\n_Returns:_ [`<this>`][this]\n\nActivate or deactivate priority mode\n\n#### Queue.prototype.roundRobin(flag)\n\n- `flag`: [`<boolean>`][boolean] default: true, false will disable roundRobin\n  mode\n\n_Returns:_ [`<this>`][this]\n\nActivate or deactivate round robin mode\n\n#### Queue.prototype.pipe(dest)\n\n- `dest`: [`<Queue>`][queue] destination queue\n\n_Returns:_ [`<this>`][this]\n\nPipe processed items to different queue\n\n### throttle(timeout, fn, ...args)\n\n- `timeout`: [`<number>`][number] msec interval\n- `fn`: [`<Function>`][function] to be throttled\n- `args`: [`<Array>`][array] arguments for fn, optional\n\n_Returns:_ [`<Function>`][function]\n\nGet throttling function, executed once per interval\n\n### debounce(timeout, fn, ...args)\n\n- `timeout`: [`<number>`][number] msec\n- `fn`: [`<Function>`][function] to be debounced\n- `args`: [`<Array>`][array] arguments for fn, optional\n\nDebounce function, delayed execution\n\n### timeout(timeout, fn, callback)\n\n- `timeout`: [`<number>`][number] time interval\n- `fn`: [`<Function>`][function] to be executed\n- `callback`: [`<Function>`][function] callback(...args), on done\n  - `args`: [`<Array>`][array]\n\nSet timeout for asynchronous function execution\n\n## Contributors\n\n- Timur Shemsedinov (marcusaurelius)\n- See github for full [contributors list](https://github.com/metarhia/metasync/graphs/contributors)\n\n[asynciterable]: https://tc39.github.io/ecma262/#sec-asynciterable-interface\n[asynciterator]: #class-asynciterator\n[collector]: #class-collector\n[queue]: #class-queue\n[object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object\n[function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function\n[promise]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise\n[array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array\n[error]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error\n[boolean]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type\n[null]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Null_type\n[number]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type\n[string]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type\n[iterable]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols\n[this]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this\n"
  },
  {
    "path": "eslint.config.js",
    "content": "'use strict';\n\nconst init = require('eslint-config-metarhia');\n\ninit[0].ignores.push('./dist/**/*.js');\ninit[0].rules['no-invalid-this'] = 'off';\n\nmodule.exports = [...init];\n"
  },
  {
    "path": "lib/adapters.js",
    "content": "'use strict';\n\n// Convert Promise to callback-last\n//   promise <Promise>\n//   callback <Function>\nconst promiseToCallbackLast = (promise) => (callback) => {\n  promise.then(\n    (value) => {\n      callback(null, value);\n    },\n    (reason) => {\n      callback(reason);\n    },\n  );\n};\n\n// Convert Promise-returning to callback-last / error-first contract\n//   fn <Function> promise-returning function\n//\n// Returns: <Function>\nconst callbackify =\n  (fn) =>\n  (...args) => {\n    const callback = args.pop();\n    promiseToCallbackLast(fn(...args))(callback);\n  };\n\n// Convert sync function to callback-last / error-first contract\n//   fn <Function> regular synchronous function\n//\n// Returns: <Function> with contract: callback-last / error-first\nconst asyncify =\n  (fn) =>\n  (...args) => {\n    const callback = args.pop();\n    setTimeout(() => {\n      let result;\n      try {\n        result = fn(...args);\n      } catch (error) {\n        return void callback(error);\n      }\n      callback(null, result);\n    }, 0);\n  };\n\n// Convert async function to Promise-returning function\n//   fn <Function> callback-last function\n//\n// Returns: <Function> Promise-returning function\nconst promisify =\n  (fn) =>\n  (...args) =>\n    new Promise((resolve, reject) => {\n      fn(...args, (err, data) => {\n        if (err) reject(err);\n        else resolve(data);\n      });\n    });\n\n// Convert sync function to Promise object\n//   fn <Function> regular synchronous function\n//\n// Returns: <Function> Promise-returning function\nconst promisifySync =\n  (fn) =>\n  (...args) => {\n    let result;\n    try {\n      result = fn(...args);\n    } catch (error) {\n      return Promise.reject(error);\n    }\n    return Promise.resolve(result);\n  };\n\nmodule.exports = {\n  callbackify,\n  asyncify,\n  promiseToCallbackLast,\n  promisify,\n  promisifySync,\n};\n"
  },
  {
    "path": "lib/array.js",
    "content": "'use strict';\n\n// Asynchronous map (iterate parallel)\n//   items - <Array>, incoming\n//   fn - <Function>, to be executed for each value in the array\n//     current - <any>, current element being processed in the array\n//     callback - <Function>\n//       err - <Error> | <null>\n//       value - <any>\n//   done - <Function>, on done\n//     err - <Error> | <null>\n//     result - <Array>\nconst map = (items, fn, done) => {\n  const len = items.length;\n  if (!len) return void done(null, []);\n  let errored = false;\n  let count = 0;\n  const result = new Array(len);\n\n  const next = (index, err, value) => {\n    if (errored) return;\n    if (err) {\n      errored = true;\n      return void done(err);\n    }\n    result[index] = value;\n    count++;\n    if (count === len) done(null, result);\n  };\n\n  for (let i = 0; i < len; i++) {\n    fn(items[i], next.bind(null, i));\n  }\n};\n\nconst DEFAULT_OPTIONS = { min: 5, percent: 0.7 };\n\n// Non-blocking synchronous map\n// Signature: items, fn[, options][, done]\n//   items - <Array>, incoming dataset\n//   fn - <Function>\n//     item - <any>\n//     index - <number>\n//   options - <Object>, map params, optional\n//     min - <number>, min number of items in one next call\n//     percent - <number>, ratio of map time to all time\n//   done - <Function>, call on done, optional\n//     err - <Error> | <null>\n//     result - <Array>\nconst asyncMap = (items, fn, options = {}, done) => {\n  if (typeof options === 'function') {\n    done = options;\n    options = DEFAULT_OPTIONS;\n  }\n\n  if (!items.length) {\n    if (done) done(null, []);\n    return;\n  }\n\n  const min = options.min || DEFAULT_OPTIONS.min;\n  const percent = options.percent || DEFAULT_OPTIONS.percent;\n\n  let begin;\n  let sum = 0;\n  let count = 0;\n\n  const result = done ? new Array(items.length) : null;\n  const ratio = percent / (1 - percent);\n\n  const countNumber = () => {\n    const loopTime = Date.now() - begin;\n    const itemTime = sum / count;\n    const necessaryNumber = (ratio * loopTime) / itemTime;\n    return Math.max(necessaryNumber, min);\n  };\n\n  const next = () => {\n    const itemsNumber = count ? countNumber() : min;\n    const iterMax = Math.min(items.length, itemsNumber + count);\n\n    begin = Date.now();\n    for (; count < iterMax; count++) {\n      const itemResult = fn(items[count], count);\n      if (done) result[count] = itemResult;\n    }\n    sum += Date.now() - begin;\n\n    if (count < items.length) {\n      begin = Date.now();\n      setTimeout(next, 0);\n    } else if (done) {\n      done(null, result);\n    }\n  };\n\n  next();\n};\n\n// Asynchrous filter (iterate parallel)\n//   items - <Array>, incoming\n//   fn - <Function>, to be executed for each value in the array\n//     value - <any>, item from items array\n//     callback - <Function>\n//       err - <Error> | <null>\n//       accepted - <boolean>\n//   done - <Function>, on done\n//     err - <Error> | <null>\n//     result - <Array>\n//\n// Example:\n// metasync.filter(\n//   ['data', 'to', 'filter'],\n//   (item, callback) => callback(item.length > 2),\n//   (err, result) => console.dir(result)\n// );\nconst filter = (items, fn, done) => {\n  const len = items.length;\n\n  if (!len) return void done(null, []);\n\n  let count = 0;\n  let suitable = 0;\n  const data = new Array(len);\n  const rejected = Symbol('rejected');\n\n  const next = (index, err, accepted) => {\n    if (!accepted || err) {\n      data[index] = rejected;\n    } else {\n      data[index] = items[index];\n      suitable++;\n    }\n    count++;\n    if (count === len) {\n      const result = new Array(suitable);\n      let pos = 0;\n      for (let i = 0; i < len; i++) {\n        const val = data[i];\n        if (val !== rejected) result[pos++] = val;\n      }\n      done(null, result);\n    }\n  };\n\n  for (let i = 0; i < len; i++) {\n    fn(items[i], next.bind(null, i));\n  }\n};\n\nconst REDUCE_EMPTY_ARR =\n  'Metasync: reduce of empty array with no initial value';\n\n// Asynchronous reduce\n// Signature: items, fn, done[, initial]\n//   items - <Array>, incoming\n//   fn - <Function>, to be executed for each value in array\n//     previous - <any>, value previously returned in the last iteration\n//     current - <any>, current element being processed in the array\n//     callback - <Function>, callback for returning value\n//         back to reduce function\n//       err - <Error> | <null>\n//       data - <any>, resulting value\n//     counter - <number>, index of the current element\n//         being processed in array\n//     items - <Array>, the array reduce was called upon\n//   done - <Function>, on done\n//     err - <Error> | <null>\n//     result - <Array>\n//   initial - <any>, optional value to be used as first\n//       argument in first iteration\nconst reduce = (items, fn, done, initial) => {\n  const len = items.length;\n  const hasInitial = typeof initial !== 'undefined';\n\n  if (len === 0 && !hasInitial) {\n    return void done(new TypeError(REDUCE_EMPTY_ARR), initial);\n  }\n\n  let previous = hasInitial ? initial : items[0];\n  if ((len === 0 && hasInitial) || (len === 1 && !hasInitial)) {\n    return void done(null, previous);\n  }\n\n  let count = hasInitial ? 0 : 1;\n  let current = items[count];\n  const last = len - 1;\n\n  const next = (err, data) => {\n    if (err) return void done(err);\n    if (count === last) return void done(null, data);\n    count++;\n    previous = data;\n    current = items[count];\n    fn(previous, current, next, count, items);\n  };\n\n  fn(previous, current, next, count, items);\n};\n\nconst REDUCE_RIGHT_EMPTY_ARR =\n  'Metasync: reduceRight of empty array with no initial value';\n\n// Asynchronous reduceRight\n// Signature: items, fn, done[, initial]\n//   items - <Array>, incoming\n//   fn - <Function>, to be executed for each value in array\n//     previous - <any>, value previously returned in the last iteration\n//     current - <any>, current element being processed in the array\n//     callback - <Function>, callback for returning value\n//         back to reduce function\n//       err - <Error> | <null>\n//       data - <any>, resulting value\n//     counter - <number>, index of the current element\n//         being processed in array\n//     items - <Array>, the array reduce was called upon\n//   done - <Function>, on done\n//     err - <Error> | <null>\n//     result - <Array>\n//   initial - <any>, optional value to be used as first\n//       argument in first iteration\nconst reduceRight = (items, fn, done, initial) => {\n  const len = items.length;\n  const hasInitial = typeof initial !== 'undefined';\n\n  if (len === 0 && !hasInitial) {\n    return void done(new TypeError(REDUCE_RIGHT_EMPTY_ARR), initial);\n  }\n\n  let previous = hasInitial ? initial : items[len - 1];\n  if ((len === 0 && hasInitial) || (len === 1 && !hasInitial)) {\n    return void done(null, previous);\n  }\n\n  let count = hasInitial ? len - 1 : len - 2;\n  let current = items[count];\n  const last = 0;\n\n  const next = (err, data) => {\n    if (err) return void done(err);\n    if (count === last) return void done(null, data);\n    count--;\n    previous = data;\n    current = items[count];\n    fn(previous, current, next, count, items);\n  };\n\n  fn(previous, current, next, count, items);\n};\n\n// Asynchronous each (iterate in parallel)\n//   items - <Array>, incoming\n//   fn - <Function>\n//     value - <any>, item from items array\n//     callback - <Function>\n//       err - <Error> | <null>\n//   done - <Function>, on done\n//     err - <Error> | <null>\n//     items - <Array>\n//\n// Example:\n// metasync.each(\n//   ['a', 'b', 'c'],\n//   (item, callback) => {\n//     console.dir({ each: item });\n//     callback();\n//   },\n//   (err, data) => console.dir('each done')\n// );\nconst each = (items, fn, done) => {\n  const len = items.length;\n  if (len === 0) return void done(null, items);\n  let count = 0;\n  let errored = false;\n\n  const next = (err) => {\n    if (errored) return;\n    if (err) {\n      errored = true;\n      return void done(err);\n    }\n    count++;\n    if (count === len) done(null);\n  };\n\n  for (let i = 0; i < len; i++) {\n    fn(items[i], next);\n  }\n};\n\n// Asynchronous series\n//   items - <Array>, incoming\n//   fn - <Function>\n//     value - <any>, item from items array\n//     callback - <Function>\n//       err - <Error> | <null>\n//   done - <Function>, on done\n//     err - <Error> | <null>\n//     items - <Array>\n//\n// Example:\n// metasync.series(\n//   ['a', 'b', 'c'],\n//   (item, callback) => {\n//     console.dir({ series: item });\n//     callback();\n//   },\n//   (err, data) => {\n//     console.dir('series done');\n//   }\n// );\nconst series = (items, fn, done) => {\n  const len = items.length;\n  let i = -1;\n\n  const next = () => {\n    i++;\n    if (i === len) return void done(null, items);\n    fn(items[i], (err) => {\n      if (err) return void done(err);\n      setImmediate(next);\n    });\n  };\n  next();\n};\n\n// Asynchronous find (iterate in series)\n//   items - <Array>, incoming\n//   fn - <Function>,\n//     value - <any>, item from items array\n//     callback - <Function>\n//       err - <Error> | <null>\n//       accepted - <boolean>\n//   done - <Function>, on done\n//     err - <Error> | <null>\n//     result - <any>\n//\n// Example:\n// metasync.find(\n//   [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],\n//   (item, callback) => callback(null, item % 3 === 0 && item % 5 === 0),\n//   (err, result) => {\n//     console.dir(result);\n//   }\n// );\nconst find = (items, fn, done) => {\n  const len = items.length;\n  if (len === 0) return void done();\n  let finished = false;\n  const last = len - 1;\n\n  const next = (index, err, accepted) => {\n    if (finished) return;\n    if (err) {\n      finished = true;\n      return void done(err);\n    }\n    if (accepted) {\n      finished = true;\n      return void done(null, items[index]);\n    }\n    if (index === last) done(null);\n  };\n\n  for (let i = 0; i < len; i++) {\n    fn(items[i], next.bind(null, i));\n  }\n};\n\n// Asynchronous every\n//   items - <Array>, incoming\n//   fn - <Function>,\n//     value - <any>, item from items array\n//     callback - <Function>\n//       err - <Error> | <null>\n//       accepted - <boolean>\n//   done - <Function>, on done\n//     err - <Error> | <null>\n//     result - <boolean>\nconst every = (items, fn, done) => {\n  if (items.length === 0) return void done(null, true);\n  let proceedItemsCount = 0;\n  const len = items.length;\n\n  const finish = (err, accepted) => {\n    if (!done) return;\n    if (err || !accepted) {\n      done(err, false);\n      done = null;\n      return;\n    }\n    proceedItemsCount++;\n    if (proceedItemsCount === len) done(null, true);\n  };\n\n  for (const item of items) fn(item, finish);\n};\n\n// Asynchronous some (iterate in series)\n//   items - <Array>, incoming\n//   fn - <Function>\n//     value - <any>, item from items array\n//     callback - <Function>\n//       err - <Error> | <null>\n//       accepted - <boolean>\n//   done - <Function>, on done\n//     err - <Error> | <null>\n//     result - <boolean>\nconst some = (items, fn, done) => {\n  const len = items.length;\n  let i = 0;\n\n  const next = () => {\n    if (i === len) return void done(null, false);\n    fn(items[i], (err, accepted) => {\n      if (err) return void done(err);\n      if (accepted) return void done(null, true);\n      i++;\n      next();\n    });\n  };\n\n  if (len > 0) next();\n  else done(null, false);\n};\n\nmodule.exports = {\n  map,\n  filter,\n  reduce,\n  reduceRight,\n  each,\n  series,\n  find,\n  every,\n  some,\n  asyncMap,\n};\n"
  },
  {
    "path": "lib/async-iterator.js",
    "content": "/* eslint-disable no-use-before-define */\n\n'use strict';\n\nconst { promisify } = require('util');\n\nconst timeout = promisify((res) => setTimeout(res, 0));\n\nconst toIterator = (base) => {\n  if (base[Symbol.asyncIterator]) {\n    return base[Symbol.asyncIterator]();\n  } else if (base[Symbol.iterator]) {\n    return base[Symbol.iterator]();\n  } else {\n    throw new TypeError('Base is not Iterable');\n  }\n};\n\nclass AsyncIterator {\n  constructor(base) {\n    this.base = toIterator(base);\n  }\n\n  [Symbol.asyncIterator]() {\n    return this;\n  }\n\n  async next() {\n    return this.base.next();\n  }\n\n  async count() {\n    let count = 0;\n    while (!(await this.next()).done) {\n      count++;\n    }\n    return count;\n  }\n\n  async each(fn, thisArg) {\n    return this.forEach(fn, thisArg);\n  }\n\n  async forEach(fn, thisArg) {\n    for await (const value of this) {\n      await fn.call(thisArg, value);\n    }\n  }\n\n  async parallel(fn, thisArg) {\n    const promises = [];\n    for await (const value of this) {\n      promises.push(fn.call(thisArg, value));\n    }\n    return Promise.all(promises);\n  }\n\n  async every(predicate, thisArg) {\n    for await (const value of this) {\n      const res = await predicate.call(thisArg, value);\n      if (!res) return false;\n    }\n    return true;\n  }\n\n  async find(predicate, thisArg) {\n    for await (const value of this) {\n      if (await predicate.call(thisArg, value)) {\n        return value;\n      }\n    }\n    const value = undefined;\n    return value;\n  }\n\n  async includes(element) {\n    for await (const value of this) {\n      if (value === element || (Number.isNaN(value) && Number.isNaN(element))) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  async reduce(reducer, initialValue) {\n    let result = initialValue;\n\n    if (result === undefined) {\n      const next = await this.next();\n      if (next.done) {\n        throw new TypeError(\n          'Reduce of consumed async iterator with no initial value',\n        );\n      }\n      result = next.value;\n    }\n\n    for await (const value of this) {\n      result = await reducer(result, value);\n    }\n    return result;\n  }\n\n  async some(predicate, thisArg) {\n    for await (const value of this) {\n      if (await predicate.call(thisArg, value)) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  async someCount(predicate, count, thisArg) {\n    let n = 0;\n    for await (const value of this) {\n      if (await predicate.call(thisArg, value)) {\n        if (++n === count) return true;\n      }\n    }\n    return false;\n  }\n\n  async collectTo(CollectionClass) {\n    const arr = await this.toArray();\n    return new CollectionClass(arr);\n  }\n\n  async collectWith(obj, collector) {\n    await this.forEach((element) => collector(obj, element));\n  }\n\n  async join(sep = ',', prefix = '', suffix = '') {\n    let result = prefix;\n    const { done, value } = await this.next();\n    if (!done) {\n      result += value;\n      for await (const value of this) {\n        result += sep + value;\n      }\n    }\n    return result + suffix;\n  }\n\n  async toArray() {\n    const newArray = [];\n    for await (const value of this) {\n      newArray.push(value);\n    }\n    return newArray;\n  }\n\n  map(mapper, thisArg) {\n    return new MapIterator(this, mapper, thisArg);\n  }\n\n  filter(predicate, thisArg) {\n    return new FilterIterator(this, predicate, thisArg);\n  }\n\n  flat(depth = 1) {\n    return new FlatIterator(this, depth);\n  }\n\n  flatMap(mapper, thisArg) {\n    return new FlatMapIterator(this, mapper, thisArg);\n  }\n\n  zip(...iterators) {\n    return new ZipIterator(this, iterators);\n  }\n\n  chain(...iterators) {\n    return new ChainIterator(this, iterators);\n  }\n\n  take(amount) {\n    return new TakeIterator(this, amount);\n  }\n\n  takeWhile(predicate, thisArg) {\n    return new TakeWhileIterator(this, predicate, thisArg);\n  }\n\n  skip(amount) {\n    for (let i = 0; i < amount; i++) {\n      this.next();\n    }\n    return this;\n  }\n\n  throttle(percent, min) {\n    return new ThrottleIterator(this, percent, min);\n  }\n\n  enumerate() {\n    return new EnumerateIterator(this);\n  }\n}\n\nclass MapIterator extends AsyncIterator {\n  constructor(base, mapper, thisArg) {\n    super(base);\n    this.mapper = mapper;\n    this.thisArg = thisArg;\n  }\n\n  async next() {\n    const { done, value } = await this.base.next();\n    return {\n      done,\n      value: done ? undefined : await this.mapper.call(this.thisArg, value),\n    };\n  }\n}\n\nclass FilterIterator extends AsyncIterator {\n  constructor(base, predicate, thisArg) {\n    super(base);\n    this.predicate = predicate;\n    this.thisArg = thisArg;\n  }\n\n  async next() {\n    for await (const value of this.base) {\n      if (await this.predicate.call(this.thisArg, value)) {\n        return { done: false, value };\n      }\n    }\n    return { done: true, value: undefined };\n  }\n}\n\nclass FlatIterator extends AsyncIterator {\n  constructor(base, depth) {\n    super(base);\n    this.currentDepth = 0;\n    this.stack = new Array(depth + 1);\n    this.stack[0] = base;\n  }\n\n  async next() {\n    while (this.currentDepth >= 0) {\n      const top = this.stack[this.currentDepth];\n      const next = await top.next();\n\n      if (next.done) {\n        this.stack[this.currentDepth] = null;\n        this.currentDepth--;\n        continue;\n      }\n\n      if (\n        this.currentDepth === this.stack.length - 1 ||\n        (!next.value[Symbol.iterator] && !next.value[Symbol.asyncIterator])\n      ) {\n        return next;\n      }\n\n      this.stack[++this.currentDepth] = next.value[Symbol.asyncIterator]\n        ? next.value[Symbol.asyncIterator]()\n        : next.value[Symbol.iterator]();\n    }\n\n    return { done: true, value: undefined };\n  }\n}\n\nclass FlatMapIterator extends AsyncIterator {\n  constructor(base, mapper, thisArg) {\n    super(base);\n    this.mapper = mapper;\n    this.thisArg = thisArg;\n    this.currentIterator = null;\n  }\n\n  async next() {\n    if (!this.currentIterator) {\n      const next = await this.base.next();\n      if (next.done) {\n        return next;\n      }\n\n      const value = this.mapper.call(this.thisArg, next.value);\n      if (!value[Symbol.iterator] && !value[Symbol.asyncIterator]) {\n        return { done: false, value };\n      }\n\n      this.currentIterator = toIterator(value);\n    }\n\n    const next = await this.currentIterator.next();\n\n    if (next.done) {\n      this.currentIterator = null;\n      return this.next();\n    }\n    return next;\n  }\n}\n\nclass TakeIterator extends AsyncIterator {\n  constructor(base, amount) {\n    super(base);\n    this.amount = amount;\n    this.iterated = 0;\n  }\n\n  async next() {\n    this.iterated++;\n    if (this.iterated <= this.amount) {\n      return this.base.next();\n    }\n    return { done: true, value: undefined };\n  }\n}\n\nclass TakeWhileIterator extends AsyncIterator {\n  constructor(base, predicate, thisArg) {\n    super(base);\n    this.predicate = predicate;\n    this.thisArg = thisArg;\n    this.done = false;\n  }\n\n  async next() {\n    if (this.done) return { done: true, value: undefined };\n    const next = await this.base.next();\n    const res = await this.predicate.call(this.thisArg, next.value);\n    if (!next.done && res) return next;\n    this.done = true;\n    return { done: true, value: undefined };\n  }\n}\n\nclass ZipIterator extends AsyncIterator {\n  constructor(base, iterators) {\n    super(base);\n    this.iterators = iterators.map(toIterator);\n  }\n\n  async next() {\n    const result = [];\n\n    const next = await this.base.next();\n    if (next.done) {\n      return next;\n    }\n    result.push(next.value);\n\n    for (const iterator of this.iterators) {\n      const next = await iterator.next();\n\n      if (next.done) {\n        return next;\n      }\n      result.push(next.value);\n    }\n    return { done: false, value: result };\n  }\n}\n\nclass ChainIterator extends AsyncIterator {\n  constructor(base, iterators) {\n    super(base);\n    this.currentIterator = base;\n    this.iterators = iterators.map(toIterator)[Symbol.iterator]();\n  }\n\n  async next() {\n    const next = await this.currentIterator.next();\n    if (!next.done) {\n      return next;\n    }\n    const iterator = this.iterators.next();\n    if (iterator.done) {\n      return iterator;\n    }\n    this.currentIterator = iterator.value;\n    return this.next();\n  }\n}\n\nclass EnumerateIterator extends AsyncIterator {\n  constructor(base) {\n    super(base);\n    this.index = 0;\n  }\n\n  async next() {\n    const next = await this.base.next();\n    if (next.done) {\n      return next;\n    }\n    return { done: false, value: [this.index++, next.value] };\n  }\n}\n\nclass ThrottleIterator extends AsyncIterator {\n  constructor(base, percent = 0.7, min = 5) {\n    super(base);\n    this.min = min;\n    this.ratio = percent / (1 - percent);\n\n    this.sum = 0;\n    this.count = 0;\n    this.begin = Date.now();\n    this.iterMax = this.min;\n  }\n\n  async next() {\n    if (this.iterMax > this.count) {\n      this.count++;\n      return this.base.next();\n    }\n\n    this.sum += Date.now() - this.begin;\n    const itemTime = this.sum / this.count;\n\n    this.begin = Date.now();\n    await timeout();\n    const loopTime = Date.now() - this.begin;\n\n    const number = Math.max((this.ratio * loopTime) / itemTime, this.min);\n\n    this.iterMax = Math.round(number) + this.count;\n\n    this.count++;\n    this.begin = Date.now();\n    return this.base.next();\n  }\n}\n\n// Create an AsyncIterator instance\n//   base - <Iterable> | <AsyncIterable>, an iterable\n//       that is wrapped in <AsyncIterator>\n//\n// Returns: <AsyncIterator>\nconst asyncIter = (base) => new AsyncIterator(base);\n\nmodule.exports = { asyncIter, AsyncIterator };\n"
  },
  {
    "path": "lib/collector.class.js",
    "content": "'use strict';\n\nconst emptiness = () => {};\nconst once = (callback) => {\n  let called = false;\n  return (...args) => {\n    if (!called) {\n      called = true;\n      callback(...args);\n    }\n  };\n};\n\nconst UNEXPECTED_KEY = 'Metasync: unexpected key: ';\nconst COLLECT_TIMEOUT = 'Metasync: Collector timed out';\nconst COLLECT_CANCELED = 'Metasync: Collector cancelled';\n\nclass Collector {\n  // Collector constructor\n  //   expected - <number> | <string[]>, count or keys\n  constructor(expected) {\n    this.expectKeys = Array.isArray(expected) ? new Set(expected) : null;\n    this.expected = this.expectKeys ? expected.length : expected;\n    this.keys = new Set();\n    this.count = 0;\n    this.timer = null;\n    this.onDone = emptiness;\n    this.isDistinct = false;\n    this.isDone = false;\n    this.data = {};\n  }\n\n  collect(key, err, value) {\n    if (this.isDone) return this;\n    if (err) {\n      this.finalize(err, this.data);\n      return this;\n    }\n    if (this.expectKeys && !this.expectKeys.has(key)) {\n      if (this.isDistinct) {\n        const err = new Error(UNEXPECTED_KEY + key);\n        this.finalize(err, this.data);\n        return this;\n      }\n    } else if (!this.keys.has(key)) {\n      this.count++;\n    }\n    this.data[key] = value;\n    this.keys.add(key);\n    if (this.expected === this.count) {\n      this.finalize(null, this.data);\n    }\n    return this;\n  }\n\n  pick(key, value) {\n    this.collect(key, null, value);\n    return this;\n  }\n\n  fail(key, err) {\n    this.collect(key, err);\n    return this;\n  }\n\n  take(key, fn, ...args) {\n    fn(...args, (err, data) => {\n      this.collect(key, err, data);\n    });\n    return this;\n  }\n\n  timeout(msec) {\n    if (this.timer) {\n      clearTimeout(this.timer);\n      this.timer = null;\n    }\n    if (msec > 0) {\n      this.timer = setTimeout(() => {\n        const err = new Error(COLLECT_TIMEOUT);\n        this.finalize(err, this.data);\n      }, msec);\n    }\n    return this;\n  }\n\n  done(callback) {\n    this.onDone = callback;\n    return this;\n  }\n\n  finalize(key, err, data) {\n    if (this.isDone) return this;\n    if (this.onDone) {\n      if (this.timer) {\n        clearTimeout(this.timer);\n        this.timer = null;\n      }\n      this.isDone = true;\n      this.onDone(key, err, data);\n    }\n    return this;\n  }\n\n  distinct(value = true) {\n    this.isDistinct = value;\n    return this;\n  }\n\n  cancel(err) {\n    err = err || new Error(COLLECT_CANCELED);\n    this.finalize(err, this.data);\n    return this;\n  }\n\n  then(fulfilled, rejected) {\n    const fulfill = once(fulfilled);\n    const reject = once(rejected);\n    this.onDone = (err, result) => {\n      if (err) reject(err);\n      else fulfill(result);\n    };\n    return this;\n  }\n}\n\n// Collector instance constructor\n//   expected - <number> | <string[]>\n//\n// Returns: <Collector>\nconst collect = (expected) => new Collector(expected);\n\nmodule.exports = { collect };\n"
  },
  {
    "path": "lib/collector.functor.js",
    "content": "'use strict';\n\nconst TYPE_ERROR = 'Metasync: Collect unexpected type';\nconst COLLECT_TIMEOUT = 'Metasync: Collector timed out';\n\n// Collector instance constructor\n//   expected - <number> | <string[]>, count or keys\n//\n// Returns: <Function>, functor, collector\nconst collect = (expected) => {\n  const isCount = typeof expected === 'number';\n  const isKeys = Array.isArray(expected);\n  if (!(isCount || isKeys)) throw new TypeError(TYPE_ERROR);\n  let keys = null;\n  if (isKeys) {\n    keys = new Set(expected);\n    expected = expected.length;\n  }\n  let count = 0;\n  let timer = null;\n  let onDone = null;\n  let isDistinct = false;\n  let isDone = false;\n  const data = {};\n\n  const collector = (key, err, value) => {\n    if (isDone) return collector;\n    if (!isDistinct || !(key in data)) {\n      if (!isCount && !keys.has(key)) return collector;\n      count++;\n    }\n    if (err) {\n      collector.finalize(err, data);\n      return collector;\n    }\n    data[key] = value;\n    if (expected === count) {\n      if (timer) clearTimeout(timer);\n      collector.finalize(null, data);\n    }\n    return collector;\n  };\n\n  const methods = {\n    pick: (key, value) => collector(key, null, value),\n    fail: (key, err) => collector(key, err),\n\n    take: (key, fn, ...args) => {\n      fn(...args, (err, data) => collector(key, err, data));\n      return collector;\n    },\n\n    timeout: (msec) => {\n      if (msec) {\n        timer = setTimeout(() => {\n          const err = new Error(COLLECT_TIMEOUT);\n          collector.finalize(err, data);\n        }, msec);\n        timer.unref();\n      }\n      return collector;\n    },\n\n    // Call on done\n    //   callback - <Function>\n    //     error - <Error> | <null>\n    //     data - <Object>\n    done: (callback) => {\n      onDone = callback;\n      return collector;\n    },\n\n    finalize: (err, data) => {\n      if (isDone) return collector;\n      isDone = true;\n      if (onDone) onDone(err, data);\n      return collector;\n    },\n\n    distinct: (value = true) => {\n      isDistinct = value;\n      return collector;\n    },\n  };\n\n  return Object.assign(collector, methods);\n};\n\nmodule.exports = { collect };\n"
  },
  {
    "path": "lib/collector.js",
    "content": "'use strict';\n\nconst emptiness = () => {};\n\nconst UNEXPECTED_KEY = 'Metasync: unexpected key: ';\nconst COLLECT_TIMEOUT = 'Metasync: Collector timed out';\nconst COLLECT_CANCELED = 'Metasync: Collector cancelled';\n\n// Data collector\n//   expected - <number> | <string[]>, count or keys\nfunction Collector(expected) {\n  this.expectKeys = Array.isArray(expected) ? new Set(expected) : null;\n  this.expected = this.expectKeys ? expected.length : expected;\n  this.keys = new Set();\n  this.count = 0;\n  this.timer = null;\n  this.onDone = emptiness;\n  this.isDistinct = false;\n  this.isDone = false;\n  this.data = {};\n}\n\n// Pick or fail key\n//   key - <string>\n//   err - <Error>\n//   value - <any>\n//\n// Returns: <this>\nCollector.prototype.collect = function (key, err, value) {\n  if (this.isDone) return this;\n  if (err) {\n    this.finalize(err, this.data);\n    return this;\n  }\n  if (this.expectKeys && !this.expectKeys.has(key)) {\n    if (this.isDistinct) {\n      const err = new Error(UNEXPECTED_KEY + key);\n      this.finalize(err, this.data);\n      return this;\n    }\n  } else if (!this.keys.has(key)) {\n    this.count++;\n  }\n  this.data[key] = value;\n  this.keys.add(key);\n  if (this.expected === this.count) {\n    this.finalize(null, this.data);\n  }\n  return this;\n};\n\n// Pick key\n//   key - <string>\n//   value - <any>\n//\n// Returns: <this>\nCollector.prototype.pick = function (key, value) {\n  this.collect(key, null, value);\n  return this;\n};\n\n// Fail key\n//   key - <string>\n//   err - <Error>\n//\n// Returns: <this>\nCollector.prototype.fail = function (key, err) {\n  this.collect(key, err);\n  return this;\n};\n\n// Take method result\n//   key - <string>\n//   fn - <Function>\n//   args - <Array>, rest arguments, to be passed in fn\n//\n// Returns: <this>\nCollector.prototype.take = function (key, fn, ...args) {\n  fn(...args, (err, data) => {\n    this.collect(key, err, data);\n  });\n  return this;\n};\n\n// Set timeout\n//   msec - <number>\n//\n// Returns: <this>\nCollector.prototype.timeout = function (msec) {\n  if (this.timer) {\n    clearTimeout(this.timer);\n    this.timer = null;\n  }\n  if (msec > 0) {\n    this.timer = setTimeout(() => {\n      const err = new Error(COLLECT_TIMEOUT);\n      this.finalize(err, this.data);\n    }, msec);\n  }\n  return this;\n};\n\n// Set on done listener\n//   callback - <Function>\n//     err - <Error>\n//     data - <any>\n//\n// Returns: <this>\nCollector.prototype.done = function (callback) {\n  this.onDone = callback;\n  return this;\n};\n\nCollector.prototype.finalize = function (key, err, data) {\n  if (this.isDone) return this;\n  if (this.timer) {\n    clearTimeout(this.timer);\n    this.timer = null;\n  }\n  this.isDone = true;\n  this.onDone(key, err, data);\n  return this;\n};\n\n// Deny or allow unlisted keys\n//   value - <boolean>\n//\n// Returns: <this>\nCollector.prototype.distinct = function (value = true) {\n  this.isDistinct = value;\n  return this;\n};\n\nCollector.prototype.cancel = function (err) {\n  err = err || new Error(COLLECT_CANCELED);\n  this.finalize(err, this.data);\n  return this;\n};\n\nCollector.prototype.then = function (fulfill, reject) {\n  if (!fulfill) fulfill = emptiness;\n  if (!reject) reject = emptiness;\n  this.onDone = (err, result) => {\n    this.onDone = emptiness;\n    if (err) reject(err);\n    else fulfill(result);\n  };\n  return this;\n};\n\n// Create Collector instance\n//   expected - <number> | <string[]>\n//\n// Returns: <Collector>\nconst collect = (expected) => new Collector(expected);\n\nmodule.exports = { collect, Collector };\n"
  },
  {
    "path": "lib/collector.prototype.js",
    "content": "'use strict';\n\nconst inherits = (child, parent) => {\n  child.prototype = Object.create(parent.prototype);\n  child.prototype.constructor = child;\n};\n\nfunction Collector() {}\n\nconst COLLECT_TIMEOUT = 'Metasync: Collector timed out';\n\n// Add event listener\n//   eventName - <string>\n//   listener - <Function>, handler\n//\n// Example:\n// const collector = new Collector();\n// collector.on('error', (err, key) => { ... });\n// collector.on('timeout', (err, data) => { ... });\n// collector.on('done', (errs, data) => { ... })\nCollector.prototype.on = function (eventName, listener) {\n  if (eventName in this.events) {\n    this.events[eventName] = listener;\n  }\n};\n\n// Emit Collector events\n//   eventName - <string>\n//   err - <Error> | <null>\nCollector.prototype.emit = function (eventName, err, data) {\n  const event = this.events[eventName];\n  if (event) event(err, data);\n};\n\n// Create new DataCollector\n// Signature: expected[, timeout]\n//   expected - <number>, count of `collect()` calls expected\n//   timeout - <number>, collect timeout, optional\n//\n// Returns: <DataCollector>\nconst DataCollector = function (expected, timeout) {\n  this.expected = expected;\n  this.timeout = timeout;\n  this.count = 0;\n  this.data = {};\n  this.errs = [];\n  this.events = {\n    error: null,\n    timeout: null,\n    done: null,\n  };\n  if (this.timeout) {\n    this.timer = setTimeout(() => {\n      const err = new Error(COLLECT_TIMEOUT);\n      this.emit('timeout', err, this.data);\n    }, timeout);\n  }\n};\n\ninherits(DataCollector, Collector);\n\n// Push data to collector\n//   key - <string>, key in result data\n//   data - <Object> | <Error>, value or error\nDataCollector.prototype.collect = function (key, data) {\n  this.count++;\n  if (data instanceof Error) {\n    this.errs[key] = data;\n    this.emit('error', data, key);\n  } else {\n    this.data[key] = data;\n  }\n  if (this.expected === this.count) {\n    if (this.timer) clearTimeout(this.timer);\n    const errs = this.errs.length ? this.errs : null;\n    this.emit('done', errs, this.data);\n  }\n};\n\n// Key Collector\n// Signature: keys[, timeout]\n//   keys - <string[]>\n//   timeout - <number>, collect timeout, optional\n//\n// Returns: <DataCollector>\n//\n// Example: new KeyCollector(['config', 'users', 'cities'])\nconst KeyCollector = function (keys, timeout) {\n  this.isDone = false;\n  this.keys = keys;\n  this.expected = keys.length;\n  this.count = 0;\n  this.timeout = timeout;\n  this.data = {};\n  this.errs = [];\n  this.events = {\n    error: null,\n    timeout: null,\n    done: null,\n  };\n  const collector = this;\n  if (this.timeout) {\n    this.timer = setTimeout(() => {\n      const err = new Error(COLLECT_TIMEOUT);\n      collector.emit('timeout', err, collector.data);\n    }, timeout);\n  }\n};\n\ninherits(KeyCollector, Collector);\n// Collect keys and data\n//   key - <string>\n//   data - <scalar> | <Object> | <Error>, value or error\nKeyCollector.prototype.collect = function (key, data) {\n  if (this.keys.includes(key)) {\n    this.count++;\n    if (data instanceof Error) {\n      this.errs[key] = data;\n      this.emit('error', data, key);\n    } else {\n      this.data[key] = data;\n    }\n    if (this.expected === this.count) {\n      if (this.timer) clearTimeout(this.timer);\n      const errs = this.errs.length ? this.errs : null;\n      this.emit('done', errs, this.data);\n    }\n  }\n};\n\nKeyCollector.prototype.stop = function () {};\n\nKeyCollector.prototype.pause = function () {};\n\nKeyCollector.prototype.resume = function () {};\n\nmodule.exports = { DataCollector, KeyCollector };\n"
  },
  {
    "path": "lib/composition.js",
    "content": "'use strict';\n\nfunction Composition() {}\n\nconst COMPOSE_CANCELED = 'Metasync: asynchronous composition canceled';\nconst COMPOSE_TIMEOUT = 'Metasync: asynchronous composition timed out';\n\n// Asynchronous functions composition\n// Array of functions results in sequential execution: `[f1, f2, f3]`\n// Double brackets array of functions results\n// in parallel execution: `[[f1, f2, f3]]`\n//   flow - <Function[]>, callback-last / err-first\n//\n// Returns: <Function>, composed callback-last / err-first\n//\n// Example:\n// const composed = metasync([f1, f2, f3, [[f4, f5, [f6, f7], f8]], f9]);\nconst compose = (flow) => {\n  const comp = (data, callback) => {\n    if (!callback) {\n      if (typeof data === 'function') {\n        callback = data;\n        data = {};\n      } else {\n        comp.data = data;\n        return comp;\n      }\n    }\n    comp.done = callback;\n    if (comp.canceled) {\n      if (callback) {\n        callback(new Error(COMPOSE_CANCELED));\n      }\n      return comp;\n    }\n    if (comp.timeout) {\n      comp.timer = setTimeout(() => {\n        comp.timer = null;\n        if (callback) {\n          callback(new Error(COMPOSE_TIMEOUT));\n          comp.done = null;\n        }\n      }, comp.timeout);\n    }\n    comp.context = data;\n    comp.arrayed = Array.isArray(comp.context);\n    comp.paused = false;\n    if (comp.len === 0) {\n      comp.finalize();\n      return comp;\n    }\n    if (comp.parallelize) comp.parallel();\n    else comp.sequential();\n    return comp;\n  };\n  const first = flow[0];\n  const parallelize = flow.length === 1 && Array.isArray(first);\n  const fns = parallelize ? first : flow;\n  comp.fns = fns;\n  comp.parallelize = parallelize;\n  comp.context = null;\n  comp.timeout = 0;\n  comp.timer = null;\n  comp.len = fns.length;\n  comp.canceled = false;\n  comp.paused = true;\n  comp.arrayed = false;\n  comp.done = null;\n  comp.onResume = null;\n  Object.setPrototypeOf(comp, Composition.prototype);\n  return comp;\n};\n\nComposition.prototype.on = function (name, callback) {\n  if (name === 'resume') {\n    this.onResume = callback;\n  }\n};\n\nComposition.prototype.finalize = function (err) {\n  if (this.canceled) return;\n  if (this.timer) {\n    clearTimeout(this.timer);\n    this.timer = null;\n  }\n  const callback = this.done;\n  if (callback) {\n    if (this.paused) {\n      this.on('resume', () => {\n        this.done = null;\n        callback(err, this.context);\n      });\n    } else {\n      this.done = null;\n      callback(err, this.context);\n    }\n  }\n};\n\nComposition.prototype.collect = function (err, result) {\n  if (this.canceled) return;\n  if (err) {\n    const callback = this.done;\n    if (callback) {\n      this.done = null;\n      callback(err);\n    }\n    return;\n  }\n  if (result !== this.context && result !== undefined) {\n    if (this.arrayed) {\n      this.context.push(result);\n    } else if (typeof result === 'object') {\n      Object.assign(this.context, result);\n    }\n  }\n};\n\nComposition.prototype.parallel = function () {\n  let counter = 0;\n  const next = (err, result) => {\n    this.collect(err, result);\n    if (++counter === this.len) this.finalize();\n  };\n  const fns = this.fns;\n  const len = this.len;\n  const context = this.context;\n  for (let i = 0; i < len; i++) {\n    const fn = fns[i];\n    const fc = Array.isArray(fn) ? compose(fn) : fn;\n    fc(context, next);\n  }\n};\n\nComposition.prototype.sequential = function () {\n  let counter = -1;\n  const fns = this.fns;\n  const len = this.len;\n  const context = this.context;\n  const next = (err, result) => {\n    if (this.canceled) return;\n    if (err || result) this.collect(err, result);\n    if (++counter === len) return void this.finalize();\n    const fn = fns[counter];\n    const fc = Array.isArray(fn) ? compose(fn) : fn;\n    if (this.paused) {\n      this.on('resume', () => fc(context, next));\n    } else {\n      fc(context, next);\n    }\n  };\n  next();\n};\n\nComposition.prototype.then = function (fulfill, reject) {\n  if (this.canceled) {\n    reject(new Error(COMPOSE_CANCELED));\n    return this;\n  }\n  this((err, result) => {\n    if (err) reject(err);\n    else fulfill(result);\n  });\n  return this;\n};\n\n// Clone composed\nComposition.prototype.clone = function () {\n  const fns = this.fns.slice();\n  const flow = this.parallelize ? [fns] : fns;\n  return compose(flow);\n};\n\n// Pause execution\nComposition.prototype.pause = function () {\n  if (this.canceled) return this;\n  this.paused = true;\n  return this;\n};\n\n// Resume execution\nComposition.prototype.resume = function () {\n  if (this.canceled) return this;\n  this.paused = false;\n  if (this.onResume) {\n    const callback = this.onResume;\n    this.onResume = null;\n    callback();\n  }\n  return this;\n};\n\n// Set timeout\n//   msec - <number>\nComposition.prototype.timeout = function (msec) {\n  this.timeout = msec;\n  return this;\n};\n\n// Cancel execution where possible\nComposition.prototype.cancel = function () {\n  if (this.canceled) return this;\n  this.canceled = true;\n  const callback = this.done;\n  if (callback) {\n    this.done = null;\n    callback(new Error(COMPOSE_CANCELED));\n  }\n  return this;\n};\n\nmodule.exports = { compose, Composition };\n"
  },
  {
    "path": "lib/control.js",
    "content": "'use strict';\n\nconst once = (callback) => {\n  let called = false;\n  return (...args) => {\n    if (!called) {\n      called = true;\n      callback(...args);\n    }\n  };\n};\nconst last = (arr) => arr[arr.length - 1];\n\nconst { each } = require('./array');\n\n// Executes all asynchronous functions and pass first result to callback\n//   fns - <Function[]>, callback-last / err-first\n//   callback - <Function>, on done, err-first\nconst firstOf = (fns, callback) => {\n  const done = once(callback);\n  each(fns, (f, iterCb) =>\n    f((...args) => {\n      done(...args);\n      iterCb(...args);\n    }),\n  );\n};\n\n// Parallel execution\n// Signature: fns[, context], callback\n//   fns - <Function[]>, callback-last / err-first\n//   context - <Object>, incoming data, optional\n//   callback - <Function>, on done, err-first\n//\n// Example:\n// metasync.parallel([f1, f2, f3], (err, data) => {});\nconst parallel = (fns, context, callback) => {\n  if (!callback) {\n    callback = context;\n    context = {};\n  }\n  const done = once(callback);\n  const isArray = Array.isArray(context);\n  const len = fns.length;\n  if (len === 0) return void done(null, context);\n  let counter = 0;\n\n  const finishFn = (fn, err, result) => {\n    if (err) return void done(err);\n    if (result !== context && result !== undefined) {\n      if (isArray) context.push(result);\n      else if (typeof result === 'object') Object.assign(context, result);\n    }\n    if (++counter === len) done(null, context);\n  };\n\n  // fn may be array of function\n  for (const fn of fns) {\n    const finish = finishFn.bind(null, fn);\n    if (fn.length === 2) fn(context, finish);\n    else fn(finish);\n  }\n};\n\n// Sequential execution\n// Signature: fns[, context], callback\n//   fns - <Function[]>, callback-last with err-first contract\n//   context - <Object>, incoming data, optional\n//   callback - <Function>, err-first on done\n//\n// Example:\n// metasync.sequential([f1, f2, f3], (err, data) => {});\nconst sequential = (fns, context, callback) => {\n  if (!callback) {\n    callback = context;\n    context = {};\n  }\n  const done = once(callback);\n  const isArray = Array.isArray(context);\n  const len = fns.length;\n  if (len === 0) return void done(null, context);\n  let i = -1;\n\n  const next = () => {\n    let fn = null;\n    const finish = (err, result) => {\n      if (result !== context && result !== undefined) {\n        if (isArray) context.push(result);\n        else if (typeof result === 'object') Object.assign(context, result);\n      }\n      if (err) return void done(err);\n      next();\n    };\n    if (++i === len) return void done(null, context);\n    fn = fns[i];\n    if (fn.length === 2) fn(context, finish);\n    else fn(finish);\n  };\n\n  next();\n};\n\n// Run `asyncFn` if `condition` is truthy, else return `defaultVal` to callback.\n// Signature: condition[, defaultVal], asyncFn, ...args\n//   condition - <any>\n//   defaultVal - <any>, optional, value that will be returned to callback if\n//       `condition` is falsy.\n//   asyncFn - <Function>, callback-last function that will be executed if\n//       `condition` if truthy\n//   args - <any[]>, args to pass to `asyncFn`\nconst runIf = (condition, defaultVal, asyncFn, ...args) => {\n  if (typeof defaultVal === 'function') {\n    args.unshift(asyncFn);\n    asyncFn = defaultVal;\n    defaultVal = undefined;\n  }\n  if (condition) {\n    asyncFn(...args);\n  } else {\n    const callback = last(args);\n    process.nextTick(callback, null, defaultVal);\n  }\n};\n\n// Run `asyncFn` if it is provided\n// Signature: asyncFn, ...args\n//   asyncFn - <Function>, callback-last function that will be executed if it\n//       is provided\n//   args - <any[]>, args to pass to `asyncFn`\nconst runIfFn = (asyncFn, ...args) => {\n  runIf(asyncFn, undefined, asyncFn, ...args);\n};\n\nmodule.exports = {\n  firstOf,\n  parallel,\n  sequential,\n  runIf,\n  runIfFn,\n};\n"
  },
  {
    "path": "lib/do.js",
    "content": "'use strict';\n\nfunction Do() {}\n\nconst chain = function (fn, ...args) {\n  const current = (done) => {\n    if (done) current.done = done;\n    if (current.prev) {\n      current.prev.next = current;\n      current.prev();\n    } else {\n      current.forward();\n    }\n    return current;\n  };\n\n  const prev = this instanceof Do ? this : null;\n  const fields = { prev, fn, args, done: null };\n\n  Object.setPrototypeOf(current, Do.prototype);\n  return Object.assign(current, fields);\n};\n\nDo.prototype.do = function (fn, ...args) {\n  return chain.call(this, fn, ...args);\n};\n\nDo.prototype.forward = function () {\n  if (this.fn) {\n    this.fn(...this.args, (err, data) => {\n      const next = this.next;\n      if (next) {\n        if (next.fn) next.forward();\n      } else if (this.done) {\n        this.done(err, data);\n      }\n    });\n  }\n};\n\nmodule.exports = { do: chain };\n"
  },
  {
    "path": "lib/fp.js",
    "content": "'use strict';\n\nlet asyncChainMethods = null;\n// Convert synchronous function to asynchronous\n// Transform function with args arguments and callback\n// to function with args as separate values and callback\n//   fn - <Function>, callback-last / err-first\n//\n// Returns: <Function>\nconst toAsync =\n  (fn) =>\n  (...argsCb) => {\n    const len = argsCb.length - 1;\n    const callback = argsCb[len];\n    const args = argsCb.slice(0, len);\n    return fn(args, callback);\n  };\n\n// Wrap function adding async chain methods\n//   fn - <Function>, asynchronous\n//   args - <Array>, its arguments\nconst asAsync = (fn, ...args) => {\n  const wrapped = fn.bind(null, ...args);\n  for (const name in asyncChainMethods) {\n    const method = asyncChainMethods[name];\n    wrapped[name] = (...args) => asAsync(method(wrapped, ...args));\n  }\n  return wrapped;\n};\n\n// Applicative f => a -> f a\n//   args - <Array>\nconst of = (...args) => asAsync((callback) => callback(null, ...args));\n\n// Monoid m => a -> a -> a\n//   fn1 - <Function>\n//   fn2 - <Function>\nconst concat = (fn1, fn2) =>\n  toAsync((args1, callback) =>\n    fn1(...args1, (err, ...args2) => {\n      if (err !== null) callback(err);\n      else fn2(...args2, callback);\n    }),\n  );\n\n// Functor f => (a -> b) -> f a -> f b\n//   fn1 - <Function>\n//   f - <Function>\nconst fmap = (fn1, f) => {\n  const fn2 = toAsync((args, callback) => of(f(...args))(callback));\n  return concat(fn1, fn2);\n};\n\n// Applicative f => f (a -> b) -> f a -> f b\n//   fn - <Function>\n//   funcA - <Function>\nconst ap = (fn, funcA) => concat(funcA, (f, callback) => fmap(fn, f)(callback));\n\nasyncChainMethods = { fmap, ap, concat };\n\nmodule.exports = {\n  toAsync,\n  asAsync,\n  of,\n  concat,\n  fmap,\n  ap,\n};\n"
  },
  {
    "path": "lib/memoize.js",
    "content": "'use strict';\n\nfunction Memoized() {}\n\n// Create memoized function\n//   fn - <Function>, sync or async\n//\n// Returns: <Function>, memoized\nconst memoize = (fn) => {\n  const cache = new Map();\n\n  const memoized = function (...args) {\n    const callback = args.pop();\n    const key = args[0];\n    const record = cache.get(key);\n    if (record) return void callback(record.err, record.data);\n    fn(...args, (err, data) => {\n      memoized.add(key, err, data);\n      memoized.emit('memoize', key, err, data);\n      callback(err, data);\n    });\n  };\n\n  const fields = {\n    cache,\n    timeout: 0,\n    limit: 0,\n    size: 0,\n    maxSize: 0,\n    maxCount: 0,\n    events: {\n      timeout: null,\n      memoize: null,\n      overflow: null,\n      add: null,\n      del: null,\n      clear: null,\n    },\n  };\n\n  Object.setPrototypeOf(memoized, Memoized.prototype);\n  return Object.assign(memoized, fields);\n};\n\nMemoized.prototype.clear = function () {\n  this.emit('clear');\n  this.cache.clear();\n};\n\nMemoized.prototype.add = function (key, err, data) {\n  this.emit('add', err, data);\n  this.cache.set(key, { err, data });\n  return this;\n};\n\nMemoized.prototype.del = function (key) {\n  this.emit('del', key);\n  this.cache.delete(key);\n  return this;\n};\n\nMemoized.prototype.get = function (key, callback) {\n  const record = this.cache.get(key);\n  callback(record.err, record.data);\n  return this;\n};\n\n// Add event listener\n//   eventName - <string>\n//   listener - <Function>, handler\n//\n// Example:\n// const memoized = new Memoized();\n// memoized.on('memoize', (err, data) => { ... });\n// memoized.on('add', (key, err, data) => { ... });\n// memoized.on('del', (key) => { ... })\n// memoized.on('clear', () => { ... })\nMemoized.prototype.on = function (eventName, listener) {\n  if (eventName in this.events) {\n    this.events[eventName] = listener;\n  }\n};\n\n// Emit Memoized events\n//   eventName - <string>\n//   args - <any>, rest arguments\nMemoized.prototype.emit = function (eventName, ...args) {\n  const event = this.events[eventName];\n  if (event) event(...args);\n};\n\nmodule.exports = { memoize, Memoized };\n"
  },
  {
    "path": "lib/poolify.js",
    "content": "'use strict';\n\nconst duplicate = (factory, n) => Array.from({ length: n }, factory);\n\nconst provide = (callback) => (item) => {\n  setImmediate(() => {\n    callback(item);\n  });\n};\n\nconst poolify = (factory, min, norm, max) => {\n  let allocated = norm;\n  const pool = (par) => {\n    if (Array.isArray(par)) {\n      while (par.length) {\n        const item = par.shift();\n        const delayed = pool.delayed.shift();\n        if (delayed) delayed(item);\n        else pool.items.push(item);\n      }\n      return pool;\n    }\n    if (pool.items.length < min && allocated < max) {\n      const grow = Math.min(max - allocated, norm - pool.items.length);\n      allocated += grow;\n      const items = duplicate(factory, grow);\n      pool.items.push(...items);\n    }\n    const res = pool.items.pop();\n    if (!par) return res;\n    const callback = provide(par);\n    if (res) callback(res);\n    else pool.delayed.push(callback);\n    return pool;\n  };\n  return Object.assign(pool, {\n    items: duplicate(factory, norm),\n    delayed: [],\n  });\n};\n\nmodule.exports = { poolify };\n"
  },
  {
    "path": "lib/poolify.opt.js",
    "content": "'use strict';\n\nconst duplicate = (factory, n) => Array.from({ length: n }, factory);\n\nconst provide = (callback) => (item) => {\n  setImmediate(() => {\n    callback(item);\n  });\n};\n\nconst poolify = (factory, min, norm, max) => {\n  let allocated = norm;\n  const items = duplicate(factory, norm);\n  const delayed = [];\n  const pool = (par) => {\n    if (Array.isArray(par)) {\n      while (par.length) {\n        const item = par.shift();\n        const request = delayed.shift();\n        if (request) request(item);\n        else items.push(item);\n      }\n      return pool;\n    }\n    if (items.length < min && allocated < max) {\n      const grow = Math.min(max - allocated, norm - items.length);\n      allocated += grow;\n      const instances = duplicate(factory, grow);\n      items.push(...instances);\n    }\n    const res = items.pop();\n    if (!par) return res;\n    const callback = provide(par);\n    if (res) callback(res);\n    else delayed.push(callback);\n    return pool;\n  };\n  return pool;\n};\n\nmodule.exports = { poolify };\n"
  },
  {
    "path": "lib/poolify.symbol.js",
    "content": "'use strict';\n\nconst poolified = Symbol('poolified');\n\nconst mixFlag = { [poolified]: true };\n\nconst duplicate = (factory, n) =>\n  Array.from({ length: n }, factory).map((instance) =>\n    Object.assign(instance, mixFlag),\n  );\n\nconst provide = (callback) => (item) => {\n  setImmediate(() => {\n    callback(item);\n  });\n};\n\nconst poolify = (factory, min, norm, max) => {\n  let allocated = norm;\n  const pool = (par) => {\n    if (par && par[poolified]) {\n      const delayed = pool.delayed.shift();\n      if (delayed) delayed(par);\n      else pool.items.push(par);\n      return pool;\n    }\n    if (pool.items.length < min && allocated < max) {\n      const grow = Math.min(max - allocated, norm - pool.items.length);\n      allocated += grow;\n      const items = duplicate(factory, grow);\n      pool.items.push(...items);\n    }\n    const res = pool.items.pop();\n    if (!par) return res;\n    const callback = provide(par);\n    if (res) callback(res);\n    else pool.delayed.push(callback);\n    return pool;\n  };\n  return Object.assign(pool, {\n    items: duplicate(factory, norm),\n    delayed: [],\n  });\n};\n\nmodule.exports = { poolify };\n"
  },
  {
    "path": "lib/queue.js",
    "content": "'use strict';\n\n// Queue constructor\n//   concurrency - <number>, asynchronous concurrency\nfunction Queue(concurrency) {\n  this.paused = false;\n  this.concurrency = concurrency;\n  this.waitTimeout = 0;\n  this.processTimeout = 0;\n  this.throttleCount = 0;\n  this.throttleInterval = 1000;\n  this.count = 0;\n  this.tasks = [];\n  this.waiting = [];\n  this.factors = {};\n  this.fifoMode = true;\n  this.roundRobinMode = false;\n  this.priorityMode = false;\n  this.onProcess = null;\n  this.onDone = null;\n  this.onSuccess = null;\n  this.onTimeout = null;\n  this.onFailure = null;\n  this.onDrain = null;\n}\n\nconst QUEUE_TIMEOUT = 'Metasync: Queue timed out';\n\n// Set wait before processing timeout\n//   msec - <number>, wait timeout for single item\n//\n// Returns: <this>\nQueue.prototype.wait = function (msec) {\n  this.waitTimeout = msec;\n  return this;\n};\n\n// Throttle to limit throughput\n// Signature: count[, interval]\n//   count - <number>, item count\n//   interval - <number>, per interval, optional\n//       default: 1000 msec\n//\n// Returns: <this>\nQueue.prototype.throttle = function (count, interval = 1000) {\n  this.throttleCount = count;\n  this.throttleInterval = interval;\n  return this;\n};\n\n// Add item to queue\n// Signature: item[, factor[, priority]]\n//   item - <Object>, to be added\n//   factor - <number> | <string>, type, source,\n//       destination or path, optional\n//   priority - <number>, optional\n//\n// Returns: <this>\nQueue.prototype.add = function (item, factor = 0, priority = 0) {\n  if (this.priorityMode && !this.roundRobinMode) {\n    priority = factor;\n    factor = 0;\n  }\n  const task = [item, factor, priority];\n  const slot = this.count < this.concurrency;\n  if (!this.paused && slot && this.onProcess) {\n    this.next(task);\n    return this;\n  }\n  let tasks;\n  if (this.roundRobinMode) {\n    tasks = this.factors[factor];\n    if (!tasks) {\n      tasks = [];\n      this.factors[factor] = tasks;\n      this.waiting.push(tasks);\n    }\n  } else {\n    tasks = this.tasks;\n  }\n\n  if (this.fifoMode) tasks.push(task);\n  else tasks.unshift(task);\n\n  if (this.priorityMode) {\n    if (this.fifoMode) {\n      tasks.sort((a, b) => b[2] - a[2]);\n    } else {\n      tasks.sort((a, b) => a[2] - b[2]);\n    }\n  }\n  return this;\n};\n\n// Process next item\n//   task - <Array>, next task [item, factor, priority]\n//\n// Returns: <this>\nQueue.prototype.next = function (task) {\n  const item = task[0];\n  let timer;\n  this.count++;\n  if (this.processTimeout) {\n    timer = setTimeout(() => {\n      const err = new Error(QUEUE_TIMEOUT);\n      if (this.onTimeout) this.onTimeout(err);\n    }, this.processTimeout);\n  }\n  this.onProcess(item, (err, result) => {\n    if (this.onDone) this.onDone(err, result);\n    if (err) {\n      if (this.onFailure) this.onFailure(err);\n    } else if (this.onSuccess) {\n      this.onSuccess(result);\n    }\n    if (timer) {\n      clearTimeout(timer);\n      timer = null;\n    }\n    this.count--;\n    if (this.tasks.length > 0 || this.waiting.length > 0) {\n      this.takeNext();\n    } else if (this.count === 0 && this.onDrain) {\n      this.onDrain();\n    }\n  });\n  return this;\n};\n\n// Prepare next item for processing\n//\n// Returns: <this>\nQueue.prototype.takeNext = function () {\n  if (this.paused || !this.onProcess) {\n    return this;\n  }\n  let tasks;\n  if (this.roundRobinMode) {\n    tasks = this.waiting.shift();\n    if (tasks.length > 1) {\n      this.waiting.push(tasks);\n    }\n  } else {\n    tasks = this.tasks;\n  }\n  const task = tasks.shift();\n  if (task) this.next(task);\n  return this;\n};\n\n// Pause queue\n// This function is not completely implemented yet\n//\n// Returns: <this>\nQueue.prototype.pause = function () {\n  this.paused = true;\n  return this;\n};\n\n// Resume queue\n// This function is not completely implemented yet\n//\n// Returns: <this>\nQueue.prototype.resume = function () {\n  this.paused = false;\n  return this;\n};\n\n// Clear queue\n//\n// Returns: <this>\nQueue.prototype.clear = function () {\n  this.count = 0;\n  this.tasks = [];\n  this.waiting = [];\n  this.factors = {};\n  return this;\n};\n\n// Set timeout interval and listener\n//   msec - <number>, process timeout for single item\n//   onTimeout - <Function>\n//\n// Returns: <this>\nQueue.prototype.timeout = function (msec, onTimeout = null) {\n  this.processTimeout = msec;\n  if (onTimeout) this.onTimeout = onTimeout;\n  return this;\n};\n\n// Set processing function\n//   fn - <Function>\n//     item - <Object>\n//     callback - <Function>\n//       err - <Error> | <null>\n//       result - <any>\n//\n// Returns: <this>\nQueue.prototype.process = function (fn) {\n  this.onProcess = fn;\n  return this;\n};\n\n// Set listener on processing done\n//   fn - <Function>, done listener\n//     err - <Error> | <null>\n//     result - <any>\n//\n// Returns: <this>\nQueue.prototype.done = function (fn) {\n  this.onDone = fn;\n  return this;\n};\n\n// Set listener on processing success\n//   listener - <Function>, on success\n//     item - <any>\n//\n// Returns: <this>\nQueue.prototype.success = function (listener) {\n  this.onSuccess = listener;\n  return this;\n};\n\n// Set listener on processing error\n//   listener - <Function>, on failure\n//     err - <Error> | <null>\n//\n// Returns: <this>\nQueue.prototype.failure = function (listener) {\n  this.onFailure = listener;\n  return this;\n};\n\n// Set listener on drain Queue\n//   listener - <Function>, on drain\n//\n// Returns: <this>\nQueue.prototype.drain = function (listener) {\n  this.onDrain = listener;\n  return this;\n};\n\n// Switch to FIFO mode (default for Queue)\n//\n// Returns: <this>\nQueue.prototype.fifo = function () {\n  this.fifoMode = true;\n  return this;\n};\n\n// Switch to LIFO mode\n//\n// Returns: <this>\nQueue.prototype.lifo = function () {\n  this.fifoMode = false;\n  return this;\n};\n\n// Activate or deactivate priority mode\n//   flag - <boolean>, default: true, false will\n//       disable priority mode\n//\n// Returns: <this>\nQueue.prototype.priority = function (flag = true) {\n  this.priorityMode = flag;\n  return this;\n};\n\n// Activate or deactivate round robin mode\n//   flag - <boolean>, default: true, false will\n//       disable roundRobin mode\n//\n// Returns: <this>\nQueue.prototype.roundRobin = function (flag = true) {\n  this.roundRobinMode = flag;\n  return this;\n};\n\n// Pipe processed items to different queue\n//   dest - <Queue>, destination queue\n//\n// Returns: <this>\nQueue.prototype.pipe = function (dest) {\n  if (dest instanceof Queue) {\n    this.success((item) => {\n      dest.add(item);\n    });\n  }\n  return this;\n};\n\n// Create Queue instance\n//   concurrency - <number>, simultaneous and\n//       asynchronously executing tasks\n//\n// Returns: <Queue>\nconst queue = (concurrency) => new Queue(concurrency);\n\nmodule.exports = { queue, Queue };\n"
  },
  {
    "path": "lib/throttle.js",
    "content": "'use strict';\n\n// Get throttling function, executed once per interval\n// Signature: timeout, fn, ...args\n//   timeout - <number>, msec interval\n//   fn - <Function>, to be throttled\n//   args - <Array>, arguments for fn, optional\n//\n// Returns: <Function>\nconst throttle = (timeout, fn, ...args) => {\n  let timer;\n  let wait = false;\n\n  const execute = args\n    ? (...pars) => (pars ? fn(...args, ...pars) : fn(...args))\n    : (...pars) => (pars ? fn(...pars) : fn());\n\n  const delayed = (...pars) => {\n    timer = undefined;\n    if (wait) execute(...pars);\n  };\n\n  const throttled = (...pars) => {\n    if (!timer) {\n      timer = setTimeout(delayed, timeout, ...pars);\n      wait = false;\n      execute(...pars);\n    }\n    wait = true;\n  };\n\n  return throttled;\n};\n\n// Debounce function, delayed execution\n// Signature: timeout, fn, ...args\n//   timeout - <number>, msec\n//   fn - <Function>, to be debounced\n//   args - <Array>, arguments for fn, optional\nconst debounce = (timeout, fn, ...args) => {\n  let timer;\n\n  const debounced = () => (args ? fn(...args) : fn());\n\n  const wrapped = () => {\n    if (timer) clearTimeout(timer);\n    timer = setTimeout(debounced, timeout);\n  };\n\n  return wrapped;\n};\n\nconst FN_TIMEOUT = 'Metasync: asynchronous function timed out';\n\n// Set timeout for asynchronous function execution\n//   timeout - <number>, time interval\n//   fn - <Function>, to be executed\n//   callback - <Function>, callback(...args), on done\n//     args - <Array>\nconst timeout = (timeout, fn, callback) => {\n  let finished = false;\n\n  const timer = setTimeout(() => {\n    finished = true;\n    callback(new Error(FN_TIMEOUT));\n  }, timeout);\n\n  fn((...args) => {\n    if (!finished) {\n      clearTimeout(timer);\n      finished = true;\n      callback(...args);\n    }\n  });\n};\n\nmodule.exports = {\n  throttle,\n  debounce,\n  timeout,\n};\n"
  },
  {
    "path": "metasync.d.ts",
    "content": "type Callback<T = unknown> = (err: Error | null, data?: T) => void;\ntype AsyncFunction<T = unknown, R = unknown> = (\n  data: T,\n  callback: Callback<R>,\n) => void;\ntype AsyncFunctionNoData<R = unknown> = (callback: Callback<R>) => void;\ntype FlowFunction = AsyncFunction | AsyncFunctionNoData | Flow;\n\ntype Flow = FlowFunction[];\n\nexport interface Composition {\n  (data: unknown, callback?: Callback): Composition;\n  (callback: Callback): Composition;\n  data?: unknown;\n  done?: Callback | null;\n  context?: unknown;\n  timeout?: number;\n  timer?: NodeJS.Timeout | null;\n  canceled?: boolean;\n  paused?: boolean;\n  onResume?: (() => void) | null;\n  fns: FlowFunction[];\n  parallelize: boolean;\n  len: number;\n  arrayed: boolean;\n\n  on(name: 'resume', callback: () => void): void;\n  finalize(err?: Error): void;\n  collect(err: Error | null, result?: unknown): void;\n  parallel(): void;\n  sequential(): void;\n  then(\n    fulfill: (result: unknown) => void,\n    reject: (err: Error) => void,\n  ): Composition;\n  clone(): Composition;\n  pause(): Composition;\n  resume(): Composition;\n  timeout(msec: number): Composition;\n  cancel(): Composition;\n}\n\nexport function compose(flow: Flow): Composition;\n\nexport class Composition {\n  constructor();\n}\n\nexport function callbackify<T extends (...args: unknown[]) => Promise<unknown>>(\n  fn: T,\n): (...args: Parameters<T>) => void;\n\nexport function asyncify<T extends (...args: unknown[]) => unknown>(\n  fn: T,\n): (...args: [...Parameters<T>, Callback<ReturnType<T>>]) => void;\n\nexport function promiseToCallbackLast<T>(\n  promise: Promise<T>,\n): (callback: Callback<T>) => void;\n\nexport function promisify<T extends (...args: unknown[]) => void>(\n  fn: T,\n): (\n  ...args: Parameters<T> extends [...infer A, Callback<infer R>] ? A : never\n) => Promise<R>;\n\nexport function promisifySync<T extends (...args: unknown[]) => unknown>(\n  fn: T,\n): (...args: Parameters<T>) => Promise<ReturnType<T>>;\n\nexport interface AsyncMapOptions {\n  min?: number;\n  percent?: number;\n}\n\nexport function map<T, R>(\n  items: T[],\n  fn: (item: T, callback: Callback<R>) => void,\n  done: Callback<R[]>,\n): void;\n\nexport function asyncMap<T, R>(\n  items: T[],\n  fn: (item: T, index: number) => R,\n  options?: AsyncMapOptions | Callback<R[]>,\n  done?: Callback<R[]>,\n): void;\n\nexport function filter<T>(\n  items: T[],\n  fn: (item: T, callback: Callback<boolean>) => void,\n  done: Callback<T[]>,\n): void;\n\nexport function reduce<T, R>(\n  items: T[],\n  fn: (\n    previous: R,\n    current: T,\n    callback: Callback<R>,\n    counter: number,\n    items: T[],\n  ) => void,\n  done: Callback<R>,\n  initial?: R,\n): void;\n\nexport function reduceRight<T, R>(\n  items: T[],\n  fn: (\n    previous: R,\n    current: T,\n    callback: Callback<R>,\n    counter: number,\n    items: T[],\n  ) => void,\n  done: Callback<R>,\n  initial?: R,\n): void;\n\nexport function each<T>(\n  items: T[],\n  fn: (item: T, callback: Callback<void>) => void,\n  done: Callback<void>,\n): void;\n\nexport function series<T>(\n  items: T[],\n  fn: (item: T, callback: Callback<void>) => void,\n  done: Callback<T[]>,\n): void;\n\nexport function find<T>(\n  items: T[],\n  fn: (item: T, callback: Callback<boolean>) => void,\n  done: Callback<T | undefined>,\n): void;\n\nexport function every<T>(\n  items: T[],\n  fn: (item: T, callback: Callback<boolean>) => void,\n  done: Callback<boolean>,\n): void;\n\nexport function some<T>(\n  items: T[],\n  fn: (item: T, callback: Callback<boolean>) => void,\n  done: Callback<boolean>,\n): void;\n\nexport interface Collector {\n  expectKeys: Set<string> | null;\n  expected: number;\n  keys: Set<string>;\n  count: number;\n  timer: NodeJS.Timeout | null;\n  onDone: (err: Error | null, data?: unknown) => void;\n  isDistinct: boolean;\n  isDone: boolean;\n  data: Record<string, unknown>;\n\n  collect(key: string, err: Error | null, value?: unknown): Collector;\n  pick(key: string, value: unknown): Collector;\n  fail(key: string, err: Error): Collector;\n  take(\n    key: string,\n    fn: (...args: unknown[]) => void,\n    ...args: unknown[]\n  ): Collector;\n  timeout(msec: number): Collector;\n  done(callback: (err: Error | null, data?: unknown) => void): Collector;\n  finalize(key: Error | null, err?: Error, data?: unknown): Collector;\n  distinct(value?: boolean): Collector;\n  cancel(err?: Error): Collector;\n  then(\n    fulfill: (result: unknown) => void,\n    reject: (err: Error) => void,\n  ): Collector;\n}\n\nexport function collect(expected: number | string[]): Collector;\n\nexport class Collector {\n  constructor(expected: number | string[]);\n}\n\nexport function firstOf(fns: AsyncFunctionNoData[], callback: Callback): void;\n\nexport function parallel(\n  fns: FlowFunction[],\n  context?: unknown,\n  callback?: Callback,\n): void;\nexport function parallel(fns: FlowFunction[], callback: Callback): void;\n\nexport function sequential(\n  fns: FlowFunction[],\n  context?: unknown,\n  callback?: Callback,\n): void;\nexport function sequential(fns: FlowFunction[], callback: Callback): void;\n\nexport function runIf(\n  condition: unknown,\n  defaultVal: unknown,\n  asyncFn: (...args: unknown[]) => void,\n  ...args: unknown[]\n): void;\nexport function runIf(\n  condition: unknown,\n  asyncFn: (...args: unknown[]) => void,\n  ...args: unknown[]\n): void;\n\nexport function runIfFn(\n  asyncFn: ((...args: unknown[]) => void) | undefined,\n  ...args: unknown[]\n): void;\n\nexport interface Do {\n  prev: Do | null;\n  fn: ((...args: unknown[]) => void) | null;\n  args: unknown[];\n  done: Callback | null;\n  next: Do | null;\n\n  (done?: Callback): Do;\n  do(fn: (...args: unknown[]) => void, ...args: unknown[]): Do;\n  forward(): void;\n}\n\nexport function doFn(fn: (...args: unknown[]) => void, ...args: unknown[]): Do;\n\nexport { doFn as do };\n\nexport function toAsync<T extends (...args: unknown[]) => void>(\n  fn: T,\n): (...argsCb: [...unknown[], Callback]) => void;\n\nexport function asAsync<T extends (...args: unknown[]) => void>(\n  fn: T,\n  ...args: Parameters<T> extends [...infer A, Callback] ? A : never\n): (...args: unknown[]) => void & {\n  fmap: typeof fmap;\n  ap: typeof ap;\n  concat: typeof concat;\n};\n\nexport function of(...args: unknown[]): (...args: unknown[]) => void & {\n  fmap: typeof fmap;\n  ap: typeof ap;\n  concat: typeof concat;\n};\n\nexport function concat(\n  fn1: (...args: unknown[]) => void,\n  fn2: (...args: unknown[]) => void,\n): (...args: unknown[]) => void;\n\nexport function fmap(\n  fn1: (...args: unknown[]) => void,\n  f: (...args: unknown[]) => unknown,\n): (...args: unknown[]) => void;\n\nexport function ap(\n  fn: (...args: unknown[]) => void,\n  funcA: (...args: unknown[]) => void,\n): (...args: unknown[]) => void;\n\nexport interface MemoizedEvents {\n  timeout: ((key: unknown) => void) | null;\n  memoize: ((key: unknown, err: Error | null, data?: unknown) => void) | null;\n  overflow: ((key: unknown) => void) | null;\n  add: ((err: Error | null, data?: unknown) => void) | null;\n  del: ((key: unknown) => void) | null;\n  clear: (() => void) | null;\n}\n\nexport interface Memoized extends Function {\n  cache: Map<unknown, { err: Error | null; data?: unknown }>;\n  timeout: number;\n  limit: number;\n  size: number;\n  maxSize: number;\n  maxCount: number;\n  events: MemoizedEvents;\n\n  (...args: [...unknown[], Callback]): void;\n  clear(): Memoized;\n  add(key: unknown, err: Error | null, data?: unknown): Memoized;\n  del(key: unknown): Memoized;\n  get(key: unknown, callback: Callback): Memoized;\n  on(\n    eventName: keyof MemoizedEvents,\n    listener: (...args: unknown[]) => void,\n  ): void;\n  emit(eventName: keyof MemoizedEvents, ...args: unknown[]): void;\n}\n\nexport function memoize<T extends (...args: unknown[]) => void>(\n  fn: T,\n): Memoized;\n\nexport class Memoized {\n  constructor();\n}\n\nexport interface Pool {\n  (par?: Callback<unknown> | unknown[]): Pool | unknown;\n  items: unknown[];\n  delayed: Array<(item: unknown) => void>;\n}\n\nexport function poolify(\n  factory: () => unknown,\n  min: number,\n  norm: number,\n  max: number,\n): Pool;\n\nexport interface Queue {\n  paused: boolean;\n  concurrency: number;\n  waitTimeout: number;\n  processTimeout: number;\n  throttleCount: number;\n  throttleInterval: number;\n  count: number;\n  tasks: Array<[unknown, number | string, number]>;\n  waiting: Array<Array<[unknown, number | string, number]>>;\n  factors: Record<string | number, Array<[unknown, number | string, number]>>;\n  fifoMode: boolean;\n  roundRobinMode: boolean;\n  priorityMode: boolean;\n  onProcess: ((item: unknown, callback: Callback) => void) | null;\n  onDone: ((err: Error | null, result?: unknown) => void) | null;\n  onSuccess: ((item: unknown) => void) | null;\n  onTimeout: ((err: Error) => void) | null;\n  onFailure: ((err: Error) => void) | null;\n  onDrain: (() => void) | null;\n\n  wait(msec: number): Queue;\n  throttle(count: number, interval?: number): Queue;\n  add(item: unknown, factor?: number | string, priority?: number): Queue;\n  next(task: [unknown, number | string, number]): Queue;\n  takeNext(): Queue;\n  pause(): Queue;\n  resume(): Queue;\n  clear(): Queue;\n  timeout(msec: number, onTimeout?: ((err: Error) => void) | null): Queue;\n  process(fn: (item: unknown, callback: Callback) => void): Queue;\n  done(fn: (err: Error | null, result?: unknown) => void): Queue;\n  success(listener: (item: unknown) => void): Queue;\n  failure(listener: (err: Error) => void): Queue;\n  drain(listener: () => void): Queue;\n  fifo(): Queue;\n  lifo(): Queue;\n  priority(flag?: boolean): Queue;\n  roundRobin(flag?: boolean): Queue;\n  pipe(dest: Queue): Queue;\n}\n\nexport function queue(concurrency: number): Queue;\n\nexport class Queue {\n  constructor(concurrency: number);\n}\n\nexport function throttle<T extends (...args: unknown[]) => void>(\n  timeout: number,\n  fn: T,\n  ...args: unknown[]\n): (...pars: unknown[]) => void;\n\nexport function debounce<T extends (...args: unknown[]) => void>(\n  timeout: number,\n  fn: T,\n  ...args: unknown[]\n): () => void;\n\nexport function timeout(\n  timeout: number,\n  fn: (callback: Callback) => void,\n  callback: Callback,\n): void;\n\nexport interface AsyncIteratorResult<T> {\n  done: boolean;\n  value: T;\n}\n\nexport interface AsyncIterator<T = unknown> {\n  base: Iterator<T> | AsyncIterator<T>;\n\n  [Symbol.asyncIterator](): AsyncIterator<T>;\n  next(): Promise<AsyncIteratorResult<T>>;\n  count(): Promise<number>;\n  each(\n    fn: (value: T) => void | Promise<void>,\n    thisArg?: unknown,\n  ): Promise<void>;\n  forEach(\n    fn: (value: T) => void | Promise<void>,\n    thisArg?: unknown,\n  ): Promise<void>;\n  parallel(\n    fn: (value: T) => unknown | Promise<unknown>,\n    thisArg?: unknown,\n  ): Promise<unknown[]>;\n  every(\n    predicate: (value: T) => boolean | Promise<boolean>,\n    thisArg?: unknown,\n  ): Promise<boolean>;\n  find(\n    predicate: (value: T) => boolean | Promise<boolean>,\n    thisArg?: unknown,\n  ): Promise<T | undefined>;\n  includes(element: T): Promise<boolean>;\n  reduce<R>(\n    reducer: (accumulator: R, value: T) => R | Promise<R>,\n    initialValue: R,\n  ): Promise<R>;\n  reduce<R>(reducer: (accumulator: R, value: T) => R | Promise<R>): Promise<R>;\n  some(\n    predicate: (value: T) => boolean | Promise<boolean>,\n    thisArg?: unknown,\n  ): Promise<boolean>;\n  someCount(\n    predicate: (value: T) => boolean | Promise<boolean>,\n    count: number,\n    thisArg?: unknown,\n  ): Promise<boolean>;\n  collectTo<C extends new (arr: T[]) => unknown>(\n    CollectionClass: C,\n  ): Promise<InstanceType<C>>;\n  collectWith(\n    obj: unknown,\n    collector: (obj: unknown, element: T) => void,\n  ): Promise<void>;\n  join(sep?: string, prefix?: string, suffix?: string): Promise<string>;\n  toArray(): Promise<T[]>;\n  map<R>(fn: (value: T) => R | Promise<R>, thisArg?: unknown): AsyncIterator<R>;\n  filter(\n    predicate: (value: T) => boolean | Promise<boolean>,\n    thisArg?: unknown,\n  ): AsyncIterator<T>;\n  flat(depth?: number): AsyncIterator<unknown>;\n  flatMap<R>(\n    fn: (value: T) => R | Promise<R> | Iterable<R> | AsyncIterable<R>,\n    thisArg?: unknown,\n  ): AsyncIterator<R>;\n  take(count: number): AsyncIterator<T>;\n  takeWhile(\n    predicate: (value: T) => boolean | Promise<boolean>,\n    thisArg?: unknown,\n  ): AsyncIterator<T>;\n  skip(amount: number): AsyncIterator<T>;\n  zip<U extends unknown[]>(\n    ...iterators: { [K in keyof U]: Iterable<U[K]> | AsyncIterable<U[K]> }\n  ): AsyncIterator<[T, ...U]>;\n  chain<U extends unknown[]>(\n    ...iterators: { [K in keyof U]: Iterable<U[K]> | AsyncIterable<U[K]> }\n  ): AsyncIterator<T | U[number]>;\n  enumerate(): AsyncIterator<[number, T]>;\n  throttle(percent?: number, min?: number): AsyncIterator<T>;\n}\n\nexport function asyncIter<T>(\n  base: Iterable<T> | AsyncIterable<T>,\n): AsyncIterator<T>;\n\nexport class AsyncIterator<T = unknown> {\n  constructor(base: Iterable<T> | AsyncIterable<T>);\n}\n"
  },
  {
    "path": "metasync.js",
    "content": "'use strict';\n\nconst composition = require('./lib/composition.js');\nconst adapters = require('./lib/adapters.js');\nconst array = require('./lib/array.js');\nconst collector = require('./lib/collector.js');\nconst control = require('./lib/control.js');\nconst doModule = require('./lib/do.js');\nconst fp = require('./lib/fp.js');\nconst memoize = require('./lib/memoize.js');\nconst poolify = require('./lib/poolify.js');\nconst queue = require('./lib/queue.js');\nconst throttle = require('./lib/throttle.js');\nconst asyncIterator = require('./lib/async-iterator.js');\n\nconst { compose } = composition;\n\nconst submodules = {\n  ...composition, // Unified abstraction\n  ...adapters, // Adapters to convert different async contracts\n  ...array, // Array utilities\n  ...collector, // DataCollector and KeyCollector\n  ...control, // Control flow utilities\n  ...doModule, // Simple chain/do\n  ...fp, // Async utils for functional programming\n  ...memoize, // Async memoization\n  ...poolify, // Create pool from factory\n  ...queue, // Concurrent queue\n  ...throttle, // Throttling utilities\n  ...asyncIterator, // AsyncIterator utilities\n};\n\nmodule.exports = Object.assign(compose, submodules);\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"metasync\",\n  \"version\": \"0.3.33\",\n  \"author\": \"Timur Shemsedinov <timur.shemsedinov@gmail.com>\",\n  \"description\": \"Asynchronous Programming Library\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"metasync\",\n    \"callback\",\n    \"promise\",\n    \"async\",\n    \"asyncronous\",\n    \"parallel\",\n    \"sequential\",\n    \"metarhia\",\n    \"flow\",\n    \"collector\",\n    \"errback\",\n    \"err-first\",\n    \"error-first\",\n    \"callback-last\",\n    \"throttle\",\n    \"impress\",\n    \"datacollector\",\n    \"keycollector\",\n    \"composition\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/metarhia/metasync\"\n  },\n  \"main\": \"metasync.js\",\n  \"browser\": {\n    \"metasync.js\": \"dist/metasync.js\"\n  },\n  \"files\": [\n    \"dist/\",\n    \"lib/\"\n  ],\n  \"readmeFilename\": \"README.md\",\n  \"scripts\": {\n    \"test\": \"npm run lint && metatests test/ && metatests tests/async-iterator.js\",\n    \"perf\": \"tests/load/run.sh\",\n    \"lint\": \"eslint . && prettier --check \\\"**/*.js\\\" \\\"**/*.json\\\" \\\"**/*.md\\\" \\\"**/*.ts\\\"\",\n    \"fix\": \"eslint . --fix && prettier --write \\\"**/*.js\\\" \\\"**/*.json\\\" \\\"**/*.md\\\" \\\"**/*.ts\\\"\",\n    \"types\": \"tsc -p tsconfig.json\"\n  },\n  \"engines\": {\n    \"node\": \">=14.0.0\"\n  },\n  \"dependencies\": {\n    \"metautil\": \"^5.3.0\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^25.0.3\",\n    \"eslint\": \"^9.39.2\",\n    \"eslint-config-metarhia\": \"^9.1.5\",\n    \"prettier\": \"^3.7.4\",\n    \"metatests\": \"^0.9.3\",\n    \"typescript\": \"^5.9.3\"\n  }\n}\n"
  },
  {
    "path": "prettier.config.js",
    "content": "'use strict';\n\nmodule.exports = {\n  printWidth: 80,\n  singleQuote: true,\n  trailingComma: 'all',\n  tabWidth: 2,\n  useTabs: false,\n  semi: true,\n};\n"
  },
  {
    "path": "test/adapters.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('callbackify: Promise to callback-last', (test) => {\n  const promiseReturning = () => Promise.resolve('result');\n  const asyncFn = metasync.callbackify(promiseReturning);\n\n  asyncFn((err, value) => {\n    if (err) {\n      test.error(err, 'must not throw');\n    }\n    test.strictSame(value, 'result');\n    test.end();\n  });\n});\n\nmetatests.test('asyncify: sync function to callback-last', (test) => {\n  const fn = (par) => par;\n  const asyncFn = metasync.asyncify(fn);\n\n  asyncFn('result', (err, value) => {\n    if (err) {\n      test.error(err, 'must not throw');\n    }\n    test.strictSame(value, 'result');\n    test.end();\n  });\n});\n\nmetatests.test('promisify: callback-last to Promise', (test) => {\n  const id = 100;\n  const data = { key: 'value' };\n\n  const getDataAsync = (dataId, callback) => {\n    test.strictSame(dataId, id);\n    callback(null, data);\n  };\n\n  const getDataPromise = metasync.promisify(getDataAsync);\n  getDataPromise(id)\n    .then((result) => {\n      test.strictSame(result, data);\n      test.end();\n    })\n    .catch((err) => {\n      test.error(err, 'must not throw');\n    });\n});\n\nmetatests.test('promisify: callback-last to Promise throw', (test) => {\n  const id = 100;\n\n  const getDataAsync = (dataId, callback) => {\n    test.strictSame(dataId, id);\n    callback(new Error('Data not found'));\n  };\n\n  const getDataPromise = metasync.promisify(getDataAsync);\n  getDataPromise(id)\n    .then((result) => {\n      test.notOk(result);\n    })\n    .catch((err) => {\n      test.ok(err);\n      test.end();\n    });\n});\n\nmetatests.test('promisify: sync function to Promise', (test) => {\n  const id = 100;\n  const data = { key: 'value' };\n\n  const getDataSync = (dataId) => {\n    test.strictSame(dataId, id);\n    return data;\n  };\n\n  const getDataPromise = metasync.promisifySync(getDataSync);\n  getDataPromise(id)\n    .then((result) => {\n      test.strictSame(result, data);\n      test.end();\n    })\n    .catch((err) => {\n      test.error(err, 'must not throw');\n    });\n});\n\nmetatests.test('promisify: sync to Promise throw', (test) => {\n  const id = 100;\n\n  const getDataSync = (dataId) => {\n    test.strictSame(dataId, id);\n    throw new Error('Data not found');\n  };\n\n  const getDataPromise = metasync.promisifySync(getDataSync);\n  getDataPromise(id)\n    .then((result) => {\n      test.notOk(result);\n    })\n    .catch((err) => {\n      test.ok(err);\n      test.end();\n    });\n});\n\nmetatests.test('promiseToCallbackLast: Promise to callback-last', (test) => {\n  const promise = Promise.resolve('result');\n  const asyncFn = metasync.promiseToCallbackLast(promise);\n\n  asyncFn((err, value) => {\n    if (err) {\n      test.error(err, 'must not throw');\n    }\n    test.strictSame(value, 'result');\n    test.end();\n  });\n});\n"
  },
  {
    "path": "test/array.asyncMap.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('succesfull map', (test) => {\n  test.plan(2);\n\n  const arr = [1, 2, 3];\n  const expectedArr = [2, 4, 6];\n\n  metasync.asyncMap(\n    arr,\n    (item) => item * 2,\n    (err, newArr) => {\n      test.error(err);\n      test.strictSame(newArr, expectedArr);\n    },\n  );\n});\n\nconst doSmth = (time) => {\n  const begin = Date.now();\n  while (Date.now() - begin < time);\n};\n\nmetatests.test('Non-blocking', (test) => {\n  const ITEM_TIME = 1;\n  const TIMER_TIME = 9;\n  const ARRAY_SIZE = 1000;\n  const EXPECTED_PERCENT = 0.5;\n  const EXPECTED_DEVIATION = 0.4;\n\n  const arr = new Array(ARRAY_SIZE).fill(1);\n\n  const timer = setInterval(() => doSmth(TIMER_TIME), 1);\n\n  const begin = Date.now();\n  metasync.asyncMap(\n    arr,\n    () => doSmth(ITEM_TIME),\n    { percent: EXPECTED_PERCENT },\n    () => {\n      clearInterval(timer);\n\n      const mapTime = ITEM_TIME * ARRAY_SIZE;\n      const allTime = Date.now() - begin;\n      const actualPercent = mapTime / allTime;\n      const actualDeviation = Math.abs(actualPercent - EXPECTED_PERCENT);\n      test.assert(actualDeviation <= EXPECTED_DEVIATION);\n      test.end();\n    },\n  );\n});\n"
  },
  {
    "path": "test/array.each.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('successful each', (test) => {\n  const arr = [1, 2, 3, 4];\n\n  const elementsSet = new Set();\n  const expectedElementsSet = new Set(arr);\n\n  metasync.each(\n    arr,\n    (el, callback) =>\n      process.nextTick(() => {\n        elementsSet.add(el);\n        callback(null);\n      }),\n    (err) => {\n      test.error(err);\n      test.strictSame(elementsSet, expectedElementsSet);\n      test.end();\n    },\n  );\n});\n\nmetatests.test('each with empty array', (test) => {\n  const arr = [];\n\n  const elementsSet = new Set();\n  const expectedElementsSet = new Set(arr);\n\n  metasync.each(\n    arr,\n    (el, callback) =>\n      process.nextTick(() => {\n        elementsSet.add(el);\n        callback(null);\n      }),\n    (err) => {\n      test.error(err);\n      test.strictSame(elementsSet, expectedElementsSet);\n      test.end();\n    },\n  );\n});\n\nmetatests.test('each with error', (test) => {\n  const arr = [1, 2, 3, 4];\n  let count = 0;\n\n  const elementsSet = new Set();\n  const expectedElementsCount = 2;\n  const eachError = new Error('Each error');\n\n  metasync.each(\n    arr,\n    (el, callback) =>\n      process.nextTick(() => {\n        elementsSet.add(el);\n        count++;\n        if (count === expectedElementsCount) {\n          callback(eachError);\n        } else {\n          callback(null);\n        }\n      }),\n    (err) => {\n      test.strictSame(err, eachError);\n      test.strictSame(elementsSet.size, expectedElementsCount);\n      test.end();\n    },\n  );\n});\n"
  },
  {
    "path": "test/array.every.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nconst identity = (x, callback) => callback(null, x);\n\nconst strictSameResult = (input, expectedResult, test, done) => {\n  metasync.every(input, identity, (err, result) => {\n    test.error(err);\n    test.strictSame(result, expectedResult);\n\n    done();\n  });\n};\n\nconst fewStrictSameResult = (inOutPairs, test) => {\n  let i = 0;\n  const testsEnd = metasync.collect(inOutPairs.length);\n  testsEnd.done(() => test.end());\n  const cb = () => testsEnd.pick('item' + i++);\n  for (const [input, output] of inOutPairs) {\n    strictSameResult(input, output, test, cb);\n  }\n};\n\nmetatests.test('every with error', (test) => {\n  const data = [1, 2, 3];\n  const everyErr = new Error('Every error');\n\n  const predicate = (item, callback) => {\n    process.nextTick(() =>\n      item % 2 === 0 ? callback(everyErr) : callback(null, true),\n    );\n  };\n\n  metasync.every(data, predicate, (err) => {\n    test.strictSame(err, everyErr);\n    test.end();\n  });\n});\n\nmetatests.test('every with empty array', (test) =>\n  strictSameResult([], true, test, () => test.end()),\n);\n\nmetatests.test('every with one-element arrays', (test) =>\n  fewStrictSameResult(\n    [\n      [[false], false],\n      [[true], true],\n    ],\n    test,\n  ),\n);\n\nmetatests.test('every with two-element arrays', (test) =>\n  fewStrictSameResult(\n    [\n      [[false, false], false],\n      [[false, true], false],\n      [[true, false], false],\n      [[true, true], true],\n    ],\n    test,\n  ),\n);\n\nmetatests.test('every', (test) => {\n  const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];\n\n  const predicate = (item, callback) => {\n    process.nextTick(() => callback(null, item > 0));\n  };\n\n  metasync.every(data, predicate, (err, result) => {\n    test.error(err);\n    test.strictSame(result, true);\n    test.end();\n  });\n});\n"
  },
  {
    "path": "test/array.filter.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('successful filter', (test) => {\n  const arr = [\n    'Lorem',\n    'ipsum',\n    'dolor',\n    'sit',\n    'amet',\n    'consectetur',\n    'adipiscing',\n    'elit',\n    'sed',\n    'do',\n    'eiusmod',\n    'tempor',\n    'incididunt',\n    'ut',\n    'labore',\n    'et',\n    'dolore',\n    'magna',\n    'aliqua',\n  ];\n  const expectedArr = [\n    'Lorem',\n    'ipsum',\n    'dolor',\n    'sit',\n    'amet',\n    'elit',\n    'sed',\n    'do',\n    'ut',\n    'et',\n    'magna',\n  ];\n\n  metasync.filter(\n    arr,\n    (str, callback) => process.nextTick(() => callback(null, str.length < 6)),\n    (err, res) => {\n      test.error(err);\n      test.same(res.join(), expectedArr.join());\n      test.end();\n    },\n  );\n});\n\nmetatests.test('filter with empty array', (test) => {\n  const arr = [];\n  const expectedArr = [];\n\n  metasync.filter(\n    arr,\n    (str, callback) => process.nextTick(() => callback(null, str.length < 6)),\n    (err, res) => {\n      test.error(err);\n      test.strictSame(res, expectedArr);\n      test.end();\n    },\n  );\n});\n\nmetatests.test('successful filter', (test) => {\n  const arr = [\n    'Lorem',\n    'ipsum',\n    'dolor',\n    'sit',\n    'amet',\n    'consectetur',\n    'adipiscing',\n    'elit',\n    'sed',\n    'do',\n    'eiusmod',\n    'tempor',\n    'incididunt',\n    'ut',\n    'labore',\n    'et',\n    'dolore',\n    'magna',\n    'aliqua',\n  ];\n  const filterError = new Error('Filter error');\n  const expectedArr = [\n    'Lorem',\n    'ipsum',\n    'dolor',\n    'sit',\n    'amet',\n    'elit',\n    'sed',\n    'magna',\n  ];\n\n  metasync.filter(\n    arr,\n    (str, callback) =>\n      process.nextTick(() => {\n        if (str.length === 2) {\n          callback(filterError);\n          return;\n        }\n        callback(null, str.length < 6);\n      }),\n    (err, res) => {\n      test.error(err);\n      test.same(res.join(), expectedArr.join());\n      test.end();\n    },\n  );\n});\n"
  },
  {
    "path": "test/array.find.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('find with error', (test) => {\n  const data = [1, 2, 3];\n  const expectedErrorMessage = 'Intentional error';\n  const predicate = (item, callback) =>\n    process.nextTick(() => {\n      if (item % 2 === 0) {\n        callback(new Error(expectedErrorMessage));\n      } else {\n        callback(null, false);\n      }\n    });\n\n  metasync.find(data, predicate, (err) => {\n    test.type(err, 'Error', 'err must be an instance of Error');\n    test.strictSame(err.message, expectedErrorMessage);\n    test.end();\n  });\n});\n\nmetatests.test('find', (test) => {\n  const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];\n  const expected = 15;\n  const predicate = (item, callback) =>\n    process.nextTick(() => callback(null, item % 3 === 0 && item % 5 === 0));\n\n  metasync.find(data, predicate, (err, result) => {\n    test.error(err, 'must not return an error');\n    test.strictSame(result, expected, `result should be: ${expected}`);\n    test.end();\n  });\n});\n\nmetatests.test('with empty array', (test) => {\n  metasync.find(\n    [],\n    (el, callback) => process.nextTick(() => callback(null, true)),\n    (err, result) => {\n      test.error(err);\n      test.strictSame(result, undefined);\n      test.end();\n    },\n  );\n});\n\nmetatests.test('with array without element which is searching', (test) => {\n  const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];\n  metasync.find(\n    data,\n    (el, callback) => process.nextTick(() => callback(null, el === 20)),\n    (err, result) => {\n      test.error(err);\n      test.strictSame(result, undefined);\n      test.end();\n    },\n  );\n});\n"
  },
  {
    "path": "test/array.map.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('succesfull map', (test) => {\n  const arr = [1, 2, 3];\n  const expectedArr = [1, 4, 9];\n\n  metasync.map(\n    arr,\n    (x, callback) => process.nextTick(() => callback(null, x * x)),\n    (err, res) => {\n      test.error(err);\n      test.strictSame(res, expectedArr);\n      test.end();\n    },\n  );\n});\n\nmetatests.test('map with empty array', (test) => {\n  const arr = [];\n  const expectedArr = [];\n\n  metasync.map(\n    arr,\n    (x, callback) => process.nextTick(() => callback(null, x * x)),\n    (err, res) => {\n      test.error(err);\n      test.strictSame(res, expectedArr);\n      test.end();\n    },\n  );\n});\n\nmetatests.test('map with error', (test) => {\n  const arr = [1, 2, 3];\n  const mapError = new Error('Map error');\n  let count = 0;\n\n  metasync.map(\n    arr,\n    (x, callback) =>\n      process.nextTick(() => {\n        count++;\n        if (count === 2) {\n          callback(mapError);\n          return;\n        }\n        callback(null, x * x);\n      }),\n    (err, res) => {\n      test.strictSame(err, mapError);\n      test.strictSame(res, undefined);\n      test.end();\n    },\n  );\n});\n"
  },
  {
    "path": "test/array.reduce.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('reduce with initial', (test) => {\n  const arr = [1, 2, 3, 4, 5];\n  const initial = 10;\n  const expectedRes = 25;\n\n  metasync.reduce(\n    arr,\n    (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)),\n    (err, res) => {\n      test.error(err);\n      test.strictSame(res, expectedRes);\n      test.end();\n    },\n    initial,\n  );\n});\n\nmetatests.test('reduce with initial and empty array', (test) => {\n  const arr = [];\n  const initial = 10;\n  const expectedRes = 10;\n\n  metasync.reduce(\n    arr,\n    (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)),\n    (err, res) => {\n      test.error(err);\n      test.strictSame(res, expectedRes);\n      test.end();\n    },\n    initial,\n  );\n});\n\nmetatests.test('reduce without initial and with empty array', (test) => {\n  const arr = [];\n  const expectedError = new TypeError(\n    'Metasync: reduce of empty array with no initial value',\n  );\n\n  metasync.reduce(\n    arr,\n    (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)),\n    (err, res) => {\n      test.strictSame(err, expectedError);\n      test.strictSame(res, undefined);\n      test.end();\n    },\n  );\n});\n\nmetatests.test('reduce single-element array without initial', (test) => {\n  const arr = [2];\n\n  metasync.reduce(\n    arr,\n    (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)),\n    (err, res) => {\n      test.strictSame(err, null);\n      test.strictSame(res, 2);\n      test.end();\n    },\n  );\n});\n\nmetatests.test('reduce without initial', (test) => {\n  const arr = [1, 2, 3, 4, 5];\n  const expectedRes = 15;\n\n  metasync.reduce(\n    arr,\n    (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)),\n    (err, res) => {\n      test.error(err);\n      test.strictSame(res, expectedRes);\n      test.end();\n    },\n  );\n});\n\nmetatests.test('reduce with asymetric function', (test) => {\n  const arr = '10110011';\n  const expectedRes = 179;\n\n  metasync.reduce(\n    arr,\n    (prev, cur, callback) =>\n      process.nextTick(() => callback(null, prev * 2 + +cur)),\n    (err, res) => {\n      test.error(err);\n      test.strictSame(res, expectedRes);\n      test.end();\n    },\n  );\n});\n\nmetatests.test('reduce with error', (test) => {\n  const arr = '10120011';\n  const reduceError = new Error('Reduce error');\n\n  metasync.reduce(\n    arr,\n    (prev, cur, callback) =>\n      process.nextTick(() => {\n        const digit = +cur;\n        if (digit > 1) {\n          callback(reduceError);\n          return;\n        }\n        callback(null, prev * 2 + digit);\n      }),\n    (err, res) => {\n      test.strictSame(err, reduceError);\n      test.strictSame(res, undefined);\n      test.end();\n    },\n  );\n});\n"
  },
  {
    "path": "test/array.reduceRight.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('reduceRight with initial', (test) => {\n  const arr = [1, 2, 3, 4, 5];\n  const initial = 10;\n  const expectedRes = 25;\n\n  metasync.reduceRight(\n    arr,\n    (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)),\n    (err, res) => {\n      test.error(err);\n      test.strictSame(res, expectedRes);\n      test.end();\n    },\n    initial,\n  );\n});\n\nmetatests.test('reduceRight with initial and empty array', (test) => {\n  const arr = [];\n  const initial = 10;\n  const expectedRes = 10;\n\n  metasync.reduceRight(\n    arr,\n    (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)),\n    (err, res) => {\n      test.error(err);\n      test.strictSame(res, expectedRes);\n      test.end();\n    },\n    initial,\n  );\n});\n\nmetatests.test('reduceRight without initial and with empty array', (test) => {\n  const arr = [];\n  const expectedError = new TypeError(\n    'Metasync: reduceRight of empty array with no initial value',\n  );\n\n  metasync.reduceRight(\n    arr,\n    (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)),\n    (err, res) => {\n      test.strictSame(err, expectedError);\n      test.strictSame(res, undefined);\n      test.end();\n    },\n  );\n});\n\nmetatests.test(\n  'reduceRight without initial and with single-element array',\n  (test) => {\n    const arr = [2];\n\n    metasync.reduceRight(\n      arr,\n      (prev, cur, callback) =>\n        process.nextTick(() => callback(null, prev + cur)),\n      (err, res) => {\n        test.strictSame(err, null);\n        test.strictSame(res, 2);\n        test.end();\n      },\n    );\n  },\n);\n\nmetatests.test('reduceRight without initial', (test) => {\n  const arr = [1, 2, 3, 4, 5];\n  const expectedRes = 15;\n\n  metasync.reduceRight(\n    arr,\n    (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)),\n    (err, res) => {\n      test.error(err);\n      test.strictSame(res, expectedRes);\n      test.end();\n    },\n  );\n});\n\nmetatests.test('reduceRight with asymetric function', (test) => {\n  const arr = '10110011';\n  const expectedRes = 205;\n\n  metasync.reduceRight(\n    arr,\n    (prev, cur, callback) =>\n      process.nextTick(() => callback(null, prev * 2 + +cur)),\n    (err, res) => {\n      test.error(err);\n      test.strictSame(res, expectedRes);\n      test.end();\n    },\n  );\n});\n\nmetatests.test('reduceRight with error', (test) => {\n  const arr = '10120011';\n  const reduceError = new Error('Reduce error');\n\n  metasync.reduce(\n    arr,\n    (prev, cur, callback) =>\n      process.nextTick(() => {\n        const digit = +cur;\n        if (digit > 1) {\n          callback(reduceError);\n          return;\n        }\n        callback(null, prev * 2 + digit);\n      }),\n    (err, res) => {\n      test.strictSame(err, reduceError);\n      test.strictSame(res, undefined);\n      test.end();\n    },\n  );\n});\n"
  },
  {
    "path": "test/array.series.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('successful series', (test) => {\n  const arr = [1, 2, 3, 4];\n  const expectedElements = arr;\n  const elements = [];\n  metasync.series(\n    arr,\n    (el, callback) => {\n      elements.push(el);\n      callback(null);\n    },\n    (err) => {\n      test.error(err);\n      test.strictSame(elements, expectedElements);\n      test.end();\n    },\n  );\n});\n\nmetatests.test('series with error', (test) => {\n  const arr = [1, 2, 3, 4];\n  const expectedElements = [1, 2];\n  const expectedElementsCount = 2;\n\n  const elements = [];\n  let count = 0;\n  const seriesError = new Error('seriesError');\n\n  metasync.series(\n    arr,\n    (el, callback) => {\n      elements.push(el);\n      count++;\n      if (count === expectedElementsCount) {\n        callback(seriesError);\n      } else {\n        callback(null);\n      }\n    },\n    (err) => {\n      test.strictSame(err, seriesError);\n      test.strictSame(elements, expectedElements);\n      test.end();\n    },\n  );\n});\n"
  },
  {
    "path": "test/array.some.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('successful some', (test) => {\n  const arr = [1, 2, 3];\n\n  const predicate = (x, callback) => callback(null, x % 2 === 0);\n  metasync.some(arr, predicate, (err, accepted) => {\n    test.error(err);\n    test.strictSame(accepted, true);\n    test.end();\n  });\n});\n\nmetatests.test('failing some', (test) => {\n  const arr = [1, 2, 3];\n\n  const predicate = (x, callback) => callback(null, x > 3);\n  metasync.some(arr, predicate, (err, accepted) => {\n    test.error(err);\n    test.strictSame(accepted, false);\n    test.end();\n  });\n});\n\nmetatests.test('erroneous some', (test) => {\n  const arr = [1, 2, 3];\n  const someError = new Error('Some error');\n\n  const predicate = (x, callback) =>\n    x % 2 === 0 ? callback(someError) : callback(null, false);\n  metasync.some(arr, predicate, (err, accepted) => {\n    test.strictSame(err, someError);\n    test.strictSame(accepted, undefined);\n    test.end();\n  });\n});\n\nmetatests.test('some with empty array', (test) => {\n  const arr = [];\n\n  const predicate = (x, callback) => callback(null, x > 3);\n  metasync.some(arr, predicate, (err, accepted) => {\n    test.error(err);\n    test.strictSame(accepted, false);\n    test.end();\n  });\n});\n"
  },
  {
    "path": "test/collectors.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('data collector', (test) => {\n  const expectedResult = {\n    key1: 1,\n    key2: 2,\n    key3: 3,\n  };\n\n  const dc = metasync\n    .collect(3)\n    .done((err, result) => {\n      test.error(err);\n      test.strictSame(result, expectedResult);\n      test.end();\n    })\n    .timeout(1000);\n\n  dc.collect('key1', null, 1);\n  dc.collect('key2', null, 2);\n  dc.collect('key3', null, 3);\n});\n\nmetatests.test('data collector', (test) => {\n  const expectedResult = {\n    key1: 1,\n    key2: 2,\n    key3: 3,\n  };\n\n  const kc = metasync\n    .collect(['key1', 'key2', 'key3'])\n    .done((err, result) => {\n      test.error(err);\n      test.strictSame(result, expectedResult);\n      test.end();\n    })\n    .timeout();\n\n  kc.collect('key1', null, 1);\n  kc.collect('key2', null, 2);\n  kc.collect('key3', null, 3);\n});\n\nmetatests.test('distinct data collector', (test) => {\n  const expectedResult = {\n    key1: 2,\n    key2: 2,\n    key3: 3,\n  };\n\n  const dc = metasync\n    .collect(3)\n    .distinct()\n    .done((err, result) => {\n      test.error(err);\n      test.strictSame(result, expectedResult);\n      test.end();\n    });\n\n  dc.pick('key1', 1);\n  dc.pick('key1', 2);\n  dc.pick('key2', 2);\n  dc.pick('key3', 3);\n});\n\nmetatests.test('distinct key collector', (test) => {\n  const expectedResult = {\n    key1: 2,\n    key2: 2,\n    key3: 3,\n  };\n\n  const kc = metasync\n    .collect(['key1', 'key2', 'key3'])\n    .distinct()\n    .done((err, result) => {\n      test.error(err);\n      test.strictSame(result, expectedResult);\n      test.end();\n    });\n\n  kc.pick('key1', 1);\n  kc.pick('key1', 2);\n  kc.pick('key2', 2);\n  kc.pick('key3', 3);\n});\n\nmetatests.test('data collector with repeated keys', (test) => {\n  const dc = metasync\n    .collect(3)\n    .timeout(100)\n    .done((err) => {\n      test.assert(err);\n      test.end();\n    });\n\n  dc.collect('key1', null, 1);\n  dc.collect('key1', null, 2);\n  dc.collect('key2', null, 2);\n});\n\nmetatests.test('key collector with repeated keys', (test) => {\n  const kc = metasync\n    .collect(['key1', 'key2', 'key3'])\n    .timeout(100)\n    .done((err) => {\n      test.assert(err);\n      test.end();\n    });\n\n  kc.collect('key1', null, 1);\n  kc.collect('key1', null, 2);\n  kc.collect('key2', null, 2);\n});\n\nmetatests.test('collect with error', (test) => {\n  const testErr = new Error('Test error');\n  const col = metasync.collect(1);\n  col.done((err, res) => {\n    test.strictSame(err, testErr);\n    test.strictSame(res, {});\n    test.end();\n  });\n  col.fail('someKey', testErr);\n});\n\nmetatests.test(`collect method calling after it's done`, (test) => {\n  const col = metasync.collect(1);\n  col.done((err, res) => {\n    test.error(err);\n    test.strictSame(res, { someKey: 'someVal' });\n    test.end();\n  });\n  col.pick('someKey', 'someVal');\n  col.pick('someKey2', 'someVal2');\n});\n\nmetatests.test('keys collector receives wrong key', (test) => {\n  const col = metasync.collect(['rightKey']);\n  col.done((err, res) => {\n    test.error(err);\n    test.strictSame(res, { wrongKey: 'someVal', rightKey: 'someVal' });\n    test.end();\n  });\n  col.pick('wrongKey', 'someVal');\n  col.pick('rightKey', 'someVal');\n});\n\nmetatests.test('distinct keys collector receives wrong key', (test) => {\n  const col = metasync.collect(['rightKey']).distinct();\n  col.done((err) => {\n    test.assert(err);\n    test.end();\n  });\n  col.pick('wrongKey', 'someVal');\n  col.pick('rightKey', 'someVal');\n});\n\nmetatests.test('collect with take', (test) => {\n  const col = metasync.collect(1);\n  col.done((err, res) => {\n    test.error(err);\n    test.strictSame(res, { someKey: 'someVal' });\n    test.end();\n  });\n  const af = (x, callback) => callback(null, x);\n  col.take('someKey', af, 'someVal');\n});\n\nmetatests.test('collect with timeout error', (test) => {\n  const timeoutErr = new Error('Metasync: Collector timed out');\n  const col = metasync\n    .collect(1)\n    .done((err, res) => {\n      test.strictSame(err, timeoutErr);\n      test.strictSame(res, {});\n      test.end();\n    })\n    .timeout(1);\n  const af = (x, callback) => setTimeout(() => callback(null, x), 2);\n  col.take('someKey', af, 'someVal');\n});\n\nmetatests.test('collect with take calls bigger than expected', (test) => {\n  const col = metasync.collect(1).done((err, res) => {\n    test.error(err);\n    test.strictSame(Object.keys(res).length, 1);\n    test.end();\n  });\n  const af = (x, callback) => setTimeout(() => callback(null, x), 1);\n  col.take('someKey', af, 'someVal');\n  col.take('someKey2', af, 'someVal2');\n});\n\nmetatests.test('cancel data collector', (test) => {\n  const dc = metasync.collect(3).done((err) => {\n    test.assert(err);\n    test.end();\n  });\n\n  dc.pick('key', 'value');\n  dc.cancel();\n});\n\nmetatests.test('cancel key collector', (test) => {\n  const dc = metasync.collect(['uno', 'due']).done((err) => {\n    test.assert(err);\n    test.end();\n  });\n\n  dc.pick('key', 'value');\n  dc.cancel();\n});\n\nmetatests.test('collect then success', (test) => {\n  const col = metasync.collect(1).then(\n    (result) => {\n      test.assert(result);\n      test.end();\n    },\n    (err) => {\n      test.error(err);\n      test.end();\n    },\n  );\n  col.pick('Key', 'value');\n});\n\nmetatests.test('collect then fail', (test) => {\n  metasync\n    .collect(5)\n    .timeout(10)\n    .then(\n      (result) => {\n        test.error(result);\n        test.end();\n      },\n      (err) => {\n        test.assert(err);\n        test.end();\n      },\n    );\n});\n"
  },
  {
    "path": "test/compose.clone.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('async functions composition clone', (test) => {\n  const data = { test: 'data' };\n  const expectedData = { test: 'data', data1: 'data 1', data2: 'data 2' };\n\n  const fn1 = (data, cb) => {\n    process.nextTick(() => {\n      cb(null, { data1: 'data 1' });\n    });\n  };\n\n  const fn2 = (data, cb) => {\n    process.nextTick(() => {\n      cb(null, { data2: 'data 2' });\n    });\n  };\n\n  const fc1 = metasync([[fn1, fn2]]);\n  const fc2 = fc1.clone();\n\n  fc1(data, (err, data) => {\n    test.error(err);\n    test.strictSame(data, expectedData);\n    fc2(data, (err, data) => {\n      test.error(err);\n      test.strictSame(data, expectedData);\n      test.end();\n    });\n  });\n});\n"
  },
  {
    "path": "test/compose.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('async parallel functions composition', (test) => {\n  const data = { test: 'data' };\n  const expectedData = { test: 'data', data1: 'data 1', data2: 'data 2' };\n\n  const fn1 = (data, cb) => {\n    process.nextTick(() => {\n      cb(null, { data1: 'data 1' });\n    });\n  };\n\n  const fn2 = (data, cb) => {\n    process.nextTick(() => {\n      cb(null, { data2: 'data 2' });\n    });\n  };\n\n  const fc = metasync([[fn1, fn2]]);\n\n  fc(data, (err, data) => {\n    test.error(err);\n    test.strictSame(data, expectedData);\n    test.end();\n  });\n});\n\nmetatests.test('async complex functions composition', (test) => {\n  const data = { test: 'data' };\n  const expectedDataInFn1 = { test: 'data' };\n  const expectedDataInFn2 = { test: 'data', data1: 'data 1' };\n  const expectedDataInRes = { test: 'data' };\n\n  let i;\n  for (i = 1; i < 6; i++) {\n    expectedDataInRes['data' + i] = 'data ' + i;\n  }\n\n  const fn1 = (data, cb) => {\n    process.nextTick(() => {\n      test.strictSame(data, expectedDataInFn1);\n      cb(null, { data1: 'data 1' });\n    });\n  };\n\n  const fn2 = (data, cb) => {\n    process.nextTick(() => {\n      test.strictSame(data, expectedDataInFn2);\n      cb(null, { data2: 'data 2' });\n    });\n  };\n\n  const fn3 = (data, cb) => {\n    process.nextTick(() => {\n      cb(null, { data3: 'data 3' });\n    });\n  };\n\n  const fn4 = (data, cb) => {\n    process.nextTick(() => {\n      cb(null, { data4: 'data 4' });\n    });\n  };\n\n  const fn5 = (data, cb) => {\n    process.nextTick(() => {\n      test.strictSame(data.data1, 'data 1');\n      test.strictSame(data.data2, 'data 2');\n      test.strictSame(data.data3, 'data 3');\n      test.strictSame(data.data4, 'data 4');\n      cb(null, { data5: 'data 5' });\n    });\n  };\n\n  const fc = metasync([fn1, fn2, [[fn3, [fn4, fn5]]], [], [[]]]);\n  fc(data, (err, data) => {\n    test.error(err);\n    test.strictSame(data, expectedDataInRes);\n    test.end();\n  });\n});\n\nconst AC1 = 'async functions composition cancel before start';\nmetatests.test(AC1, (test) => {\n  let count = 0;\n\n  const fn1 = (data, cb) => {\n    count++;\n    process.nextTick(() => cb(null, 'data 1'));\n  };\n\n  const fn2 = (data, cb) => {\n    count++;\n    process.nextTick(() => cb(null, 'data 2'));\n  };\n\n  const fn3 = (data, cb) => {\n    count++;\n    process.nextTick(() => cb(null, 'data 3'));\n  };\n\n  const fn4 = (data, cb) => {\n    count++;\n    process.nextTick(() => cb(null, 'data 4'));\n  };\n\n  const fc = metasync([fn1, [[fn2, fn3]], fn4]);\n  fc.cancel();\n  fc({}, (err, data) => {\n    test.isError(err);\n    test.strictSame(data, undefined);\n    test.strictSame(count, 0);\n    test.end();\n  });\n});\n\nconst AC2 = 'async functions composition cancel in the middle';\nmetatests.test(AC2, (test) => {\n  let count = 0;\n  let finished = 0;\n\n  const fn1 = (data, cb) => {\n    count++;\n    process.nextTick(() => {\n      finished++;\n      cb(null, 'data 1');\n    });\n  };\n\n  const fn2 = (data, cb) => {\n    count++;\n    setTimeout(() => {\n      finished++;\n      cb(null, 'data 2');\n    }, 200);\n  };\n\n  const fn3 = (data, cb) => {\n    count++;\n    setTimeout(() => {\n      finished++;\n      cb(null, 'data 3');\n    }, 200);\n  };\n\n  const fn4 = (data, cb) => {\n    count++;\n    setTimeout(() => {\n      finished++;\n      cb(null, 'data 4');\n    }, 200);\n  };\n\n  const fc = metasync([fn1, [[fn2, fn3]], fn4]);\n  fc({}, (err, data) => {\n    test.isError(err);\n    test.strictSame(data, undefined);\n    test.strictSame(count, 3);\n    test.strictSame(finished, 1);\n    test.end();\n  });\n\n  setTimeout(() => {\n    fc.cancel();\n  }, 100);\n});\n\nmetatests.test('async functions composition cancel after end', (test) => {\n  let count = 0;\n\n  const fn1 = (data, cb) => {\n    count++;\n    process.nextTick(() => {\n      cb(null, { data1: 'data 1' });\n    });\n  };\n\n  const fn2 = (data, cb) => {\n    count++;\n    process.nextTick(() => {\n      cb(null, { data2: 'data 2' });\n    });\n  };\n\n  const fn3 = (data, cb) => {\n    count++;\n    process.nextTick(() => {\n      cb(null, { data3: 'data 3' });\n    });\n  };\n\n  const fn4 = (data, cb) => {\n    count++;\n    process.nextTick(() => {\n      cb(null, { data4: 'data 4' });\n    });\n  };\n\n  const fc = metasync([fn1, [[fn2, fn3]], fn4]);\n  fc({}, (err, data) => {\n    test.error(err);\n    test.strictSame(data, {\n      data1: 'data 1',\n      data2: 'data 2',\n      data3: 'data 3',\n      data4: 'data 4',\n    });\n    test.strictSame(count, 4);\n    test.end();\n  });\n\n  setTimeout(() => {\n    fc.cancel();\n  }, 100);\n});\n\nmetatests.test('async functions composition to array', (test) => {\n  let count = 0;\n\n  const fn1 = (data, cb) => {\n    count++;\n    process.nextTick(() => cb(null, 'data 1'));\n  };\n\n  const fn2 = (data, cb) => {\n    count++;\n    process.nextTick(() => cb(null, 'data 2'));\n  };\n\n  const fn3 = (data, cb) => {\n    count++;\n    process.nextTick(() => cb(null, 'data 3'));\n  };\n\n  const fn4 = (data, cb) => {\n    count++;\n    process.nextTick(() => cb(null, 'data 4'));\n  };\n\n  const fc = metasync([fn1, [[fn2, fn3]], fn4]);\n  fc(['data 0'], (err, data) => {\n    test.error(err);\n    test.strictSame(data, ['data 0', 'data 1', 'data 2', 'data 3', 'data 4']);\n    test.strictSame(count, 4);\n    test.end();\n  });\n});\n"
  },
  {
    "path": "test/compose.then.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('successful then', (test) => {\n  let finishedFuncsCount = 0;\n  const res1 = 'res1';\n  const af1 = (data, callback) =>\n    process.nextTick(() => {\n      test.strictSame(data, {});\n      test.strictSame(finishedFuncsCount, 0);\n      finishedFuncsCount++;\n      callback(null, { res1 });\n    });\n  const res2 = 'res2';\n  const af2 = (data, callback) =>\n    process.nextTick(() => {\n      test.strictSame(data, { res1 });\n      test.strictSame(finishedFuncsCount, 1);\n      finishedFuncsCount++;\n      callback(null, { res2 });\n    });\n  const res3 = 'res3';\n  const af3 = (data, callback) =>\n    process.nextTick(() => {\n      const keysCount = Object.keys(data).length;\n      test.ok(keysCount >= 2 && keysCount < 4);\n      test.ok(finishedFuncsCount >= 2 && finishedFuncsCount < 4);\n      finishedFuncsCount++;\n      callback(null, { res3 });\n    });\n  const res4 = 'res4';\n  const af4 = (data, callback) =>\n    process.nextTick(() => {\n      const keysCount = Object.keys(data).length;\n      test.ok(keysCount >= 2 && keysCount < 4);\n      test.ok(finishedFuncsCount >= 2 && finishedFuncsCount < 4);\n      finishedFuncsCount++;\n      callback(null, { res4 });\n    });\n  const faf1 = metasync([af1, [[af2, af3]], af4]);\n  faf1().then(\n    (res) => {\n      test.strictSame(res, {\n        res1: 'res1',\n        res2: 'res2',\n        res3: 'res3',\n        res4: 'res4',\n      });\n      test.strictSame(finishedFuncsCount, 4);\n      test.end();\n    },\n    (err) => {\n      test.error(err);\n    },\n  );\n});\n"
  },
  {
    "path": "test/composition.cancel.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\n// Emulate Asynchronous calls of function\n//   callback - function\nconst wrapAsync = (callback) => {\n  setTimeout(callback, Math.floor(Math.random() * 500));\n};\n\nmetatests.test('async functions composition cancel in the middle', (test) => {\n  let fc = null;\n  const fn1 = test.mustCall((data, cb) => {\n    wrapAsync(() => {\n      cb(null, 1);\n    });\n  });\n\n  const fn2 = test.mustCall((data, cb) => {\n    test.strictSame(data, [1]);\n    wrapAsync(() => {\n      if (fc) fc.cancel();\n      cb(null, 2);\n    });\n  });\n\n  const fn3 = test.mustNotCall();\n  const fn4 = test.mustNotCall();\n\n  fc = metasync([fn1, fn2, fn3, fn4]);\n\n  fc([], (err, data) => {\n    test.isError(err, new Error('Metasync: asynchronous composition canceled'));\n    test.strictSame(data, undefined);\n    test.end();\n  });\n});\n"
  },
  {
    "path": "test/composition.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\nconst fs = require('fs');\n\nconst getPerson = (context, cb) => {\n  const persons = [\n    { name: 'Marcus Aurelius', city: 'Rome', born: 121 },\n    { name: 'Mao Zedong', city: 'Shaoshan', born: 1893 },\n  ];\n  const person = persons.find((p) => p.name === context.name);\n  cb(null, { person });\n};\n\nconst lookupCountry = (context, cb) => {\n  const dictionary = {\n    Rome: 'Roman Empire',\n    Shaoshan: 'Quin Empire',\n  };\n  const country = dictionary[context.person.city];\n  cb(null, { country });\n};\n\nconst prepareResult = (context, cb) => {\n  const result = Object.assign({}, context.person, {\n    country: context.country,\n    length: context.buffer.length,\n  });\n  cb(null, { result });\n};\n\nmetatests.test('sync complex functions composition', (test) => {\n  const readFile = (context, cb) => {\n    fs.readFile(context.file, (err, buffer) => {\n      test.error(err);\n      cb(null, { buffer });\n    });\n  };\n\n  const fc = metasync([getPerson, [[lookupCountry, readFile]], prepareResult]);\n\n  fc(\n    {\n      name: 'Mao Zedong',\n      file: './AUTHORS',\n    },\n    (err, context) => {\n      test.error(err);\n      const expected = {\n        name: 'Mao Zedong',\n        city: 'Shaoshan',\n        born: 1893,\n        country: 'Quin Empire',\n        length: 318,\n      };\n      test.strictSame(context.result, expected);\n      test.end();\n    },\n  );\n});\n"
  },
  {
    "path": "test/composition.parallel.js",
    "content": "'use strict';\n\nconst metatests = require('metatests');\nconst metasync = require('..');\n\n// Emulate Asynchronous calls of function\n//   callback - function\nconst wrapAsync = (callback) => {\n  setTimeout(callback, Math.floor(Math.random() * 500));\n};\n\nmetatests.test('async complex functions composition', (test) => {\n  const fn1 = test.mustCall((data, cb) => {\n    wrapAsync(() => {\n      cb(null, 1);\n    });\n  });\n\n  const fn2 = test.mustCall((data, cb) => {\n    wrapAsync(() => {\n      cb(null, 2);\n    });\n  });\n\n  const fn3 = test.mustCall((data, cb) => {\n    test.strictSame(data.length, 2);\n    wrapAsync(() => {\n      cb(null, 3);\n    });\n  });\n\n  const fn4 = test.mustCall((data, cb) => {\n    wrapAsync(() => {\n      cb(null, 4);\n    });\n  });\n\n  const fc = metasync([[[fn1, fn2]], fn3, fn4]);\n\n  fc([], (err, data) => {\n    test.error(err);\n    test.strictSame(data.length, 4);\n    test.end();\n  });\n});\n"
  },
  {
    "path": "test/composition.pause.js",
    "content": "'use strict';\n\nconst metatests = require('metatests');\nconst metasync = require('..');\nconst fs = require('fs');\n\nconst getPerson = (context, cb) => {\n  const persons = [\n    { name: 'Marcus Aurelius', city: 'Rome', born: 121 },\n    { name: 'Mao Zedong', city: 'Shaoshan', born: 1893 },\n  ];\n  const person = persons.find((p) => p.name === context.name);\n  cb(null, { person });\n};\n\nconst lookupCountry = (context, cb) => {\n  const dictionary = {\n    Rome: 'Roman Empire',\n    Shaoshan: 'Quin Empire',\n  };\n  const country = dictionary[context.person.city];\n  cb(null, { country });\n};\n\nconst prepareResult = (context, cb) => {\n  const result = Object.assign({}, context.person, {\n    country: context.country,\n    length: context.buffer.length,\n  });\n  cb(null, { result });\n};\n\nmetatests.test('async functions composition pause in the middle', (test) => {\n  const readFile = (context, cb) => {\n    fs.readFile(context.file, (err, buffer) => {\n      test.error(err);\n      cb(null, { buffer });\n    });\n  };\n\n  const fc = metasync([getPerson, [[lookupCountry, readFile]], prepareResult]);\n\n  fc(\n    {\n      name: 'Mao Zedong',\n      file: './AUTHORS',\n    },\n    (err, context) => {\n      test.error(err);\n      const expected = {\n        name: 'Mao Zedong',\n        city: 'Shaoshan',\n        born: 1893,\n        country: 'Quin Empire',\n        length: 318,\n      };\n      test.strictSame(context.result, expected);\n      test.end();\n    },\n  );\n\n  process.nextTick(() => {\n    fc.pause();\n    setTimeout(() => {\n      fc.resume();\n    }, 1000);\n  });\n});\n"
  },
  {
    "path": "test/composition.sequential.js",
    "content": "'use strict';\n\nconst metatests = require('metatests');\nconst metasync = require('..');\n\nmetatests.test('sequential functions', (test) => {\n  const f1 = test.mustCall((c, cb) => cb());\n  const f2 = test.mustCall((c, cb) => cb());\n  const f3 = test.mustCall((c, cb) => cb());\n  const f4 = test.mustCall((c, cb) => cb());\n\n  const fc = metasync([f1, f2, f3, f4]);\n\n  fc((err, context) => {\n    test.error(err);\n    test.strictSame(context, {});\n    test.end();\n  });\n});\n"
  },
  {
    "path": "test/control.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('firstOf', (test) => {\n  const returningFnIndex = 2;\n  let dataReturned = false;\n\n  const execUnlessDataReturned = (data) => (callback) => {\n    if (dataReturned) {\n      callback(null, data);\n    } else {\n      process.nextTick(execUnlessDataReturned);\n    }\n  };\n  const makeIFn = (i) => (callback) =>\n    process.nextTick(() => {\n      const iData = 'data' + i;\n      if (i === returningFnIndex) {\n        dataReturned = true;\n        callback(null, iData);\n      } else {\n        execUnlessDataReturned(iData);\n      }\n    });\n\n  const fns = [1, 2, 3].map(makeIFn);\n\n  metasync.firstOf(fns, (err, data) => {\n    test.error(err);\n    test.strictSame(data, 'data2');\n    test.end();\n  });\n});\n\nmetatests.test('parallel with error', (test) => {\n  const parallelError = new Error('Parallel error');\n\n  const fn1 = (data, cb) => {\n    process.nextTick(() => {\n      cb(null, { data1: 'data 1' });\n    });\n  };\n\n  const fn2 = (data, cb) => {\n    process.nextTick(() => {\n      cb(parallelError);\n    });\n  };\n\n  metasync.parallel([fn1, fn2], (err, res) => {\n    test.strictSame(err, parallelError);\n    test.strictSame(res, undefined);\n    test.end();\n  });\n});\n\nmetatests.test('sequential with error', (test) => {\n  const sequentialError = new Error('Sequential error');\n  const expectedDataInFn2 = { data1: 'data 1' };\n\n  const fn1 = (data, cb) => {\n    process.nextTick(() => {\n      cb(null, { data1: 'data 1' });\n    });\n  };\n\n  const fn2 = (data, cb) => {\n    process.nextTick(() => {\n      test.same(data, expectedDataInFn2);\n      cb(sequentialError);\n    });\n  };\n\n  metasync.sequential([fn1, fn2], (err, res) => {\n    test.strictSame(err, sequentialError);\n    test.strictSame(res, undefined);\n    test.end();\n  });\n});\n\nmetatests.test('runIf run asyncFn', (test) => {\n  const asyncFn = test.mustCall((arg1, arg2, cb) => {\n    process.nextTick(() => {\n      cb(null, { arg1, arg2 });\n    });\n  });\n\n  metasync.runIf(true, asyncFn, 'val1', 'val2', (err, result) => {\n    test.error(err);\n    test.strictSame(result, { arg1: 'val1', arg2: 'val2' });\n    test.end();\n  });\n});\n\nmetatests.test('runIf do not run asyncFn', (test) => {\n  const asyncFn = test.mustNotCall((arg1, arg2, cb) => {\n    process.nextTick(() => {\n      cb(null, { arg1, arg2 });\n    });\n  });\n\n  metasync.runIf(false, asyncFn, 'val1', 'val2', (err, result) => {\n    test.error(err);\n    test.strictSame(result, undefined);\n    test.end();\n  });\n});\n\nmetatests.test('runIf default value', (test) => {\n  const asyncFn = test.mustNotCall((val, cb) => {\n    process.nextTick(() => {\n      cb(null, val);\n    });\n  });\n\n  metasync.runIf(false, 'default', asyncFn, 'val', (err, result) => {\n    test.error(err);\n    test.strictSame(result, 'default');\n    test.end();\n  });\n});\n\nmetatests.test('runIf forward an error', (test) => {\n  const asyncFn = test.mustCall((cb) => {\n    process.nextTick(() => {\n      cb(new Error());\n    });\n  });\n\n  metasync.runIf(true, asyncFn, (err) => {\n    test.isError(err);\n    test.end();\n  });\n});\n\nmetatests.test('runIfFn', (test) => {\n  test.plan(5);\n  const value = 42;\n  const asyncFn = (cb) => {\n    cb(null, value);\n  };\n\n  metasync.runIfFn(test.mustCall(asyncFn), (err, res) => {\n    test.error(err);\n    test.strictSame(res, value);\n  });\n\n  metasync.runIfFn(null, (err, res) => {\n    test.error(err);\n    test.assertNot(res);\n  });\n});\n"
  },
  {
    "path": "test/do.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\n// Emulate Asynchronous calls of function\n//   callback - <Function>\nconst wrapAsync = (callback) => {\n  setTimeout(callback, Math.floor(Math.random() * 500));\n};\n\nmetatests.test('simple chain/do', (test) => {\n  const readConfig = test.mustCall((name, callback) => {\n    test.strictSame(name, 'myConfig');\n    wrapAsync(() => {\n      callback(null, { name });\n    });\n  });\n\n  const selectFromDb = test.mustCall((query, callback) => {\n    test.strictSame(query, 'select * from cities');\n    wrapAsync(() => {\n      callback(null, [{ name: 'Kiev' }, { name: 'Roma' }]);\n    });\n  });\n\n  const getHttpPage = test.mustCall((url, callback) => {\n    test.strictSame(url, 'http://kpi.ua');\n    wrapAsync(() => {\n      callback(null, '<html>Some archaic web here</html>');\n    });\n  });\n\n  const readFile = test.mustCall((path, callback) => {\n    test.strictSame(path, 'README.md');\n    wrapAsync(() => {\n      callback(null, 'file content');\n    });\n  });\n\n  const c1 = metasync\n    .do(readConfig, 'myConfig')\n    .do(selectFromDb, 'select * from cities')\n    .do(getHttpPage, 'http://kpi.ua')\n    .do(readFile, 'README.md');\n\n  c1((err, result) => {\n    test.error(err);\n    test.strictSame(result, 'file content');\n    test.end();\n  });\n});\n"
  },
  {
    "path": "test/examples.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst fs = require('fs');\nconst metatests = require('metatests');\nconst path = require('path');\nconst ASYNC_TIMEOUT = 200;\n\n// Data Collector\n\nmetatests.test('dataCollector / simple', (test) => {\n  const dataCollector = metasync.collect(4).done((err, data) => {\n    test.error(err);\n    test.strictSame(Object.keys(data).length, 4);\n    test.end();\n  });\n\n  dataCollector.collect('user', null, { name: 'Marcus Aurelius' });\n\n  fs.readFile(path.join(__dirname, '..', 'README.md'), (err, data) => {\n    dataCollector.collect('readme', err, data);\n  });\n\n  fs.readFile(path.join(__dirname, '..', 'AUTHORS'), (err, data) => {\n    dataCollector.collect('authors', err, data);\n  });\n\n  setTimeout(() => {\n    dataCollector.pick('timer', { date: new Date() });\n  }, ASYNC_TIMEOUT);\n});\n\nmetatests.test('data collector / timeout', (test) => {\n  const expectedErr = new Error('Metasync: Collector timed out');\n  const expectedData = { user: { name: 'Marcus Aurelius' } };\n\n  const dataCollector = metasync\n    .collect(4)\n    .timeout(1000)\n    .done((err, data) => {\n      test.isError(err, expectedErr);\n      test.strictSame(data, expectedData);\n      test.end();\n    });\n\n  dataCollector.pick('user', { name: 'Marcus Aurelius' });\n});\n\nmetatests.test('data collector / error', (test) => {\n  const expectedErr = new Error('User not found');\n  const expectedData = { file: 'file content' };\n\n  const dataCollector = metasync.collect(4).done((err, data) => {\n    test.isError(err, expectedErr);\n    test.strictSame(data, expectedData);\n    test.end();\n  });\n\n  dataCollector.pick('file', 'file content');\n  dataCollector.fail('user', new Error('User not found'));\n  dataCollector.pick('score', 1000);\n  dataCollector.fail('tcp', new Error('No socket'));\n});\n\n// Key Collector\n\nmetatests.test('key collector / simple', (test) => {\n  const keyCollector = metasync\n    .collect(['user', 'readme'])\n    .timeout(2000)\n    .done((err, data) => {\n      test.error(err);\n      test.strictSame(Object.keys(data).length, 2);\n      test.end();\n    });\n\n  keyCollector.pick('user', { name: 'Marcus Aurelius' });\n\n  fs.readFile(path.join(__dirname, '..', 'README.md'), (err, data) => {\n    test.error(err);\n    keyCollector.pick('readme', data);\n  });\n});\n\n// Parallel execution\n\nmetatests.test('parallel', (test) => {\n  test.plan(5);\n\n  const expectedData = {\n    data1: 'result1',\n    data2: 'result2',\n    data3: 'result3',\n    arg: 'arg',\n  };\n\n  const pf1 = (data, callback) => {\n    test.pass('must call');\n    setTimeout(() => callback(null, { data1: 'result1' }), ASYNC_TIMEOUT);\n  };\n\n  const pf2 = (data, callback) => {\n    test.pass('must call');\n    setTimeout(() => callback(null, { data2: 'result2' }), ASYNC_TIMEOUT);\n  };\n\n  const pf3 = (data, callback) => {\n    test.pass('must call');\n    setTimeout(() => callback(null, { data3: 'result3' }), ASYNC_TIMEOUT);\n  };\n\n  metasync.parallel([pf1, pf2, pf3], { arg: 'arg' }, (err, data) => {\n    test.error(err);\n    test.strictSame(data, expectedData);\n  });\n});\n\n// Sequential execution\n\nmetatests.test('sequential', (test) => {\n  test.plan(5);\n\n  const sf1 = (data, callback) => {\n    test.strictSame(data, ['arg']);\n    setTimeout(() => callback(null, 'result1'), ASYNC_TIMEOUT);\n  };\n\n  const sf2 = (data, callback) => {\n    test.pass('must call');\n    setTimeout(() => callback(null, 'result2'), ASYNC_TIMEOUT);\n  };\n\n  const sf3 = (data, callback) => {\n    test.strictSame(data, ['arg', 'result1', 'result2']);\n    setTimeout(() => callback(null, 'result3'), ASYNC_TIMEOUT);\n  };\n\n  metasync.sequential([sf1, sf2, sf3], ['arg'], (err, data) => {\n    test.error(err);\n    test.strictSame(data, ['arg', 'result1', 'result2', 'result3']);\n  });\n});\n\n// Asynchrous filter\n\nmetatests.test('asynchronus filter', (test) => {\n  const dataToFilter = [\n    'Lorem',\n    'ipsum',\n    'dolor',\n    'sit',\n    'amet',\n    'consectetur',\n    'adipiscing',\n    'elit',\n    'sed',\n    'do',\n    'eiusmod',\n    'tempor',\n    'incididunt',\n    'ut',\n    'labore',\n    'et',\n    'dolore',\n    'magna',\n    'aliqua',\n  ];\n\n  const expectedResult = [\n    'Lorem',\n    'ipsum',\n    'sit',\n    'amet',\n    'elit',\n    'sed',\n    'do',\n    'eiusmod',\n    'tempor',\n    'ut',\n    'labore',\n    'et',\n  ];\n\n  const filterPredicate = (item, callback) => {\n    // filter words which consists of unique letters only\n    const letters = [];\n    for (let i = 0; i < item.length; ++i) {\n      if (letters.includes(item[i].toLowerCase())) break;\n      letters.push(item[i].toLowerCase());\n    }\n\n    setTimeout(\n      () => callback(null, letters.length === item.length),\n      ASYNC_TIMEOUT,\n    );\n  };\n\n  metasync.filter(dataToFilter, filterPredicate, (err, result) => {\n    test.error(err);\n    test.strictSame(result, expectedResult);\n    test.end();\n  });\n});\n\n// Asynchrous find\n\nmetatests.test('asynchronus find', (test) => {\n  metasync.find(\n    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],\n    (item, callback) => callback(null, item % 3 === 0 && item % 5 === 0),\n    (err, result) => {\n      test.error(err);\n      test.strictSame(result, 15);\n      test.end();\n    },\n  );\n});\n\n// Asynchrous some\nmetatests.test('asynchronus some', (test) => {\n  metasync.some(\n    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],\n    (item, callback) => {\n      const res = item % 3 === 0 && item % 5 === 0;\n      callback(null, res);\n    },\n    (err, result) => {\n      test.error(err);\n      test.strictSame(result, true);\n      test.end();\n    },\n  );\n});\n\n// Asyncronous each in parallel\n\nmetatests.test('asyncronous each', (test) => {\n  const result = {};\n  metasync.each(\n    ['a', 'b', 'c'],\n    (item, callback) => {\n      result[item] = item;\n      callback(null);\n    },\n    (err) => {\n      test.error(err);\n      test.strictSame(result, { a: 'a', b: 'b', c: 'c' });\n      test.end();\n    },\n  );\n});\n\n// Asyncronous series (sequential)\n\nmetatests.test('asynchronus series', (test) => {\n  const result = [];\n  metasync.series(\n    ['a', 'b', 'c', 'd'],\n    (item, callback) => {\n      result.push(item.toUpperCase());\n      callback(null);\n    },\n    (err) => {\n      test.error(err);\n      test.strictSame(result, ['A', 'B', 'C', 'D']);\n      test.end();\n    },\n  );\n});\n\n// Asyncronous reduce (sequential)\n\nmetatests.test('asynchronus reduce', (test) => {\n  metasync.reduce(\n    ['a', 'b', 'c', 'd'],\n    (prev, curr, callback) => {\n      callback(null, prev + curr);\n    },\n    (err, data) => {\n      test.error(err);\n      test.strictSame(data, 'abcd');\n      test.end();\n    },\n  );\n});\n\n// Queue\n\nmetatests.test('queue / simple', (test) => {\n  const expectedResult = [1, 2, 3, 4, 5, 6, 8, 9];\n  const result = [];\n\n  const queue = metasync\n    .queue(3)\n    .process((item, callback) => {\n      result.push(item.id);\n      setTimeout(callback, 100);\n    })\n    .drain(() => {\n      test.strictSame(result, expectedResult);\n      test.end();\n    });\n\n  queue.add({ id: 1 });\n  queue.add({ id: 2 });\n  queue.add({ id: 3 });\n  queue.add({ id: 4 });\n  queue.add({ id: 5 });\n  queue.add({ id: 6 });\n  queue.add({ id: 8 });\n  queue.add({ id: 9 });\n});\n\nmetatests.test('queue / pause', (test) => {\n  const expectedResult = [1, 3, 4, 7, 8, 9];\n  const result = [];\n\n  const queue = metasync\n    .queue(3)\n    .process((item, callback) => {\n      result.push(item.id);\n      setTimeout(callback, 100);\n    })\n    .drain(() => {\n      test.strictSame(result, expectedResult);\n      test.end();\n    });\n\n  queue.add({ id: 1 });\n  queue.pause();\n\n  queue.add({ id: 2 });\n\n  queue.resume();\n\n  queue.add({ id: 3 });\n  queue.add({ id: 4 });\n  queue.add({ id: 5 });\n  queue.add({ id: 6 });\n\n  queue.clear();\n\n  queue.add({ id: 7 });\n  queue.add({ id: 8 });\n  queue.add({ id: 9 });\n});\n\n// Trottle\n\nmetatests.test('trottle', (test) => {\n  const expectedResult = ['A', 'E', 'F', 'I'];\n  const result = [];\n  let state;\n\n  const fn = () => {\n    result.push(state);\n  };\n\n  const f1 = metasync.throttle(500, fn);\n\n  // to be called 2 times (first and last: A and E)\n  state = 'A';\n  f1();\n  state = 'B';\n  f1();\n  state = 'C';\n  f1();\n  state = 'D';\n  f1();\n  state = 'E';\n  f1();\n\n  // to be called 2 times (last will be I)\n  setTimeout(() => {\n    state = 'F';\n    f1();\n  }, 600);\n  setTimeout(() => {\n    state = 'G';\n    f1();\n  }, 700);\n  setTimeout(() => {\n    state = 'H';\n    f1();\n  }, 1000);\n  setTimeout(() => {\n    state = 'I';\n    f1();\n  }, 1100);\n\n  setTimeout(() => {\n    test.strictSame(result, expectedResult);\n    test.end();\n  }, 3000);\n});\n\n// Debounce\n\nmetatests.test('debounce', (test) => {\n  const expectedResult = ['E', 'I'];\n  const result = [];\n  let state;\n\n  const fn = () => {\n    result.push(state);\n  };\n\n  const f1 = metasync.debounce(500, fn, ['I']);\n\n  // to be called one time (E)\n  state = 'A';\n  f1();\n  state = 'B';\n  f1();\n  state = 'C';\n  f1();\n  state = 'D';\n  f1();\n  state = 'E';\n  f1();\n\n  // to be called one time (I)\n  setTimeout(() => {\n    state = 'F';\n    f1();\n  }, 600);\n  setTimeout(() => {\n    state = 'G';\n    f1();\n  }, 700);\n  setTimeout(() => {\n    state = 'H';\n    f1();\n  }, 1000);\n  setTimeout(() => {\n    state = 'I';\n    f1();\n  }, 1100);\n\n  setTimeout(() => {\n    test.strictSame(result, expectedResult);\n    test.end();\n  }, 3000);\n});\n\n// Map\n\nmetatests.test('asynchronus map / simple', (test) => {\n  metasync.map(\n    [1, 2, 3],\n    (item, callback) => {\n      setTimeout(() => {\n        callback(null, item * item);\n      }, item * 10);\n    },\n    (error, result) => {\n      test.error(error);\n      test.strictSame(result, [1, 4, 9]);\n      test.end();\n    },\n  );\n});\n\nmetatests.test('asynchronus map / error', (test) => {\n  metasync.map(\n    [1, 2, 3],\n    (item, callback) => {\n      setTimeout(() => {\n        if (item === 2) {\n          callback(new Error());\n        } else {\n          callback(null, item);\n        }\n      }, item * 10);\n    },\n    (error, result) => {\n      test.isError(error);\n      test.strictSame(result, undefined);\n      test.end();\n    },\n  );\n});\n\n// Timeout\n\nmetatests.test('timeout', (test) => {\n  metasync.timeout(\n    200,\n    (done) => {\n      setTimeout(done, 300);\n    },\n    (err) => {\n      const expectedErr = new Error(\n        'Metasync: asynchronous function timed out',\n      );\n      test.isError(err, expectedErr);\n      test.end();\n    },\n  );\n});\n"
  },
  {
    "path": "test/firstOf.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('firstOf', (test) => {\n  const returningFnIndex = 2;\n  let dataReturned = false;\n\n  const execUnlessDataReturned = (data) => (callback) => {\n    if (dataReturned) {\n      callback(null, data);\n    } else {\n      process.nextTick(execUnlessDataReturned);\n    }\n  };\n  const makeIFn = (i) => (callback) =>\n    process.nextTick(() => {\n      const iData = 'data' + i;\n      if (i === returningFnIndex) {\n        dataReturned = true;\n        callback(null, iData);\n      } else {\n        execUnlessDataReturned(iData);\n      }\n    });\n\n  const fns = [1, 2, 3].map(makeIFn);\n\n  metasync.firstOf(fns, (err, data) => {\n    test.error(err);\n    test.strictSame(data, 'data2');\n    test.end();\n  });\n});\n"
  },
  {
    "path": "test/fp.ap.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nconst asyncArgs = (callback) => process.nextTick(() => callback(null, 4, 5));\nconst functionInCallback = (callback) =>\n  process.nextTick(() => callback(null, (x, y) => x + y));\nconst asyncError = new Error('Async error');\nconst asyncErrorCb = (callback) => process.nextTick(() => callback(asyncError));\n\nmetatests.test('two successful functions', (test) => {\n  metasync.ap(\n    asyncArgs,\n    functionInCallback,\n  )((err, res) => {\n    test.error(err);\n    test.strictSame(res, 9);\n    test.end();\n  });\n});\n\nmetatests.test('first function with error', (test) => {\n  metasync.ap(\n    asyncErrorCb,\n    functionInCallback,\n  )((err, res) => {\n    test.strictSame(err, asyncError);\n    test.strictSame(res, undefined);\n    test.end();\n  });\n});\n\nmetatests.test('second function with error', (test) => {\n  metasync.ap(\n    asyncArgs,\n    asyncErrorCb,\n  )((err, res) => {\n    test.strictSame(err, asyncError);\n    test.strictSame(res, undefined);\n    test.end();\n  });\n});\n"
  },
  {
    "path": "test/fp.asAsync.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nconst asyncSum = (x, y, callback) =>\n  process.nextTick(() => callback(null, x + y));\nconst tripleFnInCb = (callback) =>\n  process.nextTick(() => callback(null, (x) => x * 3));\nconst asyncMultBy11 = (x, callback) =>\n  process.nextTick(() => callback(null, x * 11));\n\nmetatests.test('asAsync all functions test', (test) => {\n  const done = (err, res) => {\n    test.error(err);\n    test.strictSame(res, 1848);\n    test.end();\n  };\n  metasync\n    .asAsync(asyncSum, 3, 5)\n    .fmap((x) => x * 7)\n    .ap(tripleFnInCb)\n    .concat(asyncMultBy11)(done);\n});\n"
  },
  {
    "path": "test/fp.concat.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nconst asyncData = 'data';\nconst asyncDataCb = (callback) =>\n  process.nextTick(() => callback(null, asyncData));\nconst asyncTwice = (str, callback) =>\n  process.nextTick(() => callback(null, str + str));\nconst asyncError = new Error('Async error');\nconst asyncErrorCb = (callback) => process.nextTick(() => callback(asyncError));\nconst asyncTransformErrorCb = (str, callback) =>\n  process.nextTick(() => callback(asyncError));\n\nmetatests.test('two successful functions', (test) => {\n  metasync.concat(\n    asyncDataCb,\n    asyncTwice,\n  )((err, res) => {\n    test.error(err);\n    test.strictSame(res, 'datadata');\n    test.end();\n  });\n});\n\nmetatests.test('first function error', (test) => {\n  metasync.concat(\n    asyncErrorCb,\n    asyncTwice,\n  )((err, res) => {\n    test.strictSame(err, asyncError);\n    test.strictSame(res, undefined);\n    test.end();\n  });\n});\n\nmetatests.test('second function error', (test) => {\n  metasync.concat(\n    asyncDataCb,\n    asyncTransformErrorCb,\n  )((err, res) => {\n    test.strictSame(err, asyncError);\n    test.strictSame(res, undefined);\n    test.end();\n  });\n});\n"
  },
  {
    "path": "test/fp.fmap.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nconst asyncData = 'data';\nconst asyncDataCb = (callback) =>\n  process.nextTick(() => {\n    callback(null, asyncData);\n  });\nconst asyncError = new Error('Async error');\nconst asyncErrorCb = (callback) =>\n  process.nextTick(() => {\n    callback(asyncError);\n  });\nconst identity = (x) => x;\nconst repeatStringTwice = (str) => str + str;\nconst appendColon = (str) => str + ':';\nconst twiceAndColon = (str) => appendColon(repeatStringTwice(str));\n\nmetatests.test('Result transformation', (test) => {\n  const expected = 'data:';\n  metasync.fmap(\n    asyncDataCb,\n    appendColon,\n  )((err, res) => {\n    test.error(err);\n    test.strictSame(expected, res);\n    test.end();\n  });\n});\n\nmetatests.test('Getting asynchronous error', (test) => {\n  metasync.fmap(\n    asyncErrorCb,\n    appendColon,\n  )((err, res) => {\n    test.strictSame(err, asyncError);\n    test.strictSame(res, undefined);\n    test.end();\n  });\n});\n\nconst FP1 = 'Getting error with no second argument execution';\nmetatests.test(FP1, (test) => {\n  let executed = false;\n  metasync.fmap(asyncErrorCb, (str) => {\n    executed = true;\n    return appendColon(str);\n  })(() => {\n    test.strictSame(executed, false);\n    test.end();\n  });\n});\n\nmetatests.test('functor law I', (test) => {\n  metasync.fmap(\n    asyncDataCb,\n    identity,\n  )((err, res) => {\n    test.error(err);\n    test.strictSame(asyncData, res);\n    test.end();\n  });\n});\n\nmetatests.test('functor law II', (test) => {\n  const fmap = metasync.fmap;\n  const asyncTwice = fmap(asyncDataCb, repeatStringTwice);\n  const asyncTwiceAndColon = fmap(asyncTwice, appendColon);\n\n  asyncTwiceAndColon((err1, res1) => {\n    fmap(\n      asyncDataCb,\n      twiceAndColon,\n    )((err2, res2) => {\n      test.error(err1);\n      test.error(err2);\n      test.strictSame(res1, res2);\n      test.end();\n    });\n  });\n});\n"
  },
  {
    "path": "test/fp.of.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('of test', (test) => {\n  const args = [1, 2, 3, 4, 5];\n  metasync.of(...args)((err, ...argsCb) => {\n    test.error(err);\n    test.strictSame(args, argsCb);\n    test.end();\n  });\n});\n"
  },
  {
    "path": "test/memoize.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('memoize', (test) => {\n  const storage = {\n    file1: Buffer.from('file1'),\n    file2: Buffer.from('file2'),\n  };\n\n  const getData = (file, callback) => {\n    process.nextTick(() => {\n      const result = storage[file];\n      if (result) callback(null, result);\n      else callback(new Error('File not found'));\n    });\n  };\n\n  const memoizedGetData = metasync.memoize(getData);\n\n  const keys = [];\n  memoizedGetData.on('memoize', (key) => {\n    keys.push(key);\n  });\n\n  memoizedGetData('file1', (err, data) => {\n    test.error(err);\n    test.strictSame(data, storage.file1);\n    memoizedGetData('file2', (err, data) => {\n      test.error(err);\n      test.strictSame(data, storage.file2);\n      memoizedGetData('file1', (err, data) => {\n        test.error(err);\n        test.strictSame(data, storage.file1);\n        memoizedGetData('file2', (err, data) => {\n          test.error(err);\n          test.strictSame(data, storage.file2);\n          test.strictSame(keys, ['file1', 'file2']);\n          test.end();\n        });\n      });\n    });\n  });\n});\n\nmetatests.test('memoize clear cache', (test) => {\n  const storage = {\n    file1: Buffer.from('file1'),\n  };\n\n  const getData = (file, callback) => {\n    process.nextTick(() => {\n      const result = storage[file];\n      if (result) callback(null, result);\n      else callback(new Error('File not found'));\n    });\n  };\n\n  const memoizedGetData = metasync.memoize(getData);\n\n  let onClear = false;\n  memoizedGetData.on('clear', () => {\n    onClear = true;\n  });\n\n  memoizedGetData('file1', (err, data) => {\n    test.error(err);\n    test.strictSame(data, storage.file1);\n    storage.file1 = Buffer.from('changed');\n    memoizedGetData.clear();\n    memoizedGetData('file1', (err, data) => {\n      test.error(err);\n      test.strictSame(data, Buffer.from('changed'));\n      test.strictSame(onClear, true);\n      test.end();\n    });\n  });\n});\n\nmetatests.test('memoize cache del', (test) => {\n  const storage = {\n    file1: Buffer.from('file1'),\n  };\n\n  const getData = (file, callback) => {\n    process.nextTick(() => {\n      const result = storage[file];\n      if (result) callback(null, result);\n      else callback(new Error('File not found'));\n    });\n  };\n\n  const memoizedGetData = metasync.memoize(getData);\n\n  let onDel = false;\n  memoizedGetData.on('del', () => {\n    onDel = true;\n  });\n\n  memoizedGetData('file1', (err, data) => {\n    test.error(err);\n    test.strictSame(data, storage.file1);\n    storage.file1 = Buffer.from('changed');\n    memoizedGetData.del('file1');\n    memoizedGetData('file1', (err, data) => {\n      test.error(err);\n      test.strictSame(data, Buffer.from('changed'));\n      test.strictSame(onDel, true);\n      test.end();\n    });\n  });\n});\n\nmetatests.test('memoize cache add', (test) => {\n  const getData = (file, callback) => {\n    process.nextTick(() => {\n      const result = Buffer.from('added');\n      callback(null, result);\n    });\n  };\n\n  const memoizedGetData = metasync.memoize(getData);\n\n  let onAdd = false;\n  memoizedGetData.on('add', () => {\n    onAdd = true;\n  });\n\n  const file1 = Buffer.from('added');\n  memoizedGetData.add('file1', null, file1);\n  memoizedGetData('file1', (err, data) => {\n    test.error(err);\n    test.strictSame(data, Buffer.from('added'));\n    test.strictSame(onAdd, true);\n    test.end();\n  });\n});\n\nmetatests.test('memoize cache get', (test) => {\n  const getData = (file, callback) => {\n    process.nextTick(() => {\n      const result = Buffer.from('added');\n      callback(null, result);\n    });\n  };\n\n  const memoizedGetData = metasync.memoize(getData);\n\n  const file1 = Buffer.from('added');\n  memoizedGetData.add('file1', null, file1);\n  memoizedGetData.get('file1', (err, data) => {\n    test.error(err);\n    test.strictSame(data, Buffer.from('added'));\n    test.end();\n  });\n});\n"
  },
  {
    "path": "test/poolify.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('poolify simple', (test) => {\n  const buffer = () => new Uint32Array(128);\n\n  const pool = metasync.poolify(buffer, 10, 15, 20);\n\n  pool((item1) => {\n    test.strictSame(pool.items.length, 14);\n    test.strictSame(item1.length, 128);\n    pool((item2) => {\n      test.strictSame(pool.items.length, 13);\n      test.strictSame(item2.length, 128);\n      pool([item1]);\n      pool([item2]);\n      test.strictSame(pool.items.length, 15);\n      test.end();\n    });\n  });\n});\n\nmetatests.test('poolify loop', (test) => {\n  const buffer = () => new Uint32Array(128);\n\n  const pool = metasync.poolify(buffer, 10, 15, 20);\n\n  for (let i = 0; i < 15; i++) {\n    pool((item) => {\n      pool([item]);\n      if (i === 14) {\n        test.strictSame(item.length, 128);\n        test.end();\n      }\n    });\n  }\n});\n\nmetatests.test('poolify max', (test) => {\n  const buffer = () => new Uint32Array(128);\n\n  const pool = metasync.poolify(buffer, 5, 7, 10);\n\n  for (let i = 0; i < 15; i++) {\n    pool((item) => {\n      setTimeout(() => {\n        pool([item]);\n        if (i === 14) {\n          test.end();\n        }\n      }, 100);\n    });\n  }\n});\n\nmetatests.test('poolify delayed order', (test) => {\n  const buffer = () => new Uint32Array(128);\n\n  const pool = metasync.poolify(buffer, 0, 2, 2);\n\n  let get3 = false;\n  pool((item1) => {\n    test.strictSame(pool.items.length, 1);\n    pool((item2) => {\n      test.strictSame(pool.items.length, 0);\n      pool((item3) => {\n        test.strictSame(pool.items.length, 0);\n        test.strictSame(get3, false);\n        get3 = true;\n        pool([item3]);\n      });\n      pool((item4) => {\n        test.strictSame(pool.items.length, 1);\n        test.strictSame(get3, true);\n        pool([item4]);\n        test.end();\n      });\n      pool([item1]);\n      pool([item2]);\n    });\n  });\n});\n\nmetatests.test('poolify functor', (test) => {\n  const adder = (a) => (b) => adder(a + b);\n\n  const pool = metasync.poolify(adder, 1, 2, 3);\n\n  pool((item1) => {\n    test.strictSame(pool.items.length, 1);\n    pool((item2) => {\n      test.strictSame(pool.items.length, 0);\n      pool([item1]);\n      pool([item2]);\n      test.strictSame(pool.items.length, 2);\n      test.end();\n    });\n  });\n});\n\nmetatests.test('poolify get sync', (test) => {\n  const adder = (a) => (b) => adder(a + b);\n\n  const pool = metasync.poolify(adder, 1, 2, 3);\n\n  const item1 = pool();\n  test.strictSame(pool.items.length, 1);\n  const item2 = pool();\n  test.strictSame(pool.items.length, 0);\n  const item3 = pool();\n  test.strictSame(pool.items.length, 0);\n  const item4 = pool();\n  test.strictSame(item4, undefined);\n  test.strictSame(pool.items.length, 0);\n  pool([item1]);\n  pool([item2]);\n  pool([item3]);\n  test.strictSame(pool.items.length, 3);\n  test.end();\n});\n"
  },
  {
    "path": "test/queue.both.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('priority / roundRobin', (test) => {\n  const expectedResult = [\n    1, 2, 3, 8, 17, 13, 7, 4, 21, 12, 16, 11, 20, 15, 19, 10, 23, 14, 18, 9, 22,\n    6, 5,\n  ];\n  const result = [];\n\n  const q = metasync\n    .queue(3)\n    .roundRobin()\n    .priority()\n    .process((item, cb) => {\n      result.push(item.id);\n      setTimeout(cb, 100);\n    });\n\n  q.drain(() => {\n    test.strictSame(result, expectedResult);\n    test.end();\n  });\n\n  q.add({ id: 1 }, 1, 10);\n  q.add({ id: 2 }, 2, 10);\n  q.add({ id: 3 }, 3, 10);\n  q.add({ id: 4 }, 4, 20);\n  q.add({ id: 5 }, 1, 10);\n  q.add({ id: 6 }, 2, 10);\n  q.add({ id: 7 }, 3, 10);\n  q.add({ id: 8 }, 4, 50);\n  q.add({ id: 9 }, 2, 50);\n  q.add({ id: 10 }, 2, 60);\n  q.add({ id: 11 }, 2, 70);\n  q.add({ id: 12 }, 2, 80);\n  q.add({ id: 13 }, 2, 90);\n  q.add({ id: 14 }, 2, 60);\n  q.add({ id: 15 }, 2, 70);\n  q.add({ id: 16 }, 1, 80);\n  q.add({ id: 17 }, 1, 90);\n  q.add({ id: 18 }, 1, 60);\n  q.add({ id: 19 }, 1, 70);\n  q.add({ id: 20 }, 1, 80);\n  q.add({ id: 21 }, 1, 90);\n  q.add({ id: 22 }, 1, 60);\n  q.add({ id: 23 }, 1, 70);\n});\n"
  },
  {
    "path": "test/queue.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('queue add', (test) => {\n  const queue = metasync.queue(3).timeout(2000);\n  let taskIndex = 1;\n\n  queue.process((item, callback) => {\n    process.nextTick(() => {\n      test.strictSame(item, { id: taskIndex });\n      taskIndex++;\n      callback(null);\n    });\n  });\n\n  queue.drain(() => {\n    test.end();\n  });\n\n  let id;\n  for (id = 1; id < 10; id++) {\n    queue.add({ id });\n  }\n});\n\nmetatests.test('queue pause resume clear', (test) => {\n  const queue = metasync.queue(3);\n  queue.pause();\n  queue.add({ id: 1 });\n  test.strictSame(queue.count, 0);\n\n  let itemIsProcessed = false;\n  queue.process((item, callback) => {\n    itemIsProcessed = true;\n    callback(null);\n  });\n\n  queue.add({ id: 2 });\n  test.strictSame(itemIsProcessed, false);\n\n  queue.resume();\n  test.strictSame(queue.paused, false);\n\n  queue.clear();\n  test.strictSame(queue.count, 0);\n  test.end();\n});\n\nmetatests.test('queue with no process function and no timeout', (test) => {\n  const queue = metasync.queue(3);\n  queue.add({ id: 1 });\n  queue.add({ id: 2 });\n  queue.add({ id: 3 });\n\n  test.strictSame(queue.count, 0);\n  test.end();\n});\n\nmetatests.test('queue with timeout event', (test) => {\n  const timeoutErr = new Error('Metasync: Queue timed out');\n\n  const queue = metasync.queue(3);\n\n  queue.process((item, callback) => {\n    setTimeout(() => {\n      callback(null, item);\n    }, 1000);\n  });\n\n  queue.timeout(1, (err, res) => {\n    test.strictSame(err, timeoutErr);\n    test.strictSame(res, undefined);\n    test.end();\n  });\n\n  queue.add({ id: 1 });\n});\n"
  },
  {
    "path": "test/queue.lifo.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('lifo / simple', (test) => {\n  const expectedResult = [1, 2, 3, 9, 8, 7, 6, 5, 4];\n  const result = [];\n\n  const q = metasync\n    .queue(3)\n    .priority()\n    .lifo()\n    .process((item, cb) => {\n      result.push(item.id);\n      setTimeout(cb, 100);\n    });\n\n  q.drain(() => {\n    test.strictSame(result, expectedResult);\n    test.end();\n  });\n\n  q.add({ id: 1 });\n  q.add({ id: 2 });\n  q.add({ id: 3 });\n  q.add({ id: 4 });\n  q.add({ id: 5 });\n  q.add({ id: 6 });\n  q.add({ id: 7 });\n  q.add({ id: 8 });\n  q.add({ id: 9 });\n});\n"
  },
  {
    "path": "test/queue.modes.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('queue default FIFO', (test) => {\n  const queue = metasync.queue(3).timeout(1);\n  const res = [];\n\n  queue.process((item, callback) => {\n    process.nextTick(() => {\n      res.push(item.id);\n      callback();\n    });\n  });\n\n  queue.drain(() => {\n    test.strictSame(res, [1, 2, 3, 4, 5, 6, 7, 8, 9]);\n    test.end();\n  });\n\n  for (let id = 1; id < 10; id++) {\n    queue.add({ id });\n  }\n});\n\nmetatests.test('queue FIFO', (test) => {\n  const queue = metasync.queue(3).fifo().timeout(1);\n  const res = [];\n\n  queue.process((item, callback) => {\n    process.nextTick(() => {\n      res.push(item.id);\n      callback();\n    });\n  });\n\n  queue.drain(() => {\n    test.strictSame(res, [1, 2, 3, 4, 5, 6, 7, 8, 9]);\n    test.end();\n  });\n\n  for (let id = 1; id < 10; id++) {\n    queue.add({ id });\n  }\n});\n\nmetatests.test('queue LIFO', (test) => {\n  const queue = metasync.queue(3).lifo().timeout(1);\n  const res = [];\n\n  queue.process((item, callback) => {\n    process.nextTick(() => {\n      res.push(item.id);\n      callback();\n    });\n  });\n\n  queue.drain(() => {\n    test.strictSame(res, [1, 2, 3, 9, 8, 7, 6, 5, 4]);\n    test.end();\n  });\n\n  for (let id = 1; id < 10; id++) {\n    queue.add({ id });\n  }\n});\n\nmetatests.test('queue priority', (test) => {\n  const queue = metasync.queue(3).priority();\n  const res = [];\n\n  queue.process((item, callback) => {\n    process.nextTick(() => {\n      res.push(item.id);\n      callback();\n    });\n  });\n\n  queue.drain(() => {\n    test.strictSame(res, [1, 2, 3, 8, 5, 4, 7, 9, 6]);\n    test.end();\n  });\n\n  queue.add({ id: 1 }, 1);\n  queue.add({ id: 2 }, 4);\n  queue.add({ id: 3 }, 5);\n  queue.add({ id: 4 }, 7);\n  queue.add({ id: 5 }, 8);\n  queue.add({ id: 6 }, 2);\n  queue.add({ id: 7 }, 6);\n  queue.add({ id: 8 }, 9);\n  queue.add({ id: 9 }, 3);\n});\n\nmetatests.test('queue round robin', (test) => {\n  const queue = metasync.queue(3).roundRobin();\n  const res = [];\n\n  queue.process((item, callback) => {\n    process.nextTick(() => {\n      res.push(item.id);\n      callback();\n    });\n  });\n\n  queue.drain(() => {\n    test.strictSame(res, [1, 2, 3, 4, 7, 5, 8, 6, 9]);\n    test.end();\n  });\n\n  queue.add({ id: 1 }, 5);\n  queue.add({ id: 2 }, 5);\n  queue.add({ id: 3 }, 5);\n  queue.add({ id: 4 }, 5);\n  queue.add({ id: 5 }, 5);\n  queue.add({ id: 6 }, 5);\n  queue.add({ id: 7 }, 2);\n  queue.add({ id: 8 }, 2);\n  queue.add({ id: 9 }, 2);\n});\n\nmetatests.test('queue round robin with priority', (test) => {\n  const queue = metasync.queue(3).roundRobin().priority();\n  const res = [];\n\n  queue.process((item, callback) => {\n    process.nextTick(() => {\n      res.push(item.id);\n      callback();\n    });\n  });\n\n  queue.drain(() => {\n    test.strictSame(res, [1, 2, 3, 4, 8, 9, 7, 5, 6]);\n    test.end();\n  });\n\n  queue.add({ id: 1 }, 1, 0);\n  queue.add({ id: 2 }, 1, 0);\n  queue.add({ id: 3 }, 1, 10);\n  queue.add({ id: 4 }, 1, 20);\n  queue.add({ id: 5 }, 2, 0);\n  queue.add({ id: 6 }, 2, 0);\n  queue.add({ id: 7 }, 2, 10);\n  queue.add({ id: 8 }, 2, 20);\n  queue.add({ id: 9 }, 3, 0);\n});\n"
  },
  {
    "path": "test/queue.pipe.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('priority / pipe', (test) => {\n  const expectedResult = [2, 8, 6, 4];\n  const result = [];\n\n  const q1 = metasync\n    .queue(3)\n    .priority()\n    .process((item, cb) => {\n      setTimeout(cb, 50, item.id % 2 ? new Error('unexpected') : null, item);\n    });\n\n  const q2 = metasync\n    .queue(1)\n    .wait(100)\n    .timeout(200)\n    .priority()\n    .process((item, cb) => {\n      result.push(item.id);\n      setTimeout(cb, 90);\n    });\n\n  q1.pipe(q2);\n\n  q2.drain(() => {\n    test.strictSame(result, expectedResult);\n    test.end();\n  });\n\n  q1.add({ id: 1 }, 0);\n  q1.add({ id: 2 }, 0);\n  q1.add({ id: 3 }, 1);\n  q1.add({ id: 4 }, 0);\n  q1.add({ id: 5 }, 0);\n  q1.add({ id: 6 }, 10);\n  q1.add({ id: 7 }, 0);\n  q1.add({ id: 8 }, 100);\n  q1.add({ id: 9 }, 0);\n});\n"
  },
  {
    "path": "test/queue.priority.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('fifo / priority', (test) => {\n  const expectedResult = [1, 2, 3, 8, 6, 4, 5, 7, 9];\n  const result = [];\n\n  const q = metasync\n    .queue(3)\n    .priority()\n    .process((item, cb) => {\n      result.push(item.id);\n      setTimeout(cb, 100);\n    });\n\n  q.drain(() => {\n    test.strictSame(result, expectedResult);\n    test.end();\n  });\n\n  q.add({ id: 1 }, 0);\n  q.add({ id: 2 }, 0);\n  q.add({ id: 3 }, 1);\n  q.add({ id: 4 }, 0);\n  q.add({ id: 5 }, 0);\n  q.add({ id: 6 }, 10);\n  q.add({ id: 7 }, 0);\n  q.add({ id: 8 }, 100);\n  q.add({ id: 9 }, 0);\n});\n"
  },
  {
    "path": "test/queue.roundRobin.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('roundRobin', (test) => {\n  const expectedResult = [\n    1, 2, 3, 4, 5, 6, 7, 8, 20, 9, 21, 10, 22, 11, 23, 12, 13, 14, 15, 16, 17,\n    18, 19,\n  ];\n  const result = [];\n\n  const q = metasync\n    .queue(3)\n    .roundRobin()\n    .process((item, cb) => {\n      result.push(item.id);\n      setTimeout(cb, 100);\n    });\n\n  q.drain(() => {\n    test.strictSame(result, expectedResult);\n    test.end();\n  });\n  q.add({ id: 1 }, 1);\n  q.add({ id: 2 }, 2);\n  q.add({ id: 3 }, 3);\n  q.add({ id: 4 }, 4);\n  q.add({ id: 5 }, 1);\n  q.add({ id: 6 }, 2);\n  q.add({ id: 7 }, 3);\n  q.add({ id: 8 }, 4);\n  q.add({ id: 9 }, 2);\n  q.add({ id: 10 }, 2);\n  q.add({ id: 11 }, 2);\n  q.add({ id: 12 }, 2);\n  q.add({ id: 13 }, 2);\n  q.add({ id: 14 }, 2);\n  q.add({ id: 15 }, 2);\n  q.add({ id: 16 }, 2);\n  q.add({ id: 17 }, 2);\n  q.add({ id: 18 }, 2);\n  q.add({ id: 19 }, 2);\n  q.add({ id: 20 }, 1);\n  q.add({ id: 21 }, 1);\n  q.add({ id: 22 }, 1);\n  q.add({ id: 23 }, 1);\n});\n"
  },
  {
    "path": "test/throttle.js",
    "content": "'use strict';\n\nconst metasync = require('..');\nconst metatests = require('metatests');\n\nmetatests.test('throttle', (test) => {\n  let callCount = 0;\n\n  const fn = (arg1, arg2, ...otherArgs) => {\n    test.strictSame(arg1, 'someVal');\n    test.strictSame(arg2, 4);\n    test.strictSame(otherArgs, []);\n    callCount++;\n    if (callCount === 2) {\n      test.end();\n    }\n  };\n\n  const throttledFn = metasync.throttle(1, fn, 'someVal', 4);\n\n  throttledFn();\n  test.strictSame(callCount, 1);\n  throttledFn();\n  throttledFn();\n  test.strictSame(callCount, 1);\n});\n\nmetatests.test('throttle merge args', (test) => {\n  let callCount = 0;\n\n  const fn = (arg1, arg2, ...otherArgs) => {\n    test.strictSame(arg1, 'someVal');\n    test.strictSame(arg2, 4);\n    test.strictSame(otherArgs, ['str']);\n    callCount++;\n    if (callCount === 2) {\n      test.end();\n    }\n  };\n\n  const throttledFn = metasync.throttle(1, fn, 'someVal', 4);\n\n  throttledFn('str');\n  test.strictSame(callCount, 1);\n  throttledFn('str');\n  throttledFn('str');\n  test.strictSame(callCount, 1);\n});\n\nmetatests.test('throttle without arguments for function', (test) => {\n  let callCount = 0;\n\n  const fn = (...args) => {\n    test.strictSame(args, []);\n    callCount++;\n    if (callCount === 2) {\n      test.end();\n    }\n  };\n\n  const throttledFn = metasync.throttle(1, fn);\n\n  throttledFn();\n  test.strictSame(callCount, 1);\n  throttledFn();\n  throttledFn();\n  test.strictSame(callCount, 1);\n});\n\nmetatests.test('debounce', (test) => {\n  let count = 0;\n\n  const fn = (arg1, arg2, ...otherArgs) => {\n    test.strictSame(arg1, 'someVal');\n    test.strictSame(arg2, 4);\n    test.strictSame(otherArgs, []);\n    count++;\n    test.end();\n  };\n\n  const debouncedFn = metasync.debounce(1, fn, 'someVal', 4);\n\n  debouncedFn();\n  debouncedFn();\n  test.strictSame(count, 0);\n});\n\nmetatests.test('debounce without arguments for function', (test) => {\n  let count = 0;\n\n  const fn = (...args) => {\n    test.strictSame(args, []);\n    count++;\n    test.end();\n  };\n\n  const debouncedFn = metasync.debounce(1, fn);\n\n  debouncedFn();\n  debouncedFn();\n  test.strictSame(count, 0);\n});\n\nmetatests.test('timeout with sync function', (test) => {\n  const syncFn = (callback) => callback(null, 'someVal');\n  metasync.timeout(1, syncFn, (err, res, ...args) => {\n    test.error(err);\n    test.strictSame(res, 'someVal');\n    test.strictSame(args, []);\n    test.end();\n  });\n});\n\nmetatests.test('timeout', (test) => {\n  metasync.timeout(\n    10,\n    (callback) => {\n      setTimeout(() => {\n        callback(null, 'someVal');\n      }, 0);\n    },\n    (err, res, ...args) => {\n      test.error(err);\n      test.strictSame(res, 'someVal');\n      test.strictSame(args, []);\n      test.end();\n    },\n  );\n});\n"
  },
  {
    "path": "tests/async-iterator.js",
    "content": "'use strict';\n\nconst path = require('path');\n\nconst { between } = require('metautil');\n\nconst nodeVerion = between(process.version, 'v', '.');\nconst testFilePath = path.join(__dirname, './fixtures/iterator.js');\n\nif (nodeVerion >= 10) require(testFilePath);\n"
  },
  {
    "path": "tests/fixtures/iterator.js",
    "content": "'use strict';\n\nconst path = require('path');\nconst { fork } = require('child_process');\nconst { once } = require('events');\n\nconst metatests = require('metatests');\nconst { AsyncIterator, asyncIter } = require('../../');\n\nconst array = [1, 2, 3, 4];\n\nmetatests.test('new AsyncIterator() on non Iterable', (test) => {\n  test.throws(() => {\n    new AsyncIterator(2);\n  }, new TypeError('Base is not Iterable'));\n  test.end();\n});\n\nmetatests.test('AsyncIterator.throttle with min value', (test) => {\n  const expectedMin = 1;\n  const { min } = asyncIter([]).throttle(1, expectedMin);\n  test.strictSame(min, expectedMin);\n  test.end();\n});\n\nmetatests.test('new AsyncIterator() on AsyncIterable', (test) => {\n  const iterator = array[Symbol.iterator]();\n  const iterable = {\n    [Symbol.asyncIterator]: () => ({ next: async () => iterator.next() }),\n  };\n\n  const iter = asyncIter(iterable);\n  test.assert(iter instanceof AsyncIterator);\n  test.end();\n});\n\nmetatests.test('next returns Promise', (test) => {\n  const iter = asyncIter(array);\n  const item = iter.next();\n\n  test.assert(item instanceof Promise);\n  test.end();\n});\n\nmetatests.test('iter returns an AsyncIterator', (test) => {\n  const iterator = asyncIter(array);\n  test.assert(iterator instanceof AsyncIterator);\n  test.end();\n});\n\nmetatests.test('AsyncIterator is Iterable', async (test) => {\n  const iterator = asyncIter(array);\n  let sum = 0;\n  for await (const value of iterator) {\n    sum += value;\n  }\n\n  test.strictSame(sum, 10);\n  test.end();\n});\n\nmetatests.test('AsyncIterator.count', async (test) => {\n  test.strictSame(await asyncIter(array).count(), array.length);\n  test.end();\n});\n\nmetatests.test('AsyncIterator.count on consumed iterator', async (test) => {\n  const count = await asyncIter(array).skip(array.length).count();\n  test.strictSame(count, 0);\n  test.end();\n});\n\nmetatests.test('AsyncIterator.each', async (test) => {\n  const iterator = asyncIter(array);\n  let sum = 0;\n  await iterator.each((value) => {\n    sum += value;\n  });\n\n  test.strictSame(sum, 10);\n  test.end();\n});\n\nmetatests.test('AsyncIterator.forEach', async (test) => {\n  const iterator = asyncIter(array);\n  let sum = 0;\n  await iterator.forEach((value) => {\n    sum += value;\n  });\n\n  test.strictSame(sum, 10);\n  test.end();\n});\n\nmetatests.test('AsyncIterator.parallel', async (test) => {\n  const iterator = asyncIter(array);\n  let sum = 0;\n  await iterator.parallel((value) => {\n    sum += value;\n  });\n\n  test.strictSame(sum, 10);\n  test.end();\n});\n\nmetatests.test('AsyncIterator.forEach with thisArg ', async (test) => {\n  const iterator = asyncIter(array);\n  const obj = {\n    sum: 0,\n    fn(value) {\n      this.sum += value;\n    },\n  };\n\n  await iterator.forEach(obj.fn, obj);\n\n  test.strictSame(obj.sum, 10);\n  test.end();\n});\n\nmetatests.test('AsyncIterator.reduce', async (test) => {\n  test.strictSame(\n    await asyncIter(array).reduce((acc, current) => acc + current, 0),\n    10,\n  );\n  test.end();\n});\n\nmetatests.test('AsyncIterator.reduce with no initialValue', async (test) => {\n  test.strictSame(\n    await asyncIter(array).reduce((acc, current) => acc + current),\n    10,\n  );\n  test.end();\n});\n\nmetatests.test(\n  'AsyncIterator.reduce with no initialValue on consumed iterator',\n  async (test) => {\n    const iterator = asyncIter(array);\n    await test.rejects(\n      iterator\n        .reduce(() => {})\n        .then(() => iterator.reduce((acc, current) => acc + current)),\n      new TypeError('Reduce of consumed async iterator with no initial value'),\n    );\n  },\n);\n\nmetatests.test('AsyncIterator.map', async (test) => {\n  test.strictSame(\n    await asyncIter(array)\n      .map((value) => value * 2)\n      .toArray(),\n    [2, 4, 6, 8],\n  );\n  test.end();\n});\n\nmetatests.test('AsyncIterator.map with thisArg', async (test) => {\n  const obj = {\n    multiplier: 2,\n    mapper(value) {\n      return value * this.multiplier;\n    },\n  };\n\n  test.strictSame(\n    await asyncIter(array).map(obj.mapper, obj).toArray(),\n    [2, 4, 6, 8],\n  );\n  test.end();\n});\n\nmetatests.test('AsyncIterator.filter', async (test) => {\n  test.strictSame(\n    await asyncIter(array)\n      .filter((value) => !(value % 2))\n      .toArray(),\n    [2, 4],\n  );\n  test.end();\n});\n\nmetatests.test('AsyncIterator.filter with thisArg', async (test) => {\n  const obj = {\n    divider: 2,\n    predicate(value) {\n      return !(value % this.divider);\n    },\n  };\n\n  test.strictSame(\n    await asyncIter(array).filter(obj.predicate, obj).toArray(),\n    [2, 4],\n  );\n  test.end();\n});\n\nmetatests.test('AsyncIterator.flat', async (test) => {\n  const array = [[[[1], 2], 3], 4];\n  const flatArray = [1, 2, 3, 4];\n  const newArray = await asyncIter(array).flat(3).toArray();\n  test.strictSame(newArray, flatArray);\n  test.end();\n});\n\nmetatests.test('AsyncIterator.flat with no depth', async (test) => {\n  const array = [[[[1], 2], 3], 4];\n  const flatArray = [[[1], 2], 3, 4];\n  const newArray = await asyncIter(array).flat().toArray();\n  test.strictSame(newArray, flatArray);\n  test.end();\n});\n\nmetatests.test('AsyncIterator.flatMap', async (test) => {\n  const array = [1, 2, 3];\n  const result = [1, 1, 2, 2, 3, 3];\n  const newArray = await asyncIter(array)\n    .flatMap((item) => [item, item])\n    .toArray();\n\n  test.strictSame(newArray, result);\n  test.end();\n});\n\nmetatests.test(\n  'AsyncIterator.flatMap that returns neither AsyncIterator nor Iterable',\n  async (test) => {\n    const array = [1, 2, 3];\n    const result = [2, 4, 6];\n    const newArray = await asyncIter(array)\n      .flatMap((item) => item * 2)\n      .toArray();\n\n    test.strictSame(newArray, result);\n    test.end();\n  },\n);\n\nmetatests.test('AsyncIterator.flatMap with thisArg', async (test) => {\n  const obj = {\n    value: 1,\n    mapper(item) {\n      return [item, this.value];\n    },\n  };\n\n  const array = [1, 2, 3];\n  const result = [1, 1, 2, 1, 3, 1];\n  test.strictSame(\n    await asyncIter(array).flatMap(obj.mapper, obj).toArray(),\n    result,\n  );\n  test.end();\n});\n\nmetatests.test('AsyncIterator.zip', async (test) => {\n  const it = asyncIter(array);\n  const itr = asyncIter(array).take(3);\n  const iterator = asyncIter(array).take(2);\n\n  const zipIter = it.zip(itr, iterator);\n  test.strictSame(await zipIter.toArray(), [\n    [1, 1, 1],\n    [2, 2, 2],\n  ]);\n  test.end();\n});\n\nmetatests.test('AsyncIterator.chain', async (test) => {\n  const it = asyncIter(array).take(1);\n  const itr = await asyncIter(array).skip(1).take(1);\n  const iterator = await asyncIter(array).skip(2).take(2);\n  test.strictSame(await it.chain(itr, iterator).toArray(), [1, 2, 3, 4]);\n  test.end();\n});\n\nmetatests.test('AsyncIterator.take', async (test) => {\n  const it = asyncIter(array).take(2);\n  test.strictSame((await it.next()).value, 1);\n  test.strictSame((await it.next()).value, 2);\n  test.assert((await it.next()).done);\n  test.end();\n});\n\nmetatests.testSync('AsyncIterator.takeWhile', async (test) => {\n  const it = asyncIter(array).takeWhile((x) => x < 3);\n  test.strictSame(await it.toArray(), [1, 2]);\n  test.assert(it.next().done);\n});\n\nmetatests.test('AsyncIterator.skip', async (test) => {\n  const it = asyncIter(array).skip(2);\n  test.strictSame((await it.next()).value, 3);\n  test.strictSame((await it.next()).value, 4);\n  test.assert((await it.next()).done);\n  test.end();\n});\n\nmetatests.test('AsyncIterator.every that must return true', async (test) => {\n  test.assert(await asyncIter(array).every((item) => item > 0));\n  test.end();\n});\n\nmetatests.test('AsyncIterator.every that must return false', async (test) => {\n  test.assertNot(await asyncIter(array).every((item) => item % 2));\n  test.end();\n});\n\nmetatests.test('AsyncIterator.every with thisArg', async (test) => {\n  const obj = {\n    min: 0,\n    predicate(value) {\n      return value > this.min;\n    },\n  };\n\n  test.assert(await asyncIter(array).every(obj.predicate, obj));\n  test.end();\n});\n\nmetatests.test('AsyncIterator.some that must return true', async (test) => {\n  test.assert(await asyncIter(array).some((item) => item % 2));\n  test.end();\n});\n\nmetatests.test('AsyncIterator.some that must return false', async (test) => {\n  test.assertNot(await asyncIter(array).some((item) => item < 0));\n  test.end();\n});\n\nmetatests.test('AsyncIterator.some with thisArg', async (test) => {\n  const obj = {\n    max: 2,\n    predicate(value) {\n      return value < this.max;\n    },\n  };\n\n  test.assert(await asyncIter(array).some(obj.predicate, obj));\n  test.end();\n});\n\nmetatests.testSync(\n  'AsyncIterator.someCount that must return true',\n  async (test) => {\n    test.assert(await asyncIter(array).someCount((item) => item % 2, 2));\n  },\n);\n\nmetatests.testSync(\n  'AsyncIterator.someCount that must return false',\n  async (test) => {\n    test.assertNot(await asyncIter(array).someCount((item) => item % 2, 3));\n    test.assertNot(await asyncIter(array).someCount((item) => item < 0, 1));\n  },\n);\n\nmetatests.testSync('AsyncIterator.someCount with thisArg', async (test) => {\n  const obj = {\n    max: 3,\n    predicate(value) {\n      return value < this.max;\n    },\n  };\n\n  test.assert(await asyncIter(array).someCount(obj.predicate, 2, obj));\n});\n\nmetatests.test('AsyncIterator.find that must find an element', async (test) => {\n  test.strictSame(await asyncIter(array).find((item) => item % 2 === 0), 2);\n  test.end();\n});\n\nmetatests.test(\n  'AsyncIterator.find that must not find an element',\n  async (test) => {\n    test.strictSame(await asyncIter(array).find((item) => item > 4), undefined);\n    test.end();\n  },\n);\n\nmetatests.test('AsyncIterator.find with thisArg', async (test) => {\n  const obj = {\n    divider: 2,\n    predicate(value) {\n      return value % this.divider === 0;\n    },\n  };\n\n  test.strictSame(await asyncIter(array).find(obj.predicate, obj), 2);\n  test.end();\n});\n\nmetatests.test('AsyncIterator.includes that must return true', async (test) => {\n  test.assert(await asyncIter(array).includes(1));\n  test.end();\n});\n\nmetatests.test('AsyncIterator.includes with a NaN', async (test) => {\n  test.assert(await asyncIter([1, 2, NaN]).includes(NaN));\n  test.end();\n});\n\nmetatests.test('AsyncIterator.includes must return false', async (test) => {\n  test.assertNot(await asyncIter(array).includes(0));\n  test.end();\n});\n\nmetatests.test(\n  'AsyncIterator.collectTo must collect to given Collection',\n  async (test) => {\n    const set = await asyncIter(array).collectTo(Set);\n    test.strictSame([...set.values()], array);\n    test.end();\n  },\n);\n\nmetatests.test('AsyncIterator.toArray must convert to array', async (test) => {\n  test.strictSame(await asyncIter(array).toArray(), array);\n  test.end();\n});\n\nmetatests.test(\n  'AsyncIterator.collectWith must collect to a provided object',\n  async (test) => {\n    const set = new Set();\n    await asyncIter(array).collectWith(set, (obj, item) => obj.add(item));\n    test.strictSame([...set.values()], array);\n    test.end();\n  },\n);\n\nmetatests.test('AsyncIterator.throttle', async (test) => {\n  const pathThrottleFile = path.join(__dirname, './throttle.js');\n  const child = fork(pathThrottleFile);\n\n  const [{ sum, ARRAY_SIZE }] = await once(child, 'message');\n  test.strictSame(sum, ARRAY_SIZE);\n});\n\nmetatests.testSync(\n  'AsyncIterator.enumerate must return tuples',\n  async (test) => {\n    let i = 0;\n    await asyncIter(array)\n      .enumerate()\n      .forEach((t) => {\n        test.strictSame(t, [i, array[i]]);\n        i++;\n      });\n  },\n);\n\nmetatests.testSync(\n  'AsyncIterator.enumerate must start from 0',\n  async (test) => {\n    const it = asyncIter(array);\n    await it.next();\n    let i = 0;\n    await it.enumerate().forEach((t) => {\n      test.strictSame(t, [i, array[i + 1]]);\n      i++;\n    });\n  },\n);\n\nmetatests.testSync('AsyncIterator.join default', async (test) => {\n  const actual = await asyncIter(array).join();\n  test.strictSame(actual, '1,2,3,4');\n});\n\nmetatests.testSync('AsyncIterator.join', async (test) => {\n  const actual = await asyncIter(array).join(', ');\n  test.strictSame(actual, '1, 2, 3, 4');\n});\n\nmetatests.testSync('AsyncIterator.join with prefix', async (test) => {\n  const actual = await asyncIter(array).join(', ', 'a = ');\n  test.strictSame(actual, 'a = 1, 2, 3, 4');\n});\n\nmetatests.testSync('AsyncIterator.join with suffix', async (test) => {\n  const actual = await asyncIter(array).join(', ', '', ' => 10');\n  test.strictSame(actual, '1, 2, 3, 4 => 10');\n});\n\nmetatests.testSync(\n  'AsyncIterator.join with prefix and suffix',\n  async (test) => {\n    const actual = await asyncIter(array).join(', ', '[', ']');\n    test.strictSame(actual, '[1, 2, 3, 4]');\n  },\n);\n"
  },
  {
    "path": "tests/fixtures/throttle.js",
    "content": "'use strict';\n\nconst { asyncIter } = require('../../');\n\nconst doSmth = (time) => {\n  const begin = Date.now();\n  while (Date.now() - begin < time);\n};\n\nconst ARRAY_SIZE = 1000;\nconst TIMER_TIME = 10;\nconst ITEM_TIME = 1;\nconst EXPECTED_PERCENT = 0.7;\n\nlet sum = 0;\nconst arr = new Array(ARRAY_SIZE).fill(1);\n\nconst iter = asyncIter(arr)\n  .map((number) => {\n    doSmth(ITEM_TIME);\n    sum += number;\n  })\n  .throttle(EXPECTED_PERCENT);\n\nconst timer = setInterval(() => doSmth(TIMER_TIME), 0);\n\n(async () => {\n  const begin = Date.now();\n  await iter.toArray();\n  const allTime = Date.now() - begin;\n\n  clearInterval(timer);\n\n  const mapTime = ARRAY_SIZE * ITEM_TIME;\n  const actualPercent = mapTime / allTime;\n\n  const actualDeviation = Math.abs(actualPercent - EXPECTED_PERCENT);\n  process.send({ actualDeviation, sum, ARRAY_SIZE });\n})();\n"
  },
  {
    "path": "tests/load/benchmark.js",
    "content": "'use strict';\n\nconst benchmark = {};\nmodule.exports = benchmark;\n\nconst rpad = (s, char, count) => s + char.repeat(count - s.length);\nconst lpad = (s, char, count) => char.repeat(count - s.length) + s;\n\nbenchmark.do = (count, tests) => {\n  let fn;\n  let i = 0;\n  const testCount = tests.length;\n\n  const nextTest = () => {\n    i++;\n    fn = tests.shift();\n    const result = [];\n    const begin = process.hrtime();\n    let j = 0;\n\n    const nextRepeat = () => {\n      fn((err, res) => {\n        if (err) {\n          console.error(err);\n        }\n        j++;\n        result.push(res);\n        if (j < count) {\n          nextRepeat();\n        } else {\n          const end = process.hrtime(begin);\n          const diff = end[0] * 1e9 + end[1];\n          const time = lpad(diff.toString(), '.', 15);\n          const name = rpad(fn.name, '.', 25);\n          console.log(name + time + ' nanoseconds');\n          if (i < testCount) nextTest();\n        }\n      });\n    };\n\n    nextRepeat();\n  };\n\n  nextTest();\n};\n"
  },
  {
    "path": "tests/load/collect.class.js",
    "content": "'use strict';\n\nconst COUNT = 1000000;\n\nconst benchmark = require('./benchmark.js');\nconst metasync = require('../../lib/collector.class.js');\n\nconst CollectClass = (done) => {\n  const dc = metasync.collect(6);\n  dc.done(done);\n  let i = 0;\n  setImmediate(() => dc.pick('uno', ++i * 2));\n  setImmediate(() => dc.pick('due', ++i * 3));\n  setImmediate(() => dc.pick('tre', ++i * 5));\n  setImmediate(() => dc.pick('4th', 'key' + ++i));\n  setImmediate(() => dc.pick('5th', ++i === 5));\n  setImmediate(() => dc.pick('6th', 'key' + ++i * 2));\n};\n\nbenchmark.do(COUNT, [CollectClass]);\n"
  },
  {
    "path": "tests/load/collect.functor.js",
    "content": "'use strict';\n\nconst COUNT = 1000000;\n\nconst benchmark = require('./benchmark.js');\nconst metasync = require('../../lib/collector.functor.js');\n\nconst CollectFunctor = (done) => {\n  const dc = metasync.collect(6);\n  dc.done(done);\n  let i = 0;\n  setImmediate(() => dc.pick('uno', ++i * 2));\n  setImmediate(() => dc.pick('due', ++i * 3));\n  setImmediate(() => dc.pick('tre', ++i * 5));\n  setImmediate(() => dc.pick('4th', 'key' + ++i));\n  setImmediate(() => dc.pick('5th', ++i === 5));\n  setImmediate(() => dc.pick('6th', 'key' + ++i * 2));\n};\n\nbenchmark.do(COUNT, [CollectFunctor]);\n"
  },
  {
    "path": "tests/load/collect.js",
    "content": "'use strict';\n\nconst COUNT = 1000000;\n\nconst benchmark = require('./benchmark.js');\nconst metasync = require('../../lib/collector.js');\n\nconst CollectPrototype = (done) => {\n  const dc = metasync.collect(6);\n  dc.done(done);\n  let i = 0;\n  setImmediate(() => dc.pick('uno', ++i * 2));\n  setImmediate(() => dc.pick('due', ++i * 3));\n  setImmediate(() => dc.pick('tre', ++i * 5));\n  setImmediate(() => dc.pick('4th', 'key' + ++i));\n  setImmediate(() => dc.pick('5th', ++i === 5));\n  setImmediate(() => dc.pick('6th', 'key' + ++i * 2));\n};\n\nbenchmark.do(COUNT, [CollectPrototype]);\n"
  },
  {
    "path": "tests/load/collect.prototype.js",
    "content": "'use strict';\n\nconst COUNT = 1000000;\n\nconst benchmark = require('./benchmark.js');\nconst metasync = require('../../lib/collector.prototype.js');\n\nconst CollectOldPrototype = (done) => {\n  const dc = new metasync.DataCollector(6);\n  dc.on('done', done);\n  let i = 0;\n  setImmediate(() => dc.collect('uno', ++i * 2));\n  setImmediate(() => dc.collect('due', ++i * 3));\n  setImmediate(() => dc.collect('tre', ++i * 5));\n  setImmediate(() => dc.collect('4th', 'key' + ++i));\n  setImmediate(() => dc.collect('5th', ++i === 5));\n  setImmediate(() => dc.collect('6th', 'key' + ++i * 2));\n};\n\nbenchmark.do(COUNT, [CollectOldPrototype]);\n"
  },
  {
    "path": "tests/load/parallel.collect.js",
    "content": "'use strict';\n\nconst COUNT = 1000000;\n\nconst benchmark = require('./benchmark.js');\nconst metasync = require('../..');\n\nconst Collect = (done) => {\n  const dc = metasync.collect(6);\n  dc.done(done);\n  let i = 0;\n  setImmediate(() => dc.pick('uno', ++i * 2));\n  setImmediate(() => dc.pick('due', ++i * 3));\n  setImmediate(() => dc.pick('tre', ++i * 5));\n  setImmediate(() => dc.pick('4th', 'key' + ++i));\n  setImmediate(() => dc.pick('5th', ++i === 5));\n  setImmediate(() => dc.pick('6th', 'key' + ++i * 2));\n};\n\nbenchmark.do(COUNT, [Collect]);\n"
  },
  {
    "path": "tests/load/parallel.compose.js",
    "content": "'use strict';\n\nconst COUNT = 1000000;\n\nconst benchmark = require('./benchmark.js');\nconst metasync = require('../..');\n\nconst testCompose = (done) => {\n  let i = 0;\n  const p1 = (context, callback) => {\n    setImmediate(() => callback(null, ++i * 2));\n  };\n  const p2 = (context, callback) => {\n    setImmediate(() => callback(null, ++i * 3));\n  };\n  const p3 = (context, callback) => {\n    setImmediate(() => callback(null, ++i * 5));\n  };\n  const p4 = (context, callback) => {\n    setImmediate(() => callback(null, 'key ' + ++i));\n  };\n  const p5 = (context, callback) => {\n    setImmediate(() => callback(null, ++i === 5));\n  };\n  const p6 = (context, callback) => {\n    setImmediate(() => callback(null, 'key' + ++i * 2));\n  };\n\n  const f1 = metasync([[p1, p2, p3, p4, p5, p6]]);\n  f1(done);\n};\n\nbenchmark.do(COUNT, [testCompose]);\n"
  },
  {
    "path": "tests/load/parallel.promise.js",
    "content": "'use strict';\n\nconst COUNT = 1000000;\n\nconst benchmark = require('./benchmark.js');\n\nconst PromiseAll = (done) => {\n  let i = 0;\n  const p1 = new Promise((resolve) => {\n    setImmediate(() => resolve({ p1: ++i * 2 }));\n  });\n  const p2 = new Promise((resolve) => {\n    setImmediate(() => resolve({ p2: ++i * 3 }));\n  });\n  const p3 = new Promise((resolve) => {\n    setImmediate(() => resolve({ p3: ++i * 5 }));\n  });\n  const p4 = new Promise((resolve) => {\n    setImmediate(() => resolve({ p4: 'key ' + ++i }));\n  });\n  const p5 = new Promise((resolve) => {\n    setImmediate(() => resolve({ p5: ++i === 5 }));\n  });\n  const p6 = new Promise((resolve) => {\n    setImmediate(() => resolve({ p6: 'key' + ++i * 2 }));\n  });\n\n  Promise.all([p1, p2, p3, p4, p5, p6]).then((res) => done(null, res));\n};\n\nbenchmark.do(COUNT, [PromiseAll]);\n"
  },
  {
    "path": "tests/load/poolify.array.js",
    "content": "'use strict';\n\nconst COUNT = 10000;\nconst GETS = 300;\n\nconst benchmark = require('./benchmark.js');\nconst metasync = require('../../lib/poolify.js');\n\nconst poolifyArray = (done) => {\n  const buffer = () => new Uint32Array(128);\n  const pool = metasync.poolify(buffer, 10, 100, 200);\n\n  for (let i = 0; i < GETS; i++) {\n    pool((item) => {\n      setImmediate(() => {\n        pool([item]);\n        if (i === GETS - 1) done();\n      });\n    });\n  }\n};\n\nbenchmark.do(COUNT, [poolifyArray]);\n"
  },
  {
    "path": "tests/load/poolify.opt.js",
    "content": "'use strict';\n\nconst COUNT = 10000;\nconst GETS = 300;\n\nconst benchmark = require('./benchmark.js');\nconst metasync = require('../../lib/poolify.opt.js');\n\nconst poolifyNoMixin = (done) => {\n  const buffer = () => new Uint32Array(128);\n  const pool = metasync.poolify(buffer, 10, 100, 200);\n\n  for (let i = 0; i < GETS; i++) {\n    pool((item) => {\n      setImmediate(() => {\n        pool([item]);\n        if (i === GETS - 1) done();\n      });\n    });\n  }\n};\n\nbenchmark.do(COUNT, [poolifyNoMixin]);\n"
  },
  {
    "path": "tests/load/poolify.symbol.js",
    "content": "'use strict';\n\nconst COUNT = 10000;\nconst GETS = 300;\n\nconst benchmark = require('./benchmark.js');\nconst metasync = require('../../lib/poolify.symbol.js');\n\nconst poolifySymbol = (done) => {\n  const buffer = () => new Uint32Array(128);\n  const pool = metasync.poolify(buffer, 10, 100, 200);\n\n  for (let i = 0; i < GETS; i++) {\n    pool((item) => {\n      setImmediate(() => {\n        pool(item);\n        if (i === GETS - 1) done();\n      });\n    });\n  }\n};\n\nbenchmark.do(COUNT, [poolifySymbol]);\n"
  },
  {
    "path": "tests/load/run.sh",
    "content": "echo Parallel execution: concurrency 6 x 1mln\nnode tests/load/parallel.promise.js\nnode tests/load/parallel.compose.js\nnode tests/load/parallel.collect.js\necho\necho Sequential execution: concurrency 6 x 100k\nnode tests/load/sequential.promise.js\nnode tests/load/sequential.compose.js\necho\necho Poolify: array vs symbol 300 times\nnode tests/load/poolify.array.js\nnode tests/load/poolify.symbol.js\nnode tests/load/poolify.opt.js\necho\necho Collector: 1mnl\nnode tests/load/collect.js\nnode tests/load/collect.class.js\nnode tests/load/collect.prototype.js\nnode tests/load/collect.functor.js\n"
  },
  {
    "path": "tests/load/sequential.compose.js",
    "content": "'use strict';\n\nconst count = 100000;\n\nconst benchmark = require('./benchmark.js');\nconst metasync = require('../..');\n\nconst composeSequential = (done) => {\n  let i = 0;\n  const p1 = (context, callback) => {\n    setImmediate(() => callback(null, ++i * 2));\n  };\n  const p2 = (context, callback) => {\n    setImmediate(() => callback(null, ++i * 3));\n  };\n  const p3 = (context, callback) => {\n    setImmediate(() => callback(null, ++i * 5));\n  };\n  const p4 = (context, callback) => {\n    setImmediate(() => callback(null, 'key ' + ++i));\n  };\n  const p5 = (context, callback) => {\n    setImmediate(() => callback(null, ++i === 5));\n  };\n  const p6 = (context, callback) => {\n    setImmediate(() => callback(null, 'key' + ++i * 2));\n  };\n\n  const f1 = metasync([p1, p2, p3, p4, p5, p6]);\n  f1(done);\n};\n\nbenchmark.do(count, [composeSequential]);\n"
  },
  {
    "path": "tests/load/sequential.promise.js",
    "content": "'use strict';\n\nconst count = 100000;\n\nconst benchmark = require('./benchmark.js');\n\nconst PromiseThen = (done) => {\n  let i = 0;\n  const p1 = new Promise((resolve) => {\n    setImmediate(() => resolve({ p1: ++i * 2 }));\n  });\n  const p2 = new Promise((resolve) => {\n    setImmediate(() => resolve({ p2: ++i * 3 }));\n  });\n  const p3 = new Promise((resolve) => {\n    setImmediate(() => resolve({ p3: ++i * 5 }));\n  });\n  const p4 = new Promise((resolve) => {\n    setImmediate(() => resolve({ p4: 'key ' + ++i }));\n  });\n  const p5 = new Promise((resolve) => {\n    setImmediate(() => resolve({ p5: ++i === 5 }));\n  });\n  const p6 = new Promise((resolve) => {\n    setImmediate(() => resolve({ p6: 'key' + ++i * 2 }));\n  });\n  Promise.resolve()\n    .then(p1)\n    .then(p2)\n    .then(p3)\n    .then(p4)\n    .then(p5)\n    .then(p6)\n    .then((res) => done(null, res))\n    .catch(console.error);\n};\n\nbenchmark.do(count, [PromiseThen]);\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"moduleResolution\": \"node\",\n    \"strict\": true,\n    \"noEmit\": true,\n    \"baseUrl\": \".\",\n    \"preserveWatchOutput\": true\n  },\n  \"include\": [\"*.d.ts\"]\n}\n"
  }
]