[
  {
    "path": ".circleci/config.yml",
    "content": "# Javascript Node CircleCI 2.0 configuration file\n#\n# Check https://circleci.com/docs/2.0/language-javascript/ for more details\n#\nversion: 2\njobs:\n  build:\n    docker:\n      # specify the version you desire here\n      - image: cimg/node:12.22\n\n      # Specify service dependencies here if necessary\n      # CircleCI maintains a library of pre-built images\n      # documented at https://circleci.com/docs/2.0/circleci-images/\n      # - image: circleci/mongo:3.4.4\n\n    working_directory: ~/repo\n\n    steps:\n      - checkout\n\n      # Download and cache dependencies\n      - restore_cache:\n          keys:\n          - v1-dependencies-{{ checksum \"package-lock.json\" }}\n          # fallback to using the latest cache if no exact match is found\n          - v1-dependencies-\n\n      - run: npm install\n\n      - save_cache:\n          paths:\n            - node_modules\n          key: v1-dependencies-{{ checksum \"package-lock.json\" }}\n\n      # run tests!\n      - run: npm test\n\n      # apidoc generation can easily fail -- check it.\n      - run: npm run docgen\n\n      # check for bad links in the apidocs\n      - run: sh -c \"! grep -r \\\"\\[\\[\\w\\\" apidoc/\"\n"
  },
  {
    "path": ".gitignore",
    "content": "dist/\nnode_modules/\napidoc/\nnpm-debug.log\ntests/apidoc-*\nyarn.lock\n"
  },
  {
    "path": ".npmignore",
    "content": "# Required so that built files are included when using this github repo directly as an npm dependency\n#\n# See https://stackoverflow.com/questions/40528053/npm-install-and-build-of-forked-github-repo/57829251#57829251\n# for more details."
  },
  {
    "path": "LICENSE.TXT",
    "content": "Copyright 2017 Emmanuel Touzery\n\nPermission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# prelude-ts\n\n[![NPM version][npm-image]][npm-url]\n[![Tests][circleci-image]][circleci-url]\n[![apidoc][apidoc-image]][apidoc-url]\n\n## Intro\n\nprelude-ts (previously prelude.ts) is a TypeScript library which aims to make functional programming\nconcepts accessible and productive in TypeScript. Note that even though it's\nwritten in TypeScript, it's perfectly usable from JavaScript (including ES5)!\n\nIt provides [persistent](https://en.wikipedia.org/wiki/Persistent_data_structure)\nimmutable collections (Vector, Set, Map, Stream), and constructs such as Option,\nEither, Predicate and Future.\n\n```typescript\nVector.of(1,2,3)\n  .map(x => x*2)\n  .head()\n// => Option.of(2)\n\nOption.sequence(\n  Vector.of(Option.of(1), Option.of(2)))\n// => Option.of(Vector.of(1,2))\n\nVector.of(1,2,3,4).groupBy(x => x%2)\n// => HashMap.of([0, Vector.of(2,4)],[1, Vector.of(1,3)])\n\nVector.of(1,2,3).zip(\"a\", \"b\", \"c\").takeWhile(([k,v]) => k<3)\n// Vector.of([1,\"a\"],[2,\"b\"])\n\nHashMap.of([\"a\",1],[\"b\",2]).get(\"a\")\n// Option.of(1)\n```\n\nThe collections are also JavaScript iterables, so if you have an ES6 runtime,\nyou can use the `for .. of` construct on them. If you're not familiar with\nimmutable collections, `list.append(newItem)` keeps `list` unchanged; `append()`\nreturns a new list. Immutability helps reasoning about code.\n\nYou can check the **[User Guide](https://github.com/emmanueltouzery/prelude-ts/wiki/Prelude%E2%88%92ts-user-guide)**,\nand browse the **[API documentation](http://emmanueltouzery.github.io/prelude.ts/latest/apidoc/globals.html)**,\nor our **[blog](http://emmanueltouzery.github.io/blog/tags/prelude.ts.html)**.\nNote that the constructors are private, and you should use static methods to build\nitems — for instance: `Option.of`, `Vector.of`, `Vector.ofIterable`, and so on.\n\n`HashSet` and `HashMap` are implemented using the\n[HAMT algorithm](http://en.wikipedia.org/wiki/Hash_array_mapped_trie),\nand concretely the [hamt_plus library](https://www.npmjs.com/package/hamt_plus).\n`Vector` is implemented through a\n[bit-mapped vector trie](http://hypirion.com/musings/understanding-persistent-vector-pt-1)\nand concretely the [list library](https://github.com/funkia/list/), as of 0.7.7.\nIn addition, the library is written in idiomatic JavaScript style, with loops\ninstead of recursion, so the performance should be good\n([see benchmarks here comparing to immutable.js and more](https://github.com/emmanueltouzery/prelude-ts/wiki/Benchmarks)).\n`list` and `hamt_plus` are the two only dependencies of prelude-ts.\n\n## Set, Map and equality\n\nJavaScript doesn't have structural equality, except for primitive types.\nSo `1 === 1` is true, but `[1] === [1]` is not, and neither is `{a:1} === {a:1}`.\nThis poses problems for collections, because if you have a `Set`, you don't\nwant duplicate elements because of this limited definition of equality.\n\nFor that reason, prelude-ts encourages you to define for your non-primitive types\nmethods `equals(other: any): boolean` and `hashCode(): number` (the same\nmethods that [immutable.js uses](https://immutable-js.github.io/immutable-js/docs/#/ValueObject)).\nWith these methods, structural equality is achievable, and indeed\n`Vector.of(1,2,3).equals(Vector.of(1,2,3))` is `true`. However this can only\nwork if the values you put in collections have themselves properly defined equality\n([see how prelude-ts can help](https://github.com/emmanueltouzery/prelude-ts/wiki/Equality)).\nIf these values don't have structural equality, then we can get no better than\n`===` behavior.\n\nprelude-ts attempts to assist the programmer with this; it tries to encourage\nthe developer to do the right thing. It'll refuse types without obviously properly\ndefined equality in Sets and in Maps keys, so `HashSet.of([1])`,\nor `Vector.of([1]).equals(Vector.of([2]))` will not compile.\nFor both of these, you get (a longer version of) this message:\n\n    Type 'number[]' is not assignable to type 'HasEquals'.\n      Property 'equals' is missing in type 'number[]'.\n\nSee the [User Guide](https://github.com/emmanueltouzery/prelude-ts/wiki/Prelude%E2%88%92ts-user-guide#equality)\nfor more details.\n\n## Installation\n\nTypeScript must know about `Iterable`, an ES6 feature (but present in most browsers)\nto compile prelude-ts. If you use TypeScript and target ES5, a minimum change to your tsconfig.json\ncould be to add:\n\n```json\n\"lib\": [\"DOM\", \"ES5\", \"ScriptHost\", \"es2015.iterable\"]\n```\n\n(compared to the default ES5 settings it only adds 'es2015.iterable')\n\n### Using in Node.js\n\nJust add the dependency in your `package.json` and start using it (like\n`import { Vector } from \"prelude-ts\";`, or `const { Vector } = require(\"prelude-ts\");`\nif you use commonjs).\nEverything should work, including type-checking if you use TypeScript. prelude-ts also provides\npretty-printing in the node REPL.\n\n### Using in the browser\n\nAdd the dependency in your `package.json`; TypeScript should automatically\nregister the type definitions.\n\nThe npm package contains the files `dist/src/prelude_ts.js` and `dist/src/prelude_ts.min.js`,\nwhich are UMD bundles; they work with other module systems and set `prelude_ts`\nas a window global if no module system is found. Include the relevant one in your\nindex.html in script tags:\n\n```html\n<script src=\"node_modules/prelude-ts/dist/src/prelude_ts.min.js\"></script>\n```\n\nYou shouldn't have an issue to import prelude-ts in your application, but if you use\nmodules it gets a little more complicated. One solution if you use them is to create\nan `imports.d.ts` file with the following contents:\n\n```typescript\n// https://github.com/Microsoft/TypeScript/issues/3180#issuecomment-283007750\nimport * as _P from 'prelude-ts';\nexport as namespace prelude_ts;\nexport = _P;\n```\n\nThen in a `.ts` file of your application, outside of a module, you can do:\n\n```typescript\nimport Vector = prelude_ts.Vector;\n```\n\n\\- to get values without the namespace.\n\nFinally, if you also include `dist/src/chrome_dev_tools_formatters.js` through\na `script` tag, and [enable Chrome custom formatters](http://bit.ly/object-formatters),\nthen you can get\n[a nice display of prelude-ts values in the Chrome debugger](https://raw.githubusercontent.com/wiki/emmanueltouzery/prelude-ts/chrome_formatters.png).\n\n## Wishlist/upcoming features\n\n* CharSeq, a string wrapper?\n* Non-empty vector? (already have [non-empty linkedlist](http://emmanueltouzery.github.io/prelude.ts/latest/apidoc/classes/linkedlist.conslinkedlist.html))\n* Make use of trampolining or a similar technique in `Stream` to avoid stack overflow exceptions on very large streams\n* More functions on existing classes\n\n## Out of scope for prelude-ts\n\n* Free monads\n* Monad transformers\n* Effect tracking\n* Higher-kinded types simulation\n\nI think these concepts are not expressible in a good enough manner in a language\nsuch as TypeScript.\n\n## Alternatives and Influences\n\n* [monet.js](https://monet.github.io/monet.js/) -- only has the `List` and\n  `Option` collections, implemented in functional-style ES5. The implementation,\n  using recursion, means its list type is noticeably slower than prelude-ts's.\n* [immutable.js](https://immutable-js.github.io/immutable-js/) -- doesn't have the\n  `Option` concept; the types can be clunky.\n* [sanctuary](https://github.com/sanctuary-js/sanctuary)\n  offers global functions like `S.filter(S.where(...))` while prelude-ts prefers a\n  fluent-API style like `list.filter(..).sortBy(...)`. Also, sanctuary doesn't\n  offer sets and maps. On the other hand, sanctuary has some JS runtime type system\n  support, which prelude-ts doesn't have.\n* [ramdajs](http://ramdajs.com/) offers global functions like\n  `R.filter(R.where(...))` while prelude-ts prefers a\n  fluent-API style like `list.filter(..).sortBy(...)`. Also, ramda doesn't offer\n  sets and maps. Ramda also uses currying a lot out of the box, which may not\n  be intuitive to a number of developers. In prelude,\n  [currying](http://emmanueltouzery.github.io/prelude.ts/latest/apidoc/interfaces/function.function2.html#curried)\n  & [partial application](http://emmanueltouzery.github.io/prelude.ts/latest/apidoc/interfaces/function.function2.html#apply1)\n  are opt-in.\n* [lodash](https://lodash.com) also has global functions, and many functions\n  mutate the collections.\n* [vavr](http://www.vavr.io/) -- it's a Java library, but it's the main inspiration for prelude-ts.\n  Note that vavr is inspired by the Scala library, so prelude-ts also is,\n  transitively.\n\n## TypeScript version\n\nAs of 0.8.2, prelude requires TypeScript 3.1 or newer.\n\n## Commands\n\n    npm install\n\n    npm test\n\n    npm run-script docgen\n\n    npm run benchmarks\n\n[npm-image]: https://img.shields.io/npm/v/prelude-ts.svg?style=flat-square\n[npm-url]: https://www.npmjs.com/package/prelude-ts\n[circleci-image]: https://circleci.com/gh/emmanueltouzery/prelude-ts.svg?style=shield\n[circleci-url]: https://circleci.com/gh/emmanueltouzery/prelude-ts\n[apidoc-image]: http://emmanueltouzery.github.io/prelude.ts/apidoc.svg\n[apidoc-url]: http://emmanueltouzery.github.io/prelude.ts/latest/apidoc/globals.html\n\n## Related projects\n* [Prelude-IO](https://github.com/Annoiiyed/Prelude-IO), a library offering IO features -including deserializing and validation- on top of prelude-ts, emphasizing type-safety and immutability\n"
  },
  {
    "path": "benchmarks/bench.ts",
    "content": "const Benchmark: any = require('benchmark');\n\nimport { execSync } from \"child_process\";\nimport { Vector } from \"../src/Vector\";\nimport { HashSet } from \"../src/HashSet\";\nimport { HashMap } from \"../src/HashMap\";\nimport { LinkedList } from \"../src/LinkedList\";\n\n// import immutables through require for now so that\n// the immutables typescript type definitions are not\n// parsed: as of typescript 2.9rc and immutables 4.0.0rc9\n// they don't compile.\nconst imm: any = require('immutable');\n// import * as imm from 'immutable';\n\nconst hamt: any = require(\"hamt_plus\");\nconst hamtBase: any = require(\"hamt\");\n\nimport * as Funkia from \"list\";\n\nconst lengths = [200, 10000];\n\nfunction getPrerequisites(length:number): Prerequisites {\n    // https://stackoverflow.com/a/43044960/516188\n    const getArray = (length:number) => Array.from({length}, () => Math.floor(Math.random() * length));\n    const array = getArray(length);\n    const vec = Vector.ofIterable(array);\n    const rawhamt = hamt.empty.mutate(\n        (h:any) => {\n            const iterator = array[Symbol.iterator]();\n            let curItem = iterator.next();\n            while (!curItem.done) {\n                h.set(h.size, curItem.value);\n                curItem = iterator.next();\n            }\n        });\n    let rawhamtBase = hamtBase.empty;\n    const iterator = array[Symbol.iterator]();\n    let curItem = iterator.next();\n    while (!curItem.done) {\n        rawhamtBase = rawhamtBase.set(rawhamtBase.size, curItem.value);\n        curItem = iterator.next();\n    }\n\n    const list = LinkedList.ofIterable(array);\n    const immList = imm.List(array);\n    const funkiaList = Funkia.from(array);\n\n    const idxThreeQuarters = array.length*3/4;\n    const atThreeQuarters = array[idxThreeQuarters];\n\n    const hashset = HashSet.ofIterable(array);\n    const immSet = imm.Set(array);\n\n    const hashmap = HashMap.ofIterable<string,number>(array.map<[string,number]>(x => [x+\"\",x]));\n    const immMap = imm.Map(array.map<[string,number]>(x => [x+\"\",x]));\n\n    return {vec,immList,array,list,idxThreeQuarters,\n            rawhamt,rawhamtBase,hashset,immSet,length,hashmap,immMap, funkiaList};\n}\n\ninterface Prerequisites {\n    vec: Vector<number>;\n    // immList: imm.List<number>;\n    immList: any;\n    array: number[];\n    list:LinkedList<number>;\n    idxThreeQuarters: number;\n    rawhamt: any;\n    rawhamtBase: any;\n    hashset: HashSet<number>;\n    // immSet: imm.Set<number>;\n    immSet: any;\n    hashmap: HashMap<string,number>;\n    // immMap: imm.Map<string,number>;\n    immMap: any;\n    length:number;\n    funkiaList: Funkia.List<number>;\n}\n\nconst preReqs = lengths.map(getPrerequisites);\n\nfunction _compare(preReqs: Prerequisites, items: Array<[string, (x:Prerequisites)=>any]>) {\n    const benchSuite: any = new Benchmark.Suite;\n    for (const item of items) {\n        benchSuite.add(item[0], () => item[1](preReqs));\n    }\n    benchSuite.on('cycle', function(event:any) {\n        console.log(String(event.target));\n    }).on('complete', function(this:any) {\n        console.log('Fastest is ' + this.filter('fastest').map('name') + \"\\n\");\n    }).run();\n}\nfunction compare(...items: Array<[string, (x:Prerequisites)=>any]>) {\n    for (let i=0;i<lengths.length;i++) {\n        let length = lengths[i];\n        console.log(\"n = \" + length);\n        _compare(preReqs[i], items);\n    }\n}\n\nconsole.log(\"immList, immSet are the immutablejs list,set... https://facebook.github.io/immutable-js/\");\nconsole.log(\"funkiaList is the list from https://github.com/funkia/list\");\n\nprocess.stdout.write(\"node version: \");\nexecSync(\"node --version\", {stdio:[0,1,2]});\nconsole.log();\n\ncompare(['Vector.toArray', (p:Prerequisites) => p.vec.toArray()],\n        ['LinkedList.toArray', (p:Prerequisites) => p.list.toArray()],\n        ['immList.toArray', (p:Prerequisites) => p.immList.toArray()],\n        ['funkiaList.toArray', (p:Prerequisites) => Funkia.toArray(p.funkiaList)]);\n\ncompare(['Vector.take', (p:Prerequisites) => p.vec.take(p.idxThreeQuarters)],\n        ['Array.slice', (p:Prerequisites) => p.array.slice(0,p.idxThreeQuarters)],\n        ['immList.take', (p:Prerequisites) => p.immList.take(p.idxThreeQuarters)],\n        ['LinkedList.take', (p:Prerequisites) => p.list.take(p.idxThreeQuarters)],\n        ['funkiaList.take', (p:Prerequisites) => Funkia.take(p.idxThreeQuarters, p.funkiaList)]);\n\ncompare(['Vector.drop', (p:Prerequisites) => p.vec.drop(p.idxThreeQuarters)],\n        ['Array.slice', (p:Prerequisites) => p.array.slice(p.idxThreeQuarters)],\n        ['immList.slice', (p:Prerequisites) => p.immList.slice(p.idxThreeQuarters)],\n        ['LinkedList.drop', (p:Prerequisites) => p.list.drop(p.idxThreeQuarters)],\n        ['funkiaList.drop', (p:Prerequisites) => Funkia.drop(p.idxThreeQuarters, p.funkiaList)]);\n\ncompare(['Vector.filter', (p:Prerequisites) => p.vec.filter(x => x%2===0)],\n        ['Array.filter', (p:Prerequisites) => p.array.filter(x => x%2===0)],\n        ['immList.filter', (p:Prerequisites) => p.immList.filter((x:number) => x%2===0)],\n        ['LinkedList.filter', (p:Prerequisites) => p.list.filter(x => x%2===0)],\n        ['funkiaList.filter', (p:Prerequisites) => Funkia.filter(x => x%2===0, p.funkiaList)]);\n\ncompare(['Vector.map', (p:Prerequisites) => p.vec.map(x => x*2)],\n        ['Array.map', (p:Prerequisites) => p.array.map(x => x*2)],\n        ['immList.map', (p:Prerequisites) => p.immList.map((x:number) => x*2)],\n        ['LinkedList.map', (p:Prerequisites) => p.list.map(x => x*2)],\n        ['funkiaList.map', (p:Prerequisites) => Funkia.map(x => x*2, p.funkiaList)]);\n\ncompare(['Vector.find', (p:Prerequisites) => p.vec.find(x => x===p.idxThreeQuarters)],\n        ['Array.find', (p:Prerequisites) => p.array.find(x => x===p.idxThreeQuarters)],\n        ['immList.find', (p:Prerequisites) => p.immList.find((x:number) => x===p.idxThreeQuarters)],\n        ['LinkedList.find', (p:Prerequisites) => p.list.find(x => x===p.idxThreeQuarters)],\n        ['funkiaList.find', (p:Prerequisites) => Funkia.find(x => x===p.idxThreeQuarters, p.funkiaList)]);\n\ncompare(['Vector.ofIterable', (p:Prerequisites) => Vector.ofIterable(p.array)],\n        ['rawhamt.build from iterable', (p:Prerequisites) => {\n            hamt.empty.mutate(\n                (h:any) => {\n                    const iterator = p.array[Symbol.iterator]();\n                    let curItem = iterator.next();\n                    while (!curItem.done) {\n                        h.set(h.size, curItem.value);\n                        curItem = iterator.next();\n                    }\n                })\n        }],\n        ['rawhamt.build from array', (p:Prerequisites) => {\n            hamt.empty.mutate(\n                (h:any) => {\n                    for (let i=0;i<p.array.length;i++) {\n                        h.set(i, p.array[i]);\n                    }\n                })\n        }],\n        ['rawhamtBase.build from iterable', (p:Prerequisites) => {\n            let rawhamtBase = hamtBase.empty;\n            const iterator = p.array[Symbol.iterator]();\n            let curItem = iterator.next();\n            while (!curItem.done) {\n                rawhamtBase = rawhamtBase.set(rawhamtBase.size, curItem.value);\n                curItem = iterator.next();\n            }\n        }],\n        ['LinkedList.ofIterable', (p:Prerequisites) =>LinkedList.ofIterable(p.array)],\n        ['immList.ofIterable', (p:Prerequisites) => imm.List(p.array)],\n        ['funkiaList.ofArray', (p:Prerequisites) => Funkia.from(p.array)]);\n\ncompare(['Vector.get(i)', (p:Prerequisites) => p.vec.get(p.length/2)],\n        ['rawhamt.get(i)', (p:Prerequisites) => p.rawhamt.get(p.length/2)],\n        ['rawhamtBase.get(i)', (p:Prerequisites) => p.rawhamtBase.get(p.length/2)],\n        ['LinkedList.get(i)', (p:Prerequisites) => p.list.get(p.length/2)],\n        ['Array.get(i)', (p:Prerequisites) => p.array[p.length/2]],\n        ['immList.get(i)', (p:Prerequisites) => p.immList.get(p.length/2)],\n        ['funkiaList.get(i)', (p:Prerequisites) => Funkia.nth(p.length/2, p.funkiaList)]);\n\ncompare(['Vector.flatMap', (p:Prerequisites) => p.vec.flatMap(x => Vector.of(1,2))],\n        ['LinkedList.flatMap', (p:Prerequisites) => p.list.flatMap(x =>LinkedList.of(1,2))],\n        ['immList.flatMap', (p:Prerequisites) => p.immList.flatMap((x:number) => imm.List([1,2]))],\n        ['funkiaList.chain', (p:Prerequisites) => Funkia.chain(x => Funkia.list(1,2), p.funkiaList)]);\n        \ncompare(['Vector.reverse', (p:Prerequisites) => p.vec.reverse()],\n        ['Array.reverse', (p:Prerequisites) => p.array.reverse()],\n        ['immList.reverse', (p:Prerequisites) => p.immList.reverse()],\n        ['LinkedList.reverse', (p:Prerequisites) => p.list.reverse()],\n        ['funkiaList.reverse', (p:Prerequisites) => Funkia.reverse(p.funkiaList)]);\n\ncompare(['Vector.groupBy', (p:Prerequisites) => p.vec.groupBy(x => x%2)],\n        ['LinkedList.groupBy', (p:Prerequisites) => p.list.groupBy(x => x%2)],\n        ['immList.groupBy', (p:Prerequisites) => p.immList.groupBy((x:number) => x%2)]);\n\ncompare(\n    ['Vector.append', (p:Prerequisites) => {\n        let v = Vector.empty<number>();\n        for (let item of p.array) {\n            v = v.append(item);\n        }\n    }],\n    ['Array.push', (p:Prerequisites) => {\n        let v = [];\n        for (let item of p.array) {\n            v.push(item);\n        }\n    }],\n    ['immList.push', (p:Prerequisites) => {\n        // let v = imm.List<number>();\n        let v = imm.List();\n        for (let item of p.array) {\n            v = v.push(item);\n        }\n    }],\n    ['LinkedList.append', (p:Prerequisites) => {\n        let v = LinkedList.empty<number>();\n        for (let item of p.array) {\n            v = v.append(item);\n        }\n    }],\n    ['Funkia.append', (p:Prerequisites) => {\n        let v = Funkia.empty();\n        for (let item of p.array) {\n            v = Funkia.append(item, v);\n        }\n    }]);\n\ncompare(\n    ['Vector.prepend', (p:Prerequisites) => {\n        let v = Vector.empty<number>();\n        for (let item of p.array) {\n            v = v.prepend(item);\n        }\n    }],\n    ['Array.unshift', (p:Prerequisites) => {\n        let v = [];\n        for (let item of p.array) {\n            v.unshift(item);\n        }\n    }],\n    ['immList.unshift', (p:Prerequisites) => {\n        // let v = imm.List<number>();\n        let v = imm.List();\n        for (let item of p.array) {\n            v = v.unshift(item);\n        }\n    }],\n    ['LinkedList.prepend', (p:Prerequisites) => {\n        let v = LinkedList.empty<number>();\n        for (let item of p.array) {\n            v = v.prepend(item);\n        }\n    }],\n    ['Funkia.prepend', (p:Prerequisites) => {\n        let v = Funkia.empty();\n        for (let item of p.array) {\n            v = Funkia.prepend(item, v);\n        }\n}]);\n\nfunction iterateOn<T>(coll: Iterable<T>) {\n    const it = coll[Symbol.iterator]();\n    let item = it.next();\n    while (!item.done) {\n        item = it.next();\n    }\n}\n\ncompare(['Vector.iterate', (p:Prerequisites) => iterateOn(p.vec)],\n        ['Array.iterate', (p:Prerequisites) => iterateOn(p.array)],\n        ['immList.iterate', (p:Prerequisites) => iterateOn(p.immList)],\n        ['LinkedList.iterate', (p:Prerequisites) => iterateOn(p.list)],\n        ['Funkia.iterate', (p:Prerequisites) => iterateOn(p.funkiaList)]);\n\ncompare(['Vector.appendAll', (p:Prerequisites) => p.vec.appendAll(p.vec)],\n        ['Array.appendAll', (p:Prerequisites) => p.array.concat(p.array)],\n        ['immList.appendAll', (p:Prerequisites) => p.immList.concat(p.immList)],\n        ['LinkedList.appendAll', (p:Prerequisites) => p.list.appendAll(p.list)],\n        ['Funkia.concat', (p:Prerequisites) => Funkia.concat(p.funkiaList, p.funkiaList)]);\n\ncompare(['Vector.prependAll', (p:Prerequisites) => p.vec.prependAll(p.vec)],\n        ['Array.prependAll', (p:Prerequisites) => p.array.concat(p.array)],\n        ['LinkedList.prependAll', (p:Prerequisites) => p.list.prependAll(p.list)]);\n\ncompare(['Vector.foldLeft', (p:Prerequisites) => p.vec.foldLeft(0, (acc,i)=>acc+i)],\n        ['Array.foldLeft', (p:Prerequisites) => p.array.reduce((acc,i)=>acc+i)],\n        ['immList.foldLeft', (p:Prerequisites) => p.immList.reduce((acc:number,i:number)=>acc+i,0)],\n        ['LinkedList.foldLeft', (p:Prerequisites) => p.vec.foldLeft(0, (acc,i)=>acc+i)],\n        ['Funkia.foldl', (p:Prerequisites) => Funkia.foldl((i,acc)=>acc+i, 0, p.funkiaList)]);\n\ncompare(['Vector.foldRight', (p:Prerequisites) => p.vec.foldRight(0, (i,acc)=>acc+i)],\n        ['immList.foldRight', (p:Prerequisites) => p.immList.reduceRight((acc:number,i:number)=>acc+i,0)],\n        ['LinkedList.foldRight', (p:Prerequisites) => p.vec.foldRight(0, (i,acc)=>acc+i)],\n        ['Funkia.foldr', (p:Prerequisites) => Funkia.foldr((i,acc)=>acc+i, 0, p.funkiaList)]);\n\ncompare(['HashSet.ofIterable', (p:Prerequisites) => HashSet.ofIterable(p.array)],\n        ['immSet', (p:Prerequisites) => imm.Set(p.array)]);\n\ncompare(['HashSet.ofIterable (from vector)', (p:Prerequisites) => HashSet.ofIterable(p.vec)],\n        ['immSet (from vector)', (p:Prerequisites) => imm.Set(p.vec)]);\n\ncompare(['HashSet.contains', (p:Prerequisites) => p.hashset.contains(p.array[Math.floor(Math.random()*p.array.length)])],\n        ['immSet.contains', (p:Prerequisites) => p.immSet.contains(p.array[Math.floor(Math.random()*p.array.length)])]);\n\ncompare(['HashSet.filter', (p:Prerequisites) => p.hashset.filter(x => x<p.length/2)],\n        ['immSet.filter', (p:Prerequisites) => p.immSet.filter((x:number) => x<p.length/2)]);\n\ncompare(['HashMap.ofIterable', (p:Prerequisites) =>\n         HashMap.ofIterable<string,number>(p.array.map<[string,number]>(x => [x+\"\",x]))],\n        ['immMap', (p:Prerequisites) => imm.Map(p.array.map<[string,number]>(x => [x+\"\",x]))]);\n\ncompare(['HashMap.ofIterable (from vector)', (p:Prerequisites) =>\n         HashMap.ofIterable(p.vec.map<[string,number]>(x => [x+\"\",x]))],\n        ['immMap (from vector)', (p:Prerequisites) =>\n         imm.Map(p.vec.map<[string,number]>(x => [x+\"\",x]))]);\n\ncompare(['HashMap.get', (p:Prerequisites) => p.hashmap.get(p.array[Math.floor(Math.random()*p.array.length)]+\"\")],\n        ['immMap.get', (p:Prerequisites) => p.immMap.get(p.array[Math.floor(Math.random()*p.array.length)]+\"\")]);\n\ncompare(['HashMap.filter', (p:Prerequisites) => p.hashmap.filter((k,v) => parseInt(k)<p.length/2)],\n        ['immMap.filter', (p:Prerequisites) => p.immMap.filter((v:number,k:string) => parseInt(k)<p.length/2)]);\n"
  },
  {
    "path": "package.json",
    "content": "{\n    \"name\": \"prelude-ts\",\n    \"version\": \"1.0.6\",\n    \"description\": \"A typescript functional programming library\",\n    \"main\": \"dist/src/index.js\",\n    \"typings\": \"dist/src/index.d.ts\",\n    \"repository\": {\n        \"type\": \"git\",\n        \"url\": \"git+https://github.com/emmanueltouzery/prelude.ts.git\"\n    },\n    \"dependencies\": {\n        \"hamt_plus\": \"1.0.2\",\n        \"list\": \"2.0.19\"\n    },\n    \"devDependencies\": {\n        \"@types/mocha\": \"5.2.7\",\n        \"mocha\": \"6.2.0\",\n        \"typedoc\": \"0.7.2\",\n        \"@types/node\": \"12.7.3\",\n        \"benchmark\": \"2.1.4\",\n        \"typescript\": \"3.1.6\",\n        \"browserify\": \"16.5.0\",\n        \"uglify-js\": \"3.6.0\",\n        \"immutable\": \"4.0.0-rc.12\",\n        \"hamt\": \"2.2.2\",\n        \"mocha-testcheck\": \"1.0.0-rc.0\",\n        \"request-promise-native\": \"1.0.7\",\n        \"@types/request-promise-native\": \"1.0.16\",\n        \"request\": \"2.88.0\",\n        \"handlebars\": \"4.5.3\"\n    },\n    \"keywords\": [\n        \"typescript\",\n        \"functional-programming\",\n        \"immutable\",\n        \"collections\"\n    ],\n    \"author\": \"Emmanuel Touzery\",\n    \"license\": \"ISC\",\n    \"bugs\": {\n        \"url\": \"https://github.com/emmanueltouzery/prelude.ts/issues\"\n    },\n    \"homepage\": \"https://github.com/emmanueltouzery/prelude.ts#readme\",\n    \"scripts\": {\n        \"prepare\": \"npm run clean; scripts/prepublish.sh\",\n        \"test\": \"rm -f tests/apidoc-*; tsc -p tsconfig.test.json && node ./dist/tests/Comments.js && tsc -p tsconfig.test.json && ./node_modules/mocha/bin/mocha --throw-deprecation --timeout 90000 ./dist/tests/*.js\",\n        \"clean\": \"rm -f tests/apidoc-*; rm -Rf ./dist\",\n        \"docgen\": \"./scripts/make_doc.sh\",\n        \"benchmarks\": \"tsc -p tsconfig.benchmarks.json && node ./dist/benchmarks/bench.js\"\n    },\n    \"files\": [\n        \"dist\",\n        \"src\",\n        \"LICENSE.TXT\",\n        \"README.md\",\n        \"package.json\"\n    ]\n}\n"
  },
  {
    "path": "package.json.txt",
    "content": "Comments for the package.json cause I can't put them in the file itself...\n\n   \"@types/node\": \"9.6.7\"\n   => pin the types/node dependency for a more reliable build\n      example https://github.com/DefinitelyTyped/DefinitelyTyped/issues/25342\n      @types/node is a transitive dep from typedoc, typedoc doesn't lock it\n\n   the typescript dependency is at 3.1.x because that's the oldest TS version\n   that we support. You can also build with the TS version of your choice by\n   running 'tsc' manually.\n\n   we are modifying the generated typedoc HTML to improve it, hence did not\n   upgrade typedoc for a while.\n\n\nDirect handlebars dependency:\nhttps://github.com/TypeStrong/typedoc/issues/1159\n\nNeed to pin handlebars to unbreak typedoc\n"
  },
  {
    "path": "scripts/make_doc.sh",
    "content": "#!/usr/bin/env bash\nset -e\n\nnpm install --no-package-lock\ntsc -p tsconfig.docgen.json\n\n# https://github.com/TypeStrong/typedoc/issues/564\n# i would like typedoc to group functions in categories but it's not supported\n# yet. So I hack it with their support for external modules...\n\n# we'll modify the files and then revert our changes using\n# git reset --HARD so make sure there are no local changes\nif [[ $(git status --porcelain) ]]; then\n    echo \"Can't generate the docs when the git checkout isn't clean\"\n    exit 1\nfi\n\n# pre-process files\nnode dist/scripts/make_doc_extra/make_doc_preprocess.js\n\n# trick for the 'Option' & 'Either' constants which typedoc skips as it clashes\n# with the 'Option' & 'Either' type synomym\nsed -i \"s/const Option/const optionGlabiboulga/\" src/Option.ts\nsed -i \"s/const Either/const eitherGlabiboulga/\" src/Either.ts\nsed -i \"s/const LinkedList/const linkedListGlabiboulga/\" src/LinkedList.ts\nsed -i \"s/const Stream/const streamGlabiboulga/\" src/Stream.ts\nsed -i \"s/const Function0/const function0Glabiboulga/\" src/Function.ts\nsed -i \"s/const Function1/const function1Glabiboulga/\" src/Function.ts\nsed -i \"s/const Function2/const function2Glabiboulga/\" src/Function.ts\nsed -i \"s/const Function3/const function3Glabiboulga/\" src/Function.ts\nsed -i \"s/const Function4/const function4Glabiboulga/\" src/Function.ts\nsed -i \"s/const Function5/const function5Glabiboulga/\" src/Function.ts\nsed -i \"s/const Predicate/const predicateGlabiboulga/\" src/Predicate.ts\n\n# generate with typedoc\n./node_modules/typedoc/bin/typedoc --exclude \"**/make_doc_extra/*.ts\" --mode file --out apidoc --excludePrivate --excludeExternals --excludeNotExported --ignoreCompilerErrors --tsconfig tsconfig.prepublish.json src/index.ts\n\n# revert the 'Option' & 'Either' constant rename\nfind apidoc -name \"*.html\" -exec sed -i 's/optionglabiboulga/Option/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/option<wbr>Glabiboulga/Option/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/eitherglabiboulga/Either/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/either<wbr>Glabiboulga/Either/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/linkedlistglabiboulga/LinkedList/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/linked<wbr>List<wbr>Glabiboulga/LinkedList/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/streamglabiboulga/Stream/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/stream<wbr>Glabiboulga/Stream/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/function0glabiboulga/Function0/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/function0<wbr>Glabiboulga/Function0/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/function1glabiboulga/Function1/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/function1<wbr>Glabiboulga/Function1/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/function2glabiboulga/Function2/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/function2<wbr>Glabiboulga/Function2/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/function3glabiboulga/Function3/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/function3<wbr>Glabiboulga/Function3/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/function4glabiboulga/Function4/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/function4<wbr>Glabiboulga/Function4/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/function5glabiboulga/Function5/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/function5<wbr>Glabiboulga/Function5/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/predicateglabiboulga/Predicate/g' \\{\\} \\;\nfind apidoc -name \"*.html\" -exec sed -i 's/predicate<wbr>Glabiboulga/Predicate/g' \\{\\} \\;\n\n# modify the output to say 'File' instead of 'Module'\nfind apidoc -name \"*.html\" -exec sed -i 's/Module/File/g' \\{\\} \\;\n\n# modify the paths to say 'files' instead of 'modules'\nmv apidoc/modules apidoc/files\nfind apidoc -name \"*.html\" -exec sed -i 's/modules/files/g' \\{\\} \\;\n\nnode dist/scripts/make_doc_extra/make_doc_extra.js\n\n# we're happy with the output now, revert the changes I made\n# to the files to make typedoc think they're external modules\ngit reset --hard HEAD\n"
  },
  {
    "path": "scripts/make_doc_extra/classes.ts",
    "content": "import { readdirSync, writeFileSync } from \"fs\";\nimport { Vector } from \"../../src/Vector\";\nimport { Function4 } from \"../../src/Function\";\nimport { Predicate } from \"../../src/Predicate\";\nimport * as helpers from \"./helpers\";\n\nconst classesFolder = \"apidoc/classes/\";\n\n/**\n * we work on lines-level in the text output, not xml tags\n * sometimes we have in one parentne \"<parent>..</parent>\"\n * but we also want to support \"<parent>\\n...\\n</parent>\"\n */\nfunction putStaticMethodsOnTop(parentTag: string, parentMarker: string, childTag: string,\n                               linesByIndent: helpers.LinesByIndent): helpers.LinesByIndent\n{\n    const [beforeIndexContent,indexContent,afterIndexContent] =\n        helpers.linesByIndentGetTagContents(linesByIndent, parentTag, l => l.indexOf(parentMarker) >= 0);\n\n    const openTag = Predicate.of<helpers.LineByIndent>(\n        l => l.contents.indexOf(\"<\" + childTag) >= 0);\n\n    // the marker parent might be of the same tag, so keep it always.\n    const beforeFirstTag = indexContent.take(1)\n        .appendAll(indexContent.drop(1).takeWhile(openTag.negate()));\n\n    // the marker parent might be of the same tag, so keep it always.\n    const afterLastTag = indexContent.reverse().take(1)\n        .appendAll(indexContent\n                    .reverse().drop(1)\n                    .takeWhile(l => l.contents.indexOf(\"</\" + childTag) < 0))\n        .reverse();\n\n    const staticOrNot = indexContent\n        .drop(beforeFirstTag.length())\n        .dropRight(afterLastTag.length())\n        // group the li tags and their contents together, even if they span\n        // across several lines like <parent>\\n..\\n</parent>\n        .foldLeft(Vector.empty<helpers.LinesByIndent>(), (sofar,cur) => openTag(cur) ?\n                  // open li tag => start a new entry\n                  sofar.append(Vector.of<helpers.LineByIndent>(cur)) :\n                  // not open li tag => continue the previous entry\n                  sofar.dropRight(1).append(sofar.last().getOrThrow().append(cur)))\n        .partition(l => l.head().getOrThrow().contents.indexOf(\"tsd-is-static\") >= 0);\n\n    return beforeIndexContent\n        .appendAll(beforeFirstTag)\n        .appendAll(staticOrNot[0].flatMap(x=>x))\n        .appendAll(staticOrNot[1].flatMap(x=>x))\n        .appendAll(afterLastTag)\n        .appendAll(afterIndexContent);\n}\n\nfunction classPutStaticMethodsOnTop(classfilename: string): void {\n    const lines = helpers.fileGetLinesByIndent(classesFolder + classfilename);\n    const fnStatic = Function4.of(putStaticMethodsOnTop);\n    const transform = fnStatic.apply3(\"ul\", \"tsd-index-list\", \"li\")\n        .andThen(fnStatic.apply3(\"li\", \"current tsd-kind-class\", \"li\"))\n        .andThen(fnStatic.apply3(\"section\", \"tsd-panel-group tsd-member-group\", \"section\"));\n\n    writeFileSync(classesFolder + classfilename, helpers.linesByIndentStr(transform(lines)));\n}\n\nexport function putClassStaticMethodsOnTop(): void {\n    const classFiles = Vector.ofIterable(readdirSync(classesFolder));\n    classFiles.forEach(classPutStaticMethodsOnTop);\n}\n"
  },
  {
    "path": "scripts/make_doc_extra/globals.ts",
    "content": "import { Vector } from \"../../src/Vector\";\nimport { HashMap } from \"../../src/HashMap\";\nimport { HashSet } from \"../../src/HashSet\";\nimport { writeFileSync } from \"fs\";\nimport * as helpers from \"./helpers\";\n\n// group classes & interfaces by category.\nconst CATEGORIES = Vector.of<[string,Vector<string>]>(\n    [\"Control\", Vector.of(\n        \"Either\", \"Option\", \"Lazy\",\n        \"Function\", \"Predicate\", \"Future\")],\n    [\"Collection\", Vector.of(\n        \"Collection\", \"Foldable\",\n        \"IMap\",\"IterableArray\",\"HashMap\", \"ISet\", \"HashSet\",\n        \"Seq\", \"LinkedList\", \"Stream\", \"Vector\",\n        \"Tuple2\", \"SortOnSpec\", \"SortBySpec\")],\n    [\"Core\", Vector.of(\n        \"Comparison\", \"Value\", \"Contract\")]);\n\nfunction getSectionHeader(sectionName:string): string {\n    return `${helpers.indent(6)}<section class=\"tsd-index-section\">` +\n        `${helpers.indent(7)}<h3>${sectionName}</h3>` +\n        `${helpers.indent(7)}<ul class=\"tsd-index-list\">\\n`;\n}\n\nfunction getSectionFooter(): string {\n    return `${helpers.indent(7)}</ul>` +\n        `${helpers.indent(6)}</section>`;\n}\n\n// improve the typedoc 'globals' screen by\n// grouping the classes, interfaces by \"categories\"\n// and not by type (class, interface,...) as typedoc\n// does out of the box.\n// i should rather try to improve typedoc but..\n//\n// I rather not using typescript external modules\n// because there are several options and I think\n// that may assume too much about how users of the\n// library want to consume it.\n// So everything is in the base namespace, but I can\n// at least do some grouping in the apidocs.\nexport function groupGlobalsByCategory(): void {\n    // we'll modify the 'globals' typedoc file.\n    const lines = helpers.fileGetLinesByIndent(\"apidoc/globals.html\");\n\n    // i'm interested in the part within 'tsd-index-content'\n    const [beforeIndexContent,indexContent,afterIndexContent] =\n        helpers.linesByIndentGetTagContents(lines, \"div\", l => l.indexOf(\"tsd-index-content\") >= 0);\n\n    // right now i have the part of interest. I can regenerate the wrapping items\n    // the items which interest me are the leaves, which are <li> tags,\n    // and I'll group them by their name (class name, interface name...).\n    const liRows = indexContent\n        .map(l => l.contents)\n        .filter(t => t.indexOf(\"<li\") >= 0)\n        .arrangeBy(row => helpers.requireNotNull(row.match(/>([\\w<>]+)<\\//))[1].replace(/<wbr>/g,\"\"))\n        .getOrThrow(\"globals.arrangeBy failed!\");\n\n    // start preparing the new contents for the indexContent\n    let newIndexContent = `${helpers.indent(5)}<div class=\"tsd-index-content\">`;\n\n    const allKnownElements = CATEGORIES\n        .map(c=>c[1])\n        .flatMap(x=>x)\n        .transform(HashSet.ofIterable);\n\n    const missingElements = liRows.keySet().diff(allKnownElements);\n    if (!missingElements.isEmpty()) {\n        throw \"Missing the following elements: \" + missingElements;\n    }\n\n    CATEGORIES.forEach(([name,elements]) => {\n        newIndexContent += getSectionHeader(name);\n        const rows = elements.map(elt => liRows.get(elt).getOrThrow(\"can't find row for \" + elt));\n        newIndexContent += rows.mkString(\"\\n\");\n        newIndexContent += getSectionFooter();\n    });\n\n    // conclude the new contents for the indexContent\n    newIndexContent += `${helpers.indent(5)}</div>\\n`; // close tsd-index-content\n\n    // overwrite globals.html -- first the text before the indexContent,\n    // then the modified indexContent, then the rest.\n    writeFileSync(\n        'apidoc/globals.html',\n        helpers.linesByIndentStr(beforeIndexContent) +\n            newIndexContent +\n            helpers.linesByIndentStr(afterIndexContent));\n}\n"
  },
  {
    "path": "scripts/make_doc_extra/helpers.ts",
    "content": "import { Stream } from \"../../src/Stream\";\nimport { Vector } from \"../../src/Vector\";\nimport { readFileSync } from \"fs\";\n\nexport function requireNotNull<T>(x:T|null): T {\n    if (x === null) {\n        throw \"requireNotNull got null!\";\n    }\n    return <T>x;\n}\n\nexport function indent(count: number): string {\n    return \"\\n\" + Stream.continually(()=>\"\\t\")\n        .take(count).mkString(\"\");\n}\n\nexport type LineByIndent = {contents:string,indent:number};\nexport type LinesByIndent = Vector<LineByIndent>;\n\nexport function fileGetLinesByIndent(fname: string): LinesByIndent {\n    const contents = readFileSync(fname).toString();\n    return Vector.ofIterable(contents.split(\"\\n\"))\n        .map(l => ({indent: l.length-l.trim().length, contents: l}));\n}\n\n/**\n * extract a tag from the linesbyindent. You tell me the tag name,\n * how to match the start tag, I return to you the rows before, the rows within that\n * tag (depth>=tagDepth) and the rows after.\n * returns [before, atTag, after]\n */\nexport function linesByIndentGetTagContents(\n    lines: LinesByIndent,\n    tagName: string,                                        \n    startPredicate: (line:string)=>boolean): [LinesByIndent, LinesByIndent, LinesByIndent] {\n    // split the parts before & after using string the predicate & indentation.\n    const [before, atTag] = lines.span(l => !startPredicate(l.contents));\n    const indentAtTag = atTag.head().getOrThrow().indent;\n    const [tagContents,after] =\n            atTag.span(l => (l.indent > indentAtTag) ||\n                       (l.indent <= indentAtTag && l.contents.indexOf(\"</\" + tagName) < 0));\n    if (!after.isEmpty()) {\n        // i want the closing tag also in 'atTag' but I rejected it in the span,\n        // so take it from after\n        return [before, tagContents.append(after.head().getOrThrow()), after.drop(1)];\n    }\n    return [before, tagContents, after];\n}\n\nexport function linesByIndentStr(linesByIndent: LinesByIndent): string {\n    return linesByIndent.map(l => l.contents).mkString(\"\\n\");\n}\n"
  },
  {
    "path": "scripts/make_doc_extra/make_doc_extra.ts",
    "content": "import { groupGlobalsByCategory } from \"./globals\";\nimport { putClassStaticMethodsOnTop } from \"./classes\";\n\nconsole.log(\"groupGlobalsByCategory\");\ngroupGlobalsByCategory();\nconsole.log(\"putClassStaticMethodsOnTop\");\nputClassStaticMethodsOnTop();\nconsole.log(\"make extra: done!\");\n"
  },
  {
    "path": "scripts/make_doc_extra/make_doc_preprocess.ts",
    "content": "import { readFileSync, writeFileSync } from \"fs\";\n\ndeclare global {\n    interface String {\n        startsWith(other:string): boolean\n    }\n}\n\nfunction makeModule(moduleName:string, filename:string): void {\n    const contents = readFileSync(filename).toString();\n    const moduleStart = \"export module \" + moduleName+ \" { \";\n    const contentsWithModuleHeader = contents.trim().startsWith(\"/**\") ?\n        // add the module header at the end of the apidoc comment\n        // so the comment apidoc covers the module\n        contents.replace(/\\*\\//, \"*/ \" + moduleStart) :\n        // add the module header straight at the top of the file\n        moduleStart + contents;\n\n    // in any case close at the end of the file\n    writeFileSync(filename, contentsWithModuleHeader + \"\\n}\\n\");\n}\n\n// list of files for which to trick typedoc\n// to think they're external modules\nmakeModule(\"Comparison\", \"src/Comparison.ts\");\nmakeModule(\"Contract\", \"src/Contract.ts\");\nmakeModule(\"Option\", \"src/Option.ts\");\nmakeModule(\"Either\", \"src/Either.ts\");\nmakeModule(\"LinkedList\", \"src/LinkedList.ts\");\nmakeModule(\"Stream\", \"src/Stream.ts\");\nmakeModule(\"Function\", \"src/Function.ts\");\nmakeModule(\"Predicate\", \"src/Predicate.ts\");\n\n"
  },
  {
    "path": "scripts/prepublish.sh",
    "content": "#!/usr/bin/env bash\nset -e\n\nnode_modules/typescript/bin/tsc -p tsconfig.prepublish.json\nnode ./node_modules/browserify/bin/cmd.js -s prelude_ts dist/src/index.js -o /tmp/prelude_ts_pre.js\nscripts/with_header.sh /tmp/prelude_ts_pre.js > dist/src/prelude_ts.js\nnode ./node_modules/browserify/bin/cmd.js -s prelude_ts_object_formatters dist/src/ChromeDevToolFormatters.js -o dist/src/chrome_dev_tools_formatters.js\n./node_modules/uglify-js/bin/uglifyjs --compress --mangle --output /tmp/prelude_ts_premin.js -- /tmp/prelude_ts_pre.js\nscripts/with_header.sh /tmp/prelude_ts_premin.js > dist/src/prelude_ts.min.js\nrm /tmp/prelude_ts_pre.js /tmp/prelude_ts_premin.js\n"
  },
  {
    "path": "scripts/with_header.sh",
    "content": "#!/usr/bin/env bash\nset -e\n\ncat <<END\n/**\n * prelude-ts v$(node -p 'require(\"./package.json\").version')\n * https://github.com/emmanueltouzery/prelude-ts\n * (c) 2017-$(git show -s --format=%ai | cut -d - -f 1) Emmanuel Touzery\n * prelude-ts may be freely distributed under the ISC license.\n*/\nEND\ncat $*\n"
  },
  {
    "path": "src/ChromeDevToolFormatters.ts",
    "content": "//  http://bit.ly/object-formatters\n\ninterface ElementHandler {\n    isElement(object:any): boolean;\n    getHeader(object:any): any;\n    hasBody(elt:any): boolean;\n    getBody(elt:any): any;\n}\n\nconst olStyle = \"list-style-type:none; padding-left: 0px; margin-top: 0px; margin-bottom: 0px; margin-left: 12px\";\n\nfunction getWithToArrayBody(elt: any): any {\n    return [\"ol\",\n            {\"style\":olStyle},\n            ...elt.toArray().map((x:any,idx:number) => [\"li\",{},\n                                                        [\"span\",{\"style\":\"color: rgb(136, 19, 145);\"},idx+\": \"],\n                                                        [\"object\", {\"object\":x}]])];\n}\n\nclass VectorHandler implements ElementHandler {\n    isElement(object:any): boolean {\n        return object.hashCode && object.equals &&\n            object.replace && object.sortOn && object._list;\n    }\n    getHeader(object:any): any {\n        return [\"span\", {}, \"Vector(\" + object.length() + \")\"];\n    }\n    hasBody(elt:any): boolean {\n        return !elt.isEmpty();\n    }\n    getBody = getWithToArrayBody\n}\n\n// not going to behave well with infinite streams...\nclass StreamHandler implements ElementHandler {\n    isElement(object:any): boolean {\n        return object.hashCode && object.equals && object.sortBy && object.cycle && object.toVector;\n    }\n    getHeader(object:any): any {\n        // not displaying the length for streams in case\n        // of infinite streams. the user can expand if needed.\n        return [\"span\", {}, \"Stream(?)\"];\n    }\n    hasBody(elt:any): boolean {\n        return !elt.isEmpty();\n    }\n    getBody = getWithToArrayBody\n}\n\nclass ListHandler implements ElementHandler {\n    isElement(object:any): boolean {\n        return object.hashCode && object.equals && object.sortBy && object.toVector;\n    }\n    getHeader(object:any): any {\n        // not displaying the length for streams in case\n        // of infinite streams. the user can expand if needed.\n        return [\"span\", {}, \"List(\" + object.length() + \")\"];\n    }\n    hasBody(elt:any): boolean {\n        return !elt.isEmpty();\n    }\n    getBody = getWithToArrayBody\n}\n\nclass HashSetHandler implements ElementHandler {\n    isElement(object:any): boolean {\n        return object.hashCode && object.equals && object.hamt && object.intersect;\n    }\n    getHeader(object:any): any {\n        return [\"span\", {}, \"HashSet(\" + object.length() + \")\"];\n    }\n    hasBody(elt:any): boolean {\n        return !elt.isEmpty();\n    }\n    getBody = getWithToArrayBody\n}\n\nclass HashMapHandler implements ElementHandler {\n    isElement(object:any): boolean {\n        return object.hashCode && object.equals && object.hamt && object.valueIterable;\n    }\n    getHeader(object:any): any {\n        return [\"span\", {}, \"HashMap(\" + object.length() + \")\"];\n    }\n    hasBody(elt:any): boolean {\n        return !elt.isEmpty();\n    }\n    getBody(elt:any): any {\n        return [\"ol\",\n                {\"style\":olStyle},\n                ...elt.toArray().map((kv:any,idx:number) => {\n                    // using object.create to avoid the __proto__ in the GUI\n                    const obj = Object.create(null);\n                    obj.key = kv[0];\n                    obj.value = kv[1];\n                    return [\"li\",{},\n                            [\"span\",{\"style\":\"color: rgb(136, 19, 145);\"},idx+\": \"],\n                            [\"object\", {\"object\":obj}]];\n                })];\n    }\n}\n\nconst handlers = [new VectorHandler(),\n                  new StreamHandler(),\n                  new ListHandler(),\n                  new HashSetHandler(),\n                  new HashMapHandler()];\n\nfunction getHandler(object: any): ElementHandler|undefined {\n    return handlers.find(h => h.isElement(object));\n}\n\nconst formatter = {\n    header: (object: any, config: any): any => {\n        const handler = getHandler(object);\n        return handler ? handler.getHeader(object) : null;\n    },\n    hasBody: (object: any, config: any): boolean => {\n        const handler = getHandler(object);\n        return handler ? handler.hasBody(object) : false;\n    },\n    body: (object: any, config:any): any => {\n        const handler = getHandler(object);\n        return handler ? handler.getBody(object) : null;\n    }\n};\nif (!(<any>window).devtoolsFormatters) {\n    (<any>window).devtoolsFormatters = [];\n}\n(<any>window).devtoolsFormatters.push(formatter);\n"
  },
  {
    "path": "src/Collection.ts",
    "content": "import { WithEquality, Ordering, ToOrderable } from \"./Comparison\";\nimport { Value } from \"./Value\";\nimport { Option } from \"./Option\";\nimport { HashMap } from \"./HashMap\";\nimport { Foldable } from \"./Foldable\";\n\nexport interface Collection<T> extends Value, Iterable<T>, Foldable<T> {\n\n    /**\n     * Get the length of the collection.\n     */\n    length(): number;\n\n    /**\n     * true if the collection is empty, false otherwise.\n     */\n    isEmpty(): boolean;\n\n    /**\n     * Convert to array.\n     */\n    toArray(): Array<T>;\n\n    /**\n     * Call a predicate for each element in the collection,\n     * build a new collection holding only the elements\n     * for which the predicate returned true.\n     */\n    filter<U extends T>(fn:(v:T)=>v is U): Collection<U>;\n    filter(predicate:(v:T)=>boolean): Collection<T>;\n\n    /**\n     * Returns a pair of two collections; the first one\n     * will only contain the items from this collection for\n     * which the predicate you give returns true, the second\n     * will only contain the items from this collection where\n     * the predicate returns false.\n     *\n     *     Vector.of(1,2,3,4).partition(x => x%2===0)\n     *     => [Vector.of(2,4), Vector.of(1,3)]\n     */\n    partition<U extends T>(predicate:(v:T)=>v is U): [Collection<U>,Collection<Exclude<T,U>>];\n    partition(predicate:(x:T)=>boolean): [Collection<T>,Collection<T>];\n\n    /**\n     * Returns true if the item is in the collection,\n     * false otherwise.\n     */\n    contains(v:T&WithEquality): boolean;\n\n    /**\n     * Returns true if the predicate returns true for all the\n     * elements in the collection.\n     */\n    allMatch<U extends T>(predicate:(v:T)=>v is U): this is Collection<U>;\n    allMatch(predicate:(v:T)=>boolean): boolean;\n\n    /**\n     * Returns true if there the predicate returns true for any\n     * element in the collection.\n     */\n    anyMatch(predicate:(v:T)=>boolean): boolean;\n\n    /**\n     * If the collection contains a single element,\n     * return Some of its value, otherwise return None.\n     */\n    single(): Option<T>;\n\n    /**\n     * Group elements in the collection using a classifier function.\n     * Elements are then organized in a map. The key is the value of\n     * the classifier, and in value we get the list of elements\n     * matching that value.\n     *\n     * also see [[Collection.arrangeBy]]\n     */\n    groupBy<C>(classifier: (v:T)=>C&WithEquality): HashMap<C,Collection<T>>;\n\n    /**\n     * Matches each element with a unique key that you extract from it.\n     * If the same key is present twice, the function will return None.\n     *\n     * also see [[Collection.groupBy]]\n     */\n    arrangeBy<K>(getKey: (v:T)=>K&WithEquality): Option<HashMap<K,T>>;\n\n    /**\n     * Compare values in the collection and return the smallest element.\n     * Returns Option.none if the collection is empty.\n     *\n     * also see [[Collection.minOn]]\n     */\n    minBy(compare: (v1:T,v2:T)=>Ordering): Option<T>;\n\n    /**\n     * Call the function you give for each value in the collection\n     * and return the element for which the result was the smallest.\n     * Returns Option.none if the collection is empty.\n     *\n     *     Vector.of({name:\"Joe\", age:12}, {name:\"Paula\", age:6}).minOn(x=>x.age)\n     *     => Option.of({name:\"Paula\", age:6})\n     *\n     * also see [[Collection.minBy]]\n     */\n    minOn(getNumber: ToOrderable<T>): Option<T>;\n\n    /**\n     * Compare values in the collection and return the largest element.\n     * Returns Option.none if the collection is empty.\n     *\n     * also see [[Collection.maxOn]]\n     */\n    maxBy(compare: (v1:T,v2:T)=>Ordering): Option<T>;\n\n    /**\n     * Call the function you give for each value in the collection\n     * and return the element for which the result was the largest.\n     * Returns Option.none if the collection is empty.\n     *\n     *     Vector.of({name:\"Joe\", age:12}, {name:\"Paula\", age:6}).maxOn(x=>x.age)\n     *     => Option.of({name:\"Joe\", age:12})\n     *\n     * also see [[Collection.maxBy]]\n     */\n    maxOn(getSortable: ToOrderable<T>): Option<T>;\n\n    /**\n     * Call the function you give for each element in the collection\n     * and sum all the numbers, return that sum.\n     * Will return 0 if the collection is empty.\n     *\n     *     Vector.of(1,2,3).sumOn(x=>x)\n     *     => 6\n     */\n    sumOn(getNumber: (v:T)=>number): number;\n}\n"
  },
  {
    "path": "src/Comparison.ts",
    "content": "import { Option } from \"./Option\";\n\n/**\n * Sorting function for type T: function\n * to convert this type to a type which is natively\n * sortable in javascript, that is string, number or boolean.\n * `((v:T)=>number) | ((v:T)=>string) | ((v:T)=>boolean`\n */\nexport type ToOrderable<T> = ((v:T)=>number) | ((v:T)=>string) | ((v:T)=>boolean);\n\n/**\n * List of types which provide equality semantics:\n * some builtin JS types, for which === provides\n * proper semantics, and then types providing HasEquals.\n * The reason I use all over the place T&WithEquality\n * instead of saying <T extends WithEquality> earlier\n * in the declaration is: https://stackoverflow.com/a/45903143/516188\n */\nexport type WithEquality\n    = string\n    | number\n    | boolean\n    | null\n    | HasEquals;\n\n/**\n * A type with semantic equality relationships\n */\nexport type HasEquals = {equals(other: any): boolean; hashCode(): number;};\n\n/**\n * Type guard for HasEquals: find out for a type with\n * semantic equality, whether you should call .equals\n * or ===\n */\nexport function hasEquals(v: WithEquality): v is HasEquals {\n    // there is a reason why we check only for equals, not for hashCode.\n    // we want to decide which codepath to take: === or equals/hashcode.\n    // if there is a equals function then we don't want ===, regardless of\n    // whether there is a hashCode method or not. If there is a equals\n    // and not hashCode, we want to go on the equals/hashCode codepath,\n    // which will blow a little later at runtime if the hashCode is missing.\n    return ((<HasEquals>v).equals !== undefined);\n}\n\n/**\n * Helper function for your objects so you can compute\n * a hashcode. You can pass to this function all the fields\n * of your object that should be taken into account for the\n * hash, and the function will return a reasonable hash code.\n *\n * @param fields the fields of your object to take\n *        into account for the hashcode\n */\nexport function fieldsHashCode(...fields: any[]): number {\n    // https://stackoverflow.com/a/113600/516188\n    // https://stackoverflow.com/a/18066516/516188\n    let result = 1;\n    for (const value of fields) {\n        result = 37*result + getHashCode(value);\n    }\n    return result;\n}\n\n/**\n * Helper function to compute a reasonable hashcode for strings.\n */\nexport function stringHashCode(str: string): number {\n    // https://stackoverflow.com/a/7616484/516188\n    var hash = 0, i, chr;\n    if (str.length === 0) return hash;\n    for (i = 0; i < str.length; i++) {\n        chr   = str.charCodeAt(i);\n        hash  = ((hash << 5) - hash) + chr;\n        hash |= 0; // Convert to 32bit integer\n    }\n    return hash;\n}\n\n/**\n * Equality function which tries semantic equality (using .equals())\n * if possible, degrades to === if not available, and is also null-safe.\n */\nexport function areEqual(obj: any|null, obj2: any|null): boolean {\n    if ((obj === null) != (obj2 === null)) {\n        return false;\n    }\n    if (obj === null || obj2 === null) {\n        return true;\n    }\n    if (hasEquals(obj)) {\n        return obj.equals(obj2);\n    }\n    return obj === obj2;\n}\n\n/**\n * Hashing function which tries to call hashCode()\n * and uses the object itself for numbers, then degrades\n * for stringHashCode of the string representation if\n * not available.\n */\nexport function getHashCode(obj: any|null): number {\n    if (!obj) {\n        return 0;\n    }\n    if (hasEquals(obj)) {\n        return obj.hashCode();\n    }\n    if (typeof obj === 'number') {\n        // this is the hashcode implementation for numbers from immutablejs\n        if (obj !== obj || obj === Infinity) {\n            return 0;\n        }\n        let h = obj | 0;\n        if (h !== obj) {\n            h ^= obj * 0xffffffff;\n        }\n        while (obj > 0xffffffff) {\n            obj /= 0xffffffff;\n            h ^= obj;\n        }\n        return smi(h);\n    }\n    const val = obj+\"\";\n    return val.length > STRING_HASH_CACHE_MIN_STRLEN ?\n        cachedHashString(val) :\n        stringHashCode(val);\n}\n\nfunction cachedHashString(string: string) {\n    let hashed = stringHashCache[string];\n    if (hashed === undefined) {\n        hashed = stringHashCode(string);\n        if (STRING_HASH_CACHE_SIZE === STRING_HASH_CACHE_MAX_SIZE) {\n            STRING_HASH_CACHE_SIZE = 0;\n            stringHashCache = {};\n        }\n        STRING_HASH_CACHE_SIZE++;\n        stringHashCache[string] = hashed;\n    }\n    return hashed;\n}\n\n// v8 has an optimization for storing 31-bit signed numbers.\n// Values which have either 00 or 11 as the high order bits qualify.\n// This function drops the highest order bit in a signed number, maintaining\n// the sign bit. (taken from immutablejs)\nfunction smi(i32: number): number {\n    return ((i32 >>> 1) & 0x40000000) | (i32 & 0xbfffffff);\n}\n\nconst STRING_HASH_CACHE_MIN_STRLEN = 16;\nconst STRING_HASH_CACHE_MAX_SIZE = 255;\nlet STRING_HASH_CACHE_SIZE = 0;\nlet stringHashCache: {[key:string]:number} = {};\n\n/**\n * @hidden\n */\nexport function hasTrueEquality(val: any): Option<boolean> {\n    if (!val) {\n        return Option.none<boolean>();\n    }\n    if (val.equals) {\n        return Option.of(true);\n    }\n    switch (val.constructor) {\n    case String:\n    case Number:\n    case Boolean:\n        return Option.of(true);\n    }\n    return Option.of(false);\n}\n\n/**\n * Enumeration used to express ordering relationships.\n * it's a const enum, is replaced by integers in the source.\n */\nexport const enum Ordering {\n    /**\n     * Lower Than\n     */\n    LT=-1,\n    /**\n     * EQuals\n     */\n    EQ=0,\n    /**\n     * Greater Than\n     */\n    GT=1\n};\n\n/**\n * Typescript doesn't infer typeguards for lambdas; it only sees\n * predicates. This type allows you to cast a predicate to a type\n * guard in a handy manner.\n *\n * It comes in handy for discriminated unions with a 'kind' discriminator,\n * for instance:\n *\n * .`filter(<TypeGuard<InBoard|OutBoard,InBoard>>(p => p.kind === \"in_board\"))`\n *\n * Also see [[typeGuard]], [[instanceOf]] and [[typeOf]].\n */\nexport type TypeGuard<T,U extends T> = (x: T) => x is U;\n\n/**\n * Typescript doesn't infer typeguards for lambdas; it only sees\n * predicates. This type allows you to cast a predicate to a type\n * guard in a handy manner.\n *\n * It comes in handy for discriminated unions with a 'kind' discriminator,\n * for instance:\n *\n * `.filter(typeGuard(p => p.kind === \"in_board\", {} as InBoard))`\n *\n * Normally you'd have to give both type parameters, but you can use\n * the type witness parameter as shown in that example to skip\n * the first type parameter.\n *\n * Also see [[typeGuard]], [[instanceOf]] and [[typeOf]].\n */\nexport function typeGuard<T,U extends T>(predicate:(x:T)=>boolean,\n                                         typeWitness?: U): TypeGuard<T,U> {\n    return <TypeGuard<T,U>>predicate;\n}\n\n/**\n * Curried function returning a type guard telling us if a value\n * is of a specific instance.\n * Can be used when filtering to filter for the type and at the\n * same time change the type of the generics on the container.\n *\n *     Vector.of<any>(\"bad\", new Date('04 Dec 1995 00:12:00 GMT')).filter(instanceOf(Date))\n *     => Vector.of<Date>(new Date('04 Dec 1995 00:12:00 GMT'))\n *\n *     Option.of<any>(\"test\").filter(instanceOf(Date))\n *     => Option.none<Date>()\n *\n *     Option.of<any>(new Date('04 Dec 1995 00:12:00 GMT')).filter(instanceOf(Date))\n *     => Option.of<Date>(new Date('04 Dec 1995 00:12:00 GMT'))\n *\n * Also see [[typeGuard]] and [[typeOf]].\n */\nexport function instanceOf<T>(ctor: new(...args: any[]) => T): TypeGuard<any,T> {\n    // https://github.com/Microsoft/TypeScript/issues/5101#issuecomment-145693151\n    return <TypeGuard<any,T>>(x => x instanceof ctor);\n}\n\n/**\n * Curried function returning a type guard telling us if a value\n * is of a specific type.\n * Can be used when filtering to filter for the type and at the\n * same time change the type of the generics on the container.\n *\n *     Vector.of<any>(1,\"a\",2,3,\"b\").filter(typeOf(\"number\"))\n *     => Vector.of<number>(1,2,3)\n *\n *     Option.of<any>(1).filter(typeOf(\"string\"))\n *     => Option.none<string>()\n *\n *     Option.of<any>(\"str\").filter(typeOf(\"string\"))\n *     => Option.of<string>(\"str\")\n *\n * Also see [[instanceOf]] and [[typeGuard]].\n */\nexport function typeOf(typ: \"string\"): TypeGuard<any,string>;\nexport function typeOf(typ: \"number\"): TypeGuard<any,number>;\nexport function typeOf(typ: \"boolean\"): TypeGuard<any,boolean>;\nexport function typeOf(typ: \"symbol\"): TypeGuard<any,symbol>;\nexport function typeOf(typ: string): TypeGuard<any,any> {\n    return <any>((x:any) => typeof x === typ);\n}\n"
  },
  {
    "path": "src/Contract.ts",
    "content": "import { hasTrueEquality } from \"./Comparison\";\nimport { toStringHelper } from \"./SeqHelpers\";\n\nlet preludeTsContractViolationCb = (msg:string):void => { throw new Error(msg); };\n\n/**\n * Some programmatic errors are only detectable at runtime\n * (for instance trying to setup a <code>HashSet</code> of <code>Option&lt;number[]&gt;</code>: you\n * can't reliably compare a <code>number[]</code> therefore you can't compare\n * an <code>Option&lt;number[]&gt;</code>.. but we can't detect this error at compile-time\n * in typescript). So when we detect them at runtime, prelude-ts throws\n * an exception by default.\n * This function allows you to change that default action\n * (for instance, you could display an error message in the console,\n * or log the error)\n *\n * You can reproduce the issue easily by running for instance:\n *\n *  HashSet.of(Option.of([1]))\n *  => throws\n */\nexport function setContractViolationAction(action: (msg:string)=>void) {\n    preludeTsContractViolationCb = action;\n}\n\n/**\n * @hidden\n */\nexport function reportContractViolation(msg: string): void {\n    preludeTsContractViolationCb(msg);\n}\n\n/**\n * @hidden\n */\nexport function contractTrueEquality(context: string, ...vals: Array<any>) {\n    for (const val of vals) {\n        if (val) {\n            if (val.hasTrueEquality && (!val.hasTrueEquality())) {\n                reportContractViolation(\n                    context + \": element doesn't support true equality: \" + toStringHelper(val));\n            }\n            if (!hasTrueEquality(val).getOrThrow()) {\n                reportContractViolation(\n                    context + \": element doesn't support equality: \" + toStringHelper(val));\n            }\n            // the first element i find is looking good, aborting\n            return;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Either.ts",
    "content": "/**\n * The [[Either]] type represents an alternative between two value types.\n * A \"left\" value which is also conceptually tied to a failure,\n * or a \"right\" value which is conceptually tied to success.\n *\n * The code is organized through the class [[Left]], the class [[Right]],\n * and the type alias [[Either]] (Left or Right).\n *\n * Finally, \"static\" functions on Option are arranged in the class\n * [[EitherStatic]] and are accessed through the global constant Either.\n *\n * Examples:\n *\n *     Either.right<number,number>(5);\n *     Either.left<number,number>(2);\n *     Either.right<number,number>(5).map(x => x*2);\n *\n * Left has the extra [[Left.getLeft]] method that [[Right]] doesn't have.\n * Right has the extra [[Right.get]] method that [[Left]] doesn't have.\n */\n\nimport { Value, inspect } from \"./Value\";\nimport { Option } from \"./Option\";\nimport { LinkedList } from \"./LinkedList\";\nimport { Vector } from \"./Vector\";\nimport { WithEquality, areEqual,\n         hasTrueEquality, getHashCode } from \"./Comparison\";\nimport { contractTrueEquality} from \"./Contract\";\n\n/**\n * Holds the \"static methods\" for [[Either]]\n */\nexport class EitherStatic {\n    /**\n     * Constructs an Either containing a left value which you give.\n     */\n    left<L,R>(val: L): Either<L,R> {\n        return new Left<L,R>(val);\n    }\n\n    /**\n     * Constructs an Either containing a right value which you give.\n     */\n    right<L,R>(val: R): Either<L,R> {\n        return new Right<L,R>(val);\n    }\n\n    /**\n     * Curried type guard for Either\n     * Sometimes needed also due to https://github.com/Microsoft/TypeScript/issues/20218\n     *\n     *     Vector.of(Either.right<number,number>(2), Either.left<number,number>(1))\n     *         .filter(Either.isLeft)\n     *         .map(o => o.getLeft())\n     *     => Vector.of(1)\n     */\n    isLeft<L,R>(e: Either<L,R>): e is Left<L,R> {\n        return e.isLeft();\n    }\n\n    /**\n     * Curried type guard for Either\n     * Sometimes needed also due to https://github.com/Microsoft/TypeScript/issues/20218\n     *\n     *     Vector.of(Either.right<number,number>(2), Either.left<number,number>(1))\n     *         .filter(Either.isRight)\n     *         .map(o => o.get())\n     *     => Vector.of(2)\n     */\n    isRight<L,R>(e: Either<L,R>): e is Right<L,R> {\n        return e.isRight();\n    }\n\n    /**\n     * Turns a list of eithers in an either containing a list of items.\n     * Useful in many contexts.\n     *\n     *     Either.sequence(Vector.of(\n     *         Either.right<number,number>(1),\n     *         Either.right<number,number>(2)));\n     *     => Either.right(Vector.of(1,2))\n     *\n     * But if a single element is Left, everything is discarded:\n     *\n     *     Either.sequence(Vector.of(\n     *           Either.right<number,number>(1),\n     *           Either.left<number,number>(2),\n     *           Either.left<number,number>(3)));\n     *     => Either.left(2)\n     *\n     * Also see [[EitherStatic.traverse]]\n     */\n    sequence<L,R>(elts:Iterable<Either<L,R>>): Either<L,Vector<R>> {\n        return Either.traverse(elts, x=>x);\n    }\n\n    /**\n     * Takes a list, a function that can transform list elements\n     * to eithers, then return an either containing a list of\n     * the transformed elements.\n     *\n     *     const getUserById: (x:number)=>Either<string,string> = x => x > 0 ?\n     *         Either.right(\"user\" + x.toString()) : Either.left(\"invalid id!\");\n     *     Either.traverse([4, 3, 2], getUserById);\n     *     => Either.right(Vector.of(\"user4\", \"user3\", \"user2\"))\n     *\n     * But if a single element results in Left, everything is discarded:\n     *\n     *     const getUserById: (x:number)=>Either<string,string> = x => x > 0 ?\n     *         Either.right(\"user\" + x.toString()) : Either.left(\"invalid id!\");\n     *     Either.traverse([4, -3, 2], getUserById);\n     *     => Either.left(\"invalid id!\")\n     *\n     * Also see [[EitherStatic.sequence]]\n     */\n    traverse<T,L,R>(elts:Iterable<T>, fn: (x:T)=>Either<L,R>): Either<L,Vector<R>> {\n        let r = Vector.empty<R>();\n        const iterator = elts[Symbol.iterator]();\n        let curItem = iterator.next();\n        while (!curItem.done) {\n            const v = fn(curItem.value);\n            if (v.isLeft()) {\n                return <any>v;\n            }\n            r = r.append(v.get());\n            curItem = iterator.next();\n        }\n        return Either.right<L,Vector<R>>(r);\n    }\n\n    /**\n     * Turns a list of eithers in an either containing a list of items.\n     * Compared to [[EitherStatic.sequence]], sequenceAcc 'accumulates'\n     * the errors, instead of short-circuiting on the first error.\n     *\n     *     Either.sequenceAcc(Vector.of(\n     *         Either.right<number,number>(1),\n     *         Either.right<number,number>(2)));\n     *     => Either.right(Vector.of(1,2))\n     *\n     * But if a single element is Left, you get all the lefts:\n     *\n     *     Either.sequenceAcc(Vector.of(\n     *           Either.right<number,number>(1),\n     *           Either.left<number,number>(2),\n     *           Either.left<number,number>(3)));\n     *     => Either.left(Vector.of(2,3))\n     */\n    sequenceAcc<L,R>(elts:Iterable<Either<L,R>>): Either<Vector<L>,Vector<R>> {\n        const [lefts,rights] = Vector.ofIterable(elts).partition(Either.isLeft);\n        if (lefts.isEmpty()) {\n            return Either.right<Vector<L>,Vector<R>>(rights.map(r => r.getOrThrow()));\n        }\n        return Either.left<Vector<L>,Vector<R>>(lefts.map(l => l.getLeft()));\n    }\n\n    /**\n     * Applicative lifting for Either.\n     * Takes a function which operates on basic values, and turns it\n     * in a function that operates on eithers of these values ('lifts'\n     * the function). The 2 is because it works on functions taking two\n     * parameters.\n     *\n     *     const lifted = Either.liftA2(\n     *         (x:number,y:number) => x+y, {} as string);\n     *     lifted(\n     *         Either.right<string,number>(5),\n     *         Either.right<string,number>(6));\n     *     => Either.right(11)\n     *\n     *     const lifted = Either.liftA2(\n     *         (x:number,y:number) => x+y, {} as string);\n     *     lifted(\n     *         Either.right<string,number>(5),\n     *         Either.left<string,number>(\"bad\"));\n     *     => Either.left(\"bad\")\n     *\n     * @param R1 the first right type\n     * @param R2 the second right type\n     * @param L the left type\n     * @param V the new right type as returned by the combining function.\n     */\n    liftA2<R1,R2,L,V>(fn:(v1:R1,v2:R2)=>V, leftWitness?: L) : (p1:Either<L,R1>, p2:Either<L,R2>) => Either<L,V> {\n        return (p1,p2) => p1.flatMap(a1 => p2.map(a2 => fn(a1,a2)));\n    }\n\n    /**\n     * Applicative lifting for Either. 'p' stands for 'properties'.\n     *\n     * Takes a function which operates on a simple JS object, and turns it\n     * in a function that operates on the same JS object type except which each field\n     * wrapped in an Either ('lifts' the function).\n     * It's an alternative to [[EitherStatic.liftA2]] when the number of parameters\n     * is not two.\n     *\n     *     const fn = (x:{a:number,b:number,c:number}) => x.a+x.b+x.c;\n     *     const lifted = Either.liftAp(fn, {} as number);\n     *     lifted({\n     *         a: Either.right<number,number>(5),\n     *         b: Either.right<number,number>(6),\n     *         c: Either.right<number,number>(3)});\n     *     => Either.right(14)\n     *\n     *     const lifted = Either.liftAp<number,{a:number,b:number},number>(\n     *         x => x.a+x.b);\n     *     lifted({\n     *         a: Either.right<number,number>(5),\n     *         b: Either.left<number,number>(2)});\n     *     => Either.left(2)\n     *\n     * @param L the left type\n     * @param A the object property type specifying the parameters for your function\n     * @param B the type returned by your function, returned wrapped in an either by liftAp.\n     */\n    liftAp<L,A,B>(fn:(x:A)=>B, leftWitness?: L): (x: {[K in keyof A]: Either<L,A[K]>;}) => Either<L,B> {\n        return x => {\n            const copy:A = <any>{};\n            for (let p in x) {\n                if (x[p].isLeft()) {\n                    return <Either<L,B>><any>x[p];\n                }\n                copy[p] = x[p].getOrThrow();\n            }\n            return Either.right<L,B>(fn(copy));\n        }\n    }\n\n    /**\n     * Applicative lifting for Either. 'p' stands for 'properties'.\n     * Compared to [[EitherStatic.liftAp]], liftApAcc 'accumulates'\n     * the errors, instead of short-circuiting on the first error.\n     *\n     * Takes a function which operates on a simple JS object, and turns it\n     * in a function that operates on the same JS object type except which each field\n     * wrapped in an Either ('lifts' the function).\n     * It's an alternative to [[EitherStatic.liftA2]] when the number of parameters\n     * is not two.\n     *\n     *     const fn = (x:{a:number,b:number,c:number}) => x.a+x.b+x.c;\n     *     const lifted = Either.liftApAcc(fn, {} as number);\n     *     lifted({\n     *         a: Either.right<number,number>(5),\n     *         b: Either.right<number,number>(6),\n     *         c:Either.right<number,number>(3)});\n     *     => Either.right(14)\n     *\n     *     const fn = (x:{a:number,b:number,c:number}) => x.a+x.b+x.c;\n     *     const lifted = Either.liftApAcc(fn, {} as number);\n     *     lifted({\n     *         a: Either.right<number,number>(5),\n     *         b: Either.left<number,number>(2),\n     *         c: Either.left<number,number>(6)});\n     *     => Either.left(Vector.of(2, 6))\n     *\n     * @param L the left type\n     * @param A the object property type specifying the parameters for your function\n     * @param B the type returned by your function, returned wrapped in an either by liftAp.\n     */\n    liftApAcc<L,A,B>(fn:(x:A)=>B, leftWitness?: L): (x: {[K in keyof A]: Either<L,A[K]>;}) => Either<Vector<L>,B> {\n        const leftErrs: L[] = [];\n        return x => {\n            const copy:A = <any>{};\n            for (let p in x) {\n                const field = x[p];\n                if (field.isLeft()) {\n                    leftErrs.push(field.getLeft());\n                } else {\n                    copy[p] = x[p].getOrThrow();\n                }\n            }\n            if (leftErrs.length === 0) {\n                return Either.right<Vector<L>,B>(fn(copy));\n            } else {\n                return Either.left<Vector<L>,B>(Vector.ofIterable(leftErrs));\n            }\n        }\n    }\n\n    /**\n     * Take a partial function (may return undefined or throw),\n     * and lift it to return an [[Either]] instead.\n     *\n     * Note that unlike the [[OptionStatic.lift]] version, if\n     * the function returns undefined, the Either.lift version will throw\n     * (the Option.lift version returns None()): if you want to do\n     * pure side-effects which may throw, you're better off just using\n     * javascript try blocks.\n     *\n     * When using typescript, to help the compiler infer the left type,\n     * you can either pass a second parameter like `{} as <type>`, or\n     * call with `lift<L,R>(...)`.\n     *\n     *     const add = Either.lift((x:number,y:number) => x+y, {} as string);\n     *     add(1,2);\n     *     => Either.right(3)\n     *\n     *     const undef = Either.lift((x:number,y:number,z:number) => undefined);\n     *     undef(1,2,3);\n     *     => throws\n     *\n     *     const throws = Either.lift(() => {throw \"x\"});\n     *     throws();\n     *     => Either.left(\"x\")\n     */\n    lift<T extends any[],L,U>(fn: (...args: T)=>U, witness?: L): (...args:T)=>Either<L,U> {\n        return (...args:T) => {\n            try {\n                const r = fn(...args);\n                if (r !== undefined) {\n                    return Either.right(r);\n                }\n            } catch (err) {\n                return Either.left(err);\n            }\n            throw new Error(\"liftEither got undefined!\");\n        };\n    }\n\n    /**\n     * Take a no-parameter partial function (may return undefined or throw),\n     * call it, and return an [[Either]] instead.\n     *\n     * Note that unlike the [[OptionStatic.try_]] version, if\n     * the function returns undefined, this function will throw\n     * (the Option.try_ version returns None()): if you want to do\n     * pure side-effects which may throw, you're better off just using\n     * javascript try blocks.\n     *\n     * When using typescript, to help the compiler infer the left type,\n     * you can either pass a second parameter like `{} as <type>`, or\n     * call with `try_<L,R>(...)`.\n     *\n     *     Either.try_(Math.random, {} as string);\n     *     => Either.right(0.49884723907769635)\n     *\n     *     Either.try_(() => undefined);\n     *     => throws\n     *\n     *     Either.try_(() => {throw \"x\"});\n     *     => Either.left(\"x\")\n     *\n     * Also see [[EitherStatic.lift]], [[OptionStatic.try_]],\n     * [[OptionStatic.tryNullable]]\n     */\n    try_<L,T>(fn:()=>T, witness?: L): Either<L,T> {\n        return Either.lift<[],L,T>(fn)();\n    }\n}\n\n/**\n * The Either constant allows to call the either \"static\" methods\n */\nexport const Either = new EitherStatic();\n\n/**\n * Either represents an alternative between two value types.\n * A \"left\" value which is also conceptually tied to a failure,\n * or a \"right\" value which is conceptually tied to success.\n * \"static methods\" available through [[EitherStatic]]\n */\nexport type Either<L,R> = Left<L,R> | Right<L,R>;\n\n/**\n * Represents an [[Either]] containing a left value,\n * conceptually tied to a failure.\n * \"static methods\" available through [[EitherStatic]]\n * @param L the \"left\" item type 'failure'\n * @param R the \"right\" item type 'success'\n */\nexport class Left<L,R> implements Value {\n    constructor(private value: L) {}\n\n    /**\n     * @hidden\n     */\n    readonly className: \"Left\" = <any>undefined;  // https://stackoverflow.com/a/47841595/516188\n\n    /**\n     * Returns true since this is a Left\n     */\n    isLeft(): this is Left<L,R> {\n        return true;\n    }\n\n    /**\n     * Returns false since this is a Left\n     */\n    isRight(): this is Right<L,R> {\n        return false;\n    }\n\n    /**\n     * Returns true if this is either is a right and contains the value you give.\n     */\n    contains(val: R&WithEquality): boolean {\n        return false;\n    }\n\n    /**\n     * If this either is a right, applies the function you give\n     * to its contents and build a new right either, otherwise return this.\n     */\n    map<U>(fn: (x:R)=>U): Either<L,U> {\n        return <any>this;\n    }\n\n    /**\n     * If this either is a right, call the function you give with\n     * the contents, and return what the function returns, else\n     * returns this.\n     * This is the monadic bind.\n     */\n    flatMap<U>(fn: (x:R)=>Either<L,U>): Either<L,U> {\n        return <any>this;\n    }\n\n    /**\n     * If this either is a left, call the function you give with\n     * the left value and return a new either left with the result\n     * of the function, else return this.\n     */\n    mapLeft<U>(fn: (x:L)=>U): Either<U,R> {\n        return new Left<U,R>(fn(this.value));\n    }\n\n    /**\n     * Map the either: you give a function to apply to the value,\n     * a function in case it's a left, a function in case it's a right.\n     */\n    bimap<S,T>(fnL: (x:L)=>S,fnR: (x:R)=>T): Either<S,T> {\n        return new Left<S,T>(fnL(this.value));\n    }\n\n    /**\n     * \"filter\" the either. If it was a Left, it stays a Left.\n     * If it was a Right and the predicate you pass returns\n     * true for its value, return the either unchanged.\n     * But if it was a left and the predicate returns false,\n     * return a Left with the value returned by the function\n     * passed as second parameter.\n     *\n     *     Either.right<string,number>(-3)\n     *         .filter(x => x >= 0, v => \"got negative value: \" + v);\n     *     => Either.left<string,number>(\"got negative value: -3\")\n     */\n    filter(p: (x:R)=>boolean, filterVal: (x:R)=>L): Either<L,R> {\n        return this;\n    }\n\n    /**\n     * Combines two eithers. If this either is a right, returns it.\n     * If it's a left, returns the other one.\n     */\n    orElse(other: Either<L,R>): Either<L,R> {\n        return other;\n    }\n\n    /**\n     * Has no effect if this Either is a right. If it's a left however,\n     * the function you give will be called, receiving as parameter\n     * the left contents, and an Either equivalent to the one your\n     * function returns will be returned.\n     */\n    recoverWith(recoveryFn: (left:L)=>Either<L, R>): Either<L, R> {\n        return recoveryFn(this.value);\n    }\n\n    /**\n     * Execute a side-effecting function if the either\n     * is a right; returns the either.\n     */\n    ifRight(fn: (x:R)=>void): Either<L,R> {\n        return this;\n    }\n\n    /**\n     * Execute a side-effecting function if the either\n     * is a left; returns the either.\n     */\n    ifLeft(fn: (x:L)=>void): Either<L,R> {\n        fn(this.value);\n        return this;\n    }\n\n    /**\n     * Handle both branches of the either and return a value\n     * (can also be used for side-effects).\n     * This is the catamorphism for either.\n     *\n     *     Either.right<string,number>(5).match({\n     *         Left:  x => \"left \" + x,\n     *         Right: x => \"right \" + x\n     *     });\n     *     => \"right 5\"\n     */\n    match<U>(cases: {Left: (v:L)=>U, Right: (v:R)=>U}): U {\n        return cases.Left(this.value);\n    }\n\n    /**\n     * If this either is a right, return its value, else throw\n     * an exception.\n     * You can optionally pass a message that'll be used as the\n     * exception message, or an Error object.\n     */\n    getOrThrow(errorInfo?: Error|string): R {\n        if (typeof errorInfo === 'string') {\n            throw new Error(errorInfo || \"Left.getOrThrow called!\");\n        }\n        throw errorInfo || new Error(\"Left.getOrThrow called!\");\n    }\n\n    /**\n     * If this either is a right, return its value, else return\n     * the value you give.\n     */\n    getOrElse(other: R): R {\n        return other;\n    }\n\n    /**\n     * Get the value contained in this left.\n     * NOTE: we know it's there, since this method\n     * belongs to Left, not Either.\n     */\n    getLeft(): L {\n        return this.value;\n    }\n\n    /**\n     * If this either is a left, return its value, else throw\n     * an exception.\n     * You can optionally pass a message that'll be used as the\n     * exception message.\n     */\n    getLeftOrThrow(message?: string): L {\n        return this.value;\n    }\n\n    /**\n     * If this either is a left, return its value, else return\n     * the value you give.\n     */\n    getLeftOrElse(other: L): L {\n        return this.value;\n    }\n\n    /**\n     * Convert this either to an option, conceptually dropping\n     * the left (failing) value.\n     */\n    toOption(): Option<R> {\n        return Option.none<R>();\n    }\n\n    /**\n     * Convert to a vector. If it's a left, it's the empty\n     * vector, if it's a right, it's a one-element vector with\n     * the contents of the either.\n     */\n    toVector(): Vector<R> {\n        return Vector.empty<R>();\n    }\n\n    /**\n     * Convert to a list. If it's a left, it's the empty\n     * list, if it's a right, it's a one-element list with\n     * the contents of the either.\n     */\n    toLinkedList(): LinkedList<R> {\n        return LinkedList.empty<R>();\n    }\n\n    /**\n     * Transform this value to another value type.\n     * Enables fluent-style programming by chaining calls.\n     */\n    transform<U>(converter:(x:Either<L,R>)=>U): U {\n        return converter(this);\n    }\n\n    hasTrueEquality(): boolean {\n        return (this.value && (<any>this.value).hasTrueEquality) ?\n            (<any>this.value).hasTrueEquality() :\n            hasTrueEquality(this.value);\n    }\n\n    /**\n     * Get a number for that object. Two different values\n     * may get the same number, but one value must always get\n     * the same number. The formula can impact performance.\n     */\n    hashCode(): number {\n        return getHashCode(this.value);\n    }\n\n    /**\n     * Two objects are equal if they represent the same value,\n     * regardless of whether they are the same object physically\n     * in memory.\n     */\n    equals(other: Either<L&WithEquality,R&WithEquality>): boolean {\n        if (<any>other === this) {\n            return true;\n        }\n        if ((!other) || (!other.isRight) || other.isRight()) {\n            return false;\n        }\n        const leftOther = <Left<L&WithEquality,R&WithEquality>>other;\n        contractTrueEquality(\"Either.equals\", this, leftOther);\n        return areEqual(this.value, leftOther.value);\n    }\n\n    /**\n     * Get a human-friendly string representation of that value.\n     */\n    toString(): string {\n        return \"Left(\" + this.value + \")\";\n    }\n\n    /**\n     * Used by the node REPL to display values.\n     */\n    [inspect](): string {\n        return this.toString();\n    }\n}\n\n/**\n * Represents an [[Either]] containing a success value,\n * conceptually tied to a success.\n * \"static methods\" available through [[EitherStatic]]\n * @param L the \"left\" item type 'failure'\n * @param R the \"right\" item type 'success'\n */\nexport class Right<L,R> implements Value {\n    constructor(private value: R) {}\n\n    /**\n     * @hidden\n     */\n    readonly className: \"Right\" = <any>undefined;  // https://stackoverflow.com/a/47841595/516188\n\n    /**\n     * Returns false since this is a Right\n     */\n    isLeft(): this is Left<L,R> {\n        return false;\n    }\n\n    /**\n     * Returns true since this is a Right\n     */\n    isRight(): this is Right<L,R> {\n        return true;\n    }\n\n    /**\n     * Returns true if this is either is a right and contains the value you give.\n     */\n    contains(val: R&WithEquality): boolean {\n        return areEqual(this.value, val);\n    }\n\n    /**\n     * If this either is a right, applies the function you give\n     * to its contents and build a new right either, otherwise return this.\n     */\n    map<U>(fn: (x:R)=>U): Either<L,U> {\n        return new Right<L,U>(fn(this.value));\n    }\n\n    /**\n     * If this either is a right, call the function you give with\n     * the contents, and return what the function returns, else\n     * returns this.\n     * This is the monadic bind.\n     */\n    flatMap<U>(fn: (x:R)=>Either<L,U>): Either<L,U> {\n        return fn(this.value);\n    }\n\n    /**\n     * If this either is a left, call the function you give with\n     * the left value and return a new either left with the result\n     * of the function, else return this.\n     */\n    mapLeft<U>(fn: (x:L)=>U): Either<U,R> {\n        return <any>this;\n    }\n\n    /**\n     * Map the either: you give a function to apply to the value,\n     * a function in case it's a left, a function in case it's a right.\n     */\n    bimap<S,T>(fnL: (x:L)=>S,fnR: (x:R)=>T): Either<S,T> {\n        return new Right<S,T>(fnR(this.value));\n    }\n\n    /**\n     * \"filter\" the either. If it was a Left, it stays a Left.\n     * If it was a Right and the predicate you pass returns\n     * true for its value, return the either unchanged.\n     * But if it was a left and the predicate returns false,\n     * return a Left with the value returned by the function\n     * passed as second parameter.\n     *\n     *     Either.right<string,number>(-3)\n     *         .filter(x => x >= 0, v => \"got negative value: \" + v);\n     *     => Either.left<string,number>(\"got negative value: -3\")\n     */\n    filter(p: (x:R)=>boolean, filterVal: (x:R)=>L): Either<L,R> {\n        if (p(this.value)) {\n            return this;\n        }\n        return new Left(filterVal(this.value));\n    }\n\n    /**\n     * Combines two eithers. If this either is a right, returns it.\n     * If it's a left, returns the other one.\n     */\n    orElse(other: Either<L,R>): Either<L,R> {\n        return this;\n    }\n    \n    /**\n     * Has no effect if this Either is a right. If it's a left however,\n     * the function you give will be called, receiving as parameter\n     * the left contents, and an Either equivalent to the one your\n     * function returns will be returned.\n     */\n    recoverWith(recoveryFn: (left:L)=>Either<L, R>): Either<L, R> {\n        return this;\n    }\n\n    /**\n     * Execute a side-effecting function if the either\n     * is a right; returns the either.\n     */\n    ifRight(fn: (x:R)=>void): Either<L,R> {\n        fn(this.value);\n        return this;\n    }\n\n    /**\n     * Execute a side-effecting function if the either\n     * is a left; returns the either.\n     */\n    ifLeft(fn: (x:L)=>void): Either<L,R> {\n        return this;\n    }\n\n    /**\n     * Handle both branches of the either and return a value\n     * (can also be used for side-effects).\n     * This is the catamorphism for either.\n     *\n     *     Either.right<string,number>(5).match({\n     *         Left:  x => \"left \" + x,\n     *         Right: x => \"right \" + x\n     *     });\n     *     => \"right 5\"\n     */\n    match<U>(cases: {Left: (v:L)=>U, Right: (v:R)=>U}): U {\n        return cases.Right(this.value);\n    }\n\n    /**\n     * Get the value contained in this right.\n     * NOTE: we know it's there, since this method\n     * belongs to Right, not Either.\n     */\n    get(): R {\n        return this.value;\n    }\n\n    /**\n     * If this either is a right, return its value, else throw\n     * an exception.\n     * You can optionally pass a message that'll be used as the\n     * exception message, or an Error object.\n     */\n    getOrThrow(errorInfo?: Error|string): R {\n        return this.value;\n    }\n\n    /**\n     * If this either is a right, return its value, else return\n     * the value you give.\n     */\n    getOrElse(other: R): R {\n        return this.value;\n    }\n\n    /**\n     * If this either is a left, return its value, else throw\n     * an exception.\n     * You can optionally pass a message that'll be used as the\n     * exception message.\n     */\n    getLeftOrThrow(message?: string): L {\n        throw message || \"Left.getOrThrow called!\";\n    }\n\n    /**\n     * If this either is a left, return its value, else return\n     * the value you give.\n     */\n    getLeftOrElse(other: L): L {\n        return other;\n    }\n\n    /**\n     * Convert this either to an option, conceptually dropping\n     * the left (failing) value.\n     */\n    toOption(): Option<R> {\n        return Option.of(this.value);\n    }\n\n    /**\n     * Convert to a vector. If it's a left, it's the empty\n     * vector, if it's a right, it's a one-element vector with\n     * the contents of the either.\n     */\n    toVector(): Vector<R> {\n        return Vector.of(this.value);\n    }\n\n    /**\n     * Convert to a list. If it's a left, it's the empty\n     * list, if it's a right, it's a one-element list with\n     * the contents of the either.\n     */\n    toLinkedList(): LinkedList<R> {\n        return LinkedList.of(this.value);\n    }\n\n    /**\n     * Transform this value to another value type.\n     * Enables fluent-style programming by chaining calls.\n     */\n    transform<U>(converter:(x:Either<L,R>)=>U): U {\n        return converter(this);\n    }\n\n    hasTrueEquality(): boolean {\n        return (this.value && (<any>this.value).hasTrueEquality) ?\n            (<any>this.value).hasTrueEquality() :\n            hasTrueEquality(this.value);\n    }\n\n    /**\n     * Get a number for that object. Two different values\n     * may get the same number, but one value must always get\n     * the same number. The formula can impact performance.\n     */\n    hashCode(): number {\n        return getHashCode(this.value);\n    }\n\n    /**\n     * Two objects are equal if they represent the same value,\n     * regardless of whether they are the same object physically\n     * in memory.\n     */\n    equals(other: Either<L&WithEquality,R&WithEquality>): boolean {\n        if (<any>other === this) {\n            return true;\n        }\n        if ((!other) || (!other.isRight) || (!other.isRight())) {\n            return false;\n        }\n        const rightOther = <Right<L&WithEquality,R&WithEquality>>other;\n        contractTrueEquality(\"Either.equals\", this, rightOther);\n        return areEqual(this.value, rightOther.value);\n    }\n\n    /**\n     * Get a human-friendly string representation of that value.\n     */\n    toString(): string {\n        return \"Right(\" + this.value + \")\";\n    }\n\n    /**\n     * Used by the node REPL to display values.\n     */\n    [inspect](): string {\n        return this.toString();\n    }\n}\n"
  },
  {
    "path": "src/Foldable.ts",
    "content": "import { Option } from \"./Option\";\n\nexport interface Foldable<T> {\n\n    /**\n     * Reduces the collection to a single value using the\n     * associative binary function you give. Since the function\n     * is associative, order of application doesn't matter.\n     *\n     * Example:\n     *\n     *     HashSet.of(1,2,3).fold(0, (a,b) => a + b);\n     *     => 6\n     */\n    fold(zero:T, fn:(v1:T,v2:T)=>T): T;\n\n    /**\n     * Reduces the collection to a single value.\n     * Left-associative.\n     *\n     * Example:\n     *\n     *     Vector.of(\"a\", \"b\", \"c\").foldLeft(\"!\", (xs,x) => x+xs);\n     *     => \"cba!\"\n     *\n     * @param zero The initial value\n     * @param fn A function taking the previous value and\n     *           the current collection item, and returning\n     *           an updated value.\n     */\n    foldLeft<U>(zero: U, fn:(soFar:U,cur:T)=>U): U;\n\n    /**\n     * Reduces the collection to a single value.\n     * Right-associative.\n     *\n     * Example:\n     *\n     *     Vector.of(\"a\", \"b\", \"c\").foldRight(\"!\", (x,xs) => xs+x)\n     *     => \"!cba\"\n     *\n     * @param zero The initial value\n     * @param fn A function taking the current collection item and\n     *           the previous value , and returning\n     *           an updated value.\n     */\n    foldRight<U>(zero: U, fn:(cur:T, soFar:U)=>U): U;\n\n    /**\n     * Reduces the collection to a single value by repeatedly\n     * calling the combine function.\n     * No starting value. The order in which the elements are\n     * passed to the combining function is undetermined.\n     */\n    reduce(combine: (v1:T,v2:T)=>T): Option<T>;\n}\n"
  },
  {
    "path": "src/Function.ts",
    "content": "/**\n * Rich functions with helpers such as [[Function1.andThen]],\n * [[Function2.apply1]] and so on.\n *\n * We support functions of arities up to 5. For each arity, we have\n * the interface ([[Function1]], [[Function2]], ...), builders are on functions\n * on [[Function1Static]], [[Function2Static]]... accessible on constants\n * named Function1, Function2,...\n *\n * Examples:\n *\n *     const combined = Function1.of((x:number)=>x+2).andThen(x=>x*3);\n *     combined(6);\n *     => 24\n *\n *     const plus5 = Function2.of((x:number,y:number)=>x+y).apply1(5);\n *     plus5(1);\n *     => 6\n */\n\n/**\n * Function0 encapsulates a parameterless function\n * which returns a value. It adds some useful functions\n * to combine or transform functions.\n *\n * @param T the parameter type\n * @param U the result type\n */\nexport interface Function0<R> {\n\n    /**\n     * Invoke the function\n     */\n    (): R;\n\n    /**\n     * Returns a new composed function which first calls the current\n     * function and then the one you pass as parameter.\n     */\n    andThen<V>(fn:(x:R)=>V): Function0<V>;\n}\n\n/**\n * Function1 encapsulates a function taking a single parameter\n * and returning a value. It adds some useful functions\n * to combine or transform functions.\n *\n * @param T the parameter type\n * @param U the result type\n */\nexport interface Function1<T,U> {\n\n    /**\n     * Invoke the function\n     */\n    (x:T): U;\n\n    /**\n     * Returns a new composed function which first applies the current\n     * function and then the one you pass as parameter.\n     */\n    andThen<V>(fn:(x:U)=>V): Function1<T,V>;\n\n    /**\n     *\n     */\n    compose<S>(fn:(x:S)=>T): Function1<S,U>;\n}\n\n/**\n * Function2 encapsulates a function taking two parameters\n * and returning a value. It adds some useful functions\n * to combine or transform functions.\n *\n * @param T1 the first parameter type\n * @param T2 the second parameter type\n * @param R the result type\n */\nexport interface Function2<T1,T2,R> {\n\n    /**\n     * Invoke the function\n     */\n    (x:T1,y:T2): R;\n\n    /**\n     * Returns a new composed function which first applies the current\n     * function and then the one you pass as parameter.\n     */\n    andThen<V>(fn:(x:R)=>V): Function2<T1,T2,V>;\n\n    /**\n     * Returns a curried version of this function, for example:\n     *\n     *     const plus5 = Function2.of(\n     *         (x:number,y:number)=>x+y)\n     *            .curried()(5);\n     *     assert.equal(6, plus5(1));\n     */\n    curried(): Function1<T1,Function1<T2,R>>;\n\n    /**\n     * Returns a version of this function which takes a tuple\n     * instead of individual parameters. Useful in combination\n     * with [[Vector.zip]] for instance.\n     */\n    tupled(): Function1<[T1,T2],R>;\n\n    /**\n     * Returns a version of this function taking its parameters\n     * in the reverse order.\n     */\n    flipped(): Function2<T2,T1,R>;\n\n    /**\n     * Applies this function partially to one argument.\n     *\n     *     const plus5 = Function2.of(\n     *         (x:number,y:number)=>x+y)\n     *            .apply1(5);\n     *     assert.equal(6, plus5(1));\n     */\n    apply1(param1:T1): Function1<T2,R>;\n}\n\n/**\n * Function3 encapsulates a function taking three parameters\n * and returning a value. It adds some useful functions\n * to combine or transform functions.\n *\n * @param T1 the first parameter type\n * @param T2 the second parameter type\n * @param T3 the third parameter type\n * @param R the result type\n */\nexport interface Function3<T1,T2,T3,R> {\n\n    /**\n     * Invoke the function\n     */\n    (x:T1,y:T2,z:T3): R;\n\n    /**\n     * Returns a new composed function which first applies the current\n     * function and then the one you pass as parameter.\n     */\n    andThen<V>(fn:(x:R)=>V): Function3<T1,T2,T3,V>;\n\n    /**\n     * Returns a curried version of this function, for example:\n     * See [[Function2.curried]]\n     */\n    curried(): Function1<T1,Function1<T2,Function1<T3,R>>>;\n\n    /**\n     * Returns a version of this function which takes a tuple\n     * instead of individual parameters.\n     */\n    tupled(): Function1<[T1,T2,T3],R>;\n\n    /**\n     * Returns a version of this function taking its parameters\n     * in the reverse order.\n     */\n    flipped(): Function3<T3,T2,T1,R>;\n\n    /**\n     * Applies this function partially to one argument.\n     *\n     *     const plus5 = Function3.of(\n     *         (x:number,y:number,z:number)=>x+y+z)\n     *            .apply1(5);\n     *     assert.equal(8, plus5(1,2));\n     */\n    apply1(param1:T1): Function2<T2,T3,R>;\n\n    /**\n     * Applies this function partially to two arguments.\n     *\n     *     const plus54 = Function3.of(\n     *         (x:number,y:number,z:number)=>x+y+z)\n     *            .apply2(5,4);\n     *     assert.equal(12, plus54(3));\n     */\n    apply2(param1:T1, param2: T2): Function1<T3,R>;\n}\n\n/**\n * Function4 encapsulates a function taking four parameters\n * and returning a value. It adds some useful functions\n * to combine or transform functions.\n *\n * @param T1 the first parameter type\n * @param T2 the second parameter type\n * @param T3 the third parameter type\n * @param T4 the fourth parameter type\n * @param R the result type\n */\nexport interface Function4<T1,T2,T3,T4,R> {\n\n    /**\n     * Invoke the function\n     */\n    (x:T1,y:T2,z:T3,a:T4): R;\n\n    /**\n     * Returns a new composed function which first applies the current\n     * function and then the one you pass as parameter.\n     */\n    andThen<V>(fn:(x:R)=>V): Function4<T1,T2,T3,T4,V>;\n\n    /**\n     * Returns a curried version of this function, for example:\n     * See [[Function2.curried]]\n     */\n    curried(): Function1<T1,Function1<T2,Function1<T3,Function1<T4,R>>>>;\n\n    /**\n     * Returns a version of this function which takes a tuple\n     * instead of individual parameters.\n     */\n    tupled(): Function1<[T1,T2,T3,T4],R>;\n\n    /**\n     * Returns a version of this function taking its parameters\n     * in the reverse order.\n     */\n    flipped(): Function4<T4,T3,T2,T1,R>;\n\n    /**\n     * Applies this function partially to one argument.\n     *\n     *     const plus5 = Function4.of(\n     *         (x:number,y:number,z:number,a:number)=>x+y+z+a)\n     *            .apply1(5);\n     *     assert.equal(11, plus5(1,2,3));\n     */\n    apply1(param1:T1): Function3<T2,T3,T4,R>;\n\n    /**\n     * Applies this function partially to two arguments.\n     *\n     *     const plus51 = Function4.of(\n     *         (x:number,y:number,z:number,a:number)=>x+y+z+a)\n     *            .apply2(5,1);\n     *     assert.equal(11, plus51(2,3));\n     */\n    apply2(param1:T1, param2: T2): Function2<T3,T4,R>;\n\n    /**\n     * Applies this function partially to three arguments.\n     *\n     *     const plus512 = Function4.of(\n     *         (x:number,y:number,z:number,a:number)=>x+y+z+a)\n     *            .apply3(5,1,2);\n     *     assert.equal(11, plus512(3));\n     */\n    apply3(param1:T1, param2: T2, param3: T3): Function1<T4,R>;\n}\n\n/**\n * Function5 encapsulates a function taking give parameters\n * and returning a value. It adds some useful functions\n * to combine or transform functions.\n *\n * @param T1 the first parameter type\n * @param T2 the second parameter type\n * @param T3 the third parameter type\n * @param T4 the fourth parameter type\n * @param T5 the fifth parameter type\n * @param R the result type\n */\nexport interface Function5<T1,T2,T3,T4,T5,R> {\n\n    /**\n     * Invoke the function\n     */\n    (x:T1,y:T2,z:T3,a:T4,b:T5): R;\n\n    /**\n     * Returns a new composed function which first applies the current\n     * function and then the one you pass as parameter.\n     */\n    andThen<V>(fn:(x:R)=>V): Function5<T1,T2,T3,T4,T5,V>;\n\n    /**\n     * Returns a curried version of this function, for example:\n     * See [[Function2.curried]]\n     */\n    curried(): Function1<T1,Function1<T2,Function1<T3,Function1<T4,Function1<T5,R>>>>>;\n\n    /**\n     * Returns a version of this function which takes a tuple\n     * instead of individual parameters.\n     */\n    tupled(): Function1<[T1,T2,T3,T4,T5],R>;\n\n    /**\n     * Returns a version of this function taking its parameters\n     * in the reverse order.\n     */\n    flipped(): Function5<T5,T4,T3,T2,T1,R>;\n\n    /**\n     * Applies this function partially to one argument.\n     *\n     *     const plus5 = Function5.of(\n     *         (x:number,y:number,z:number,a:number,b:number)=>x+y+z+a+b)\n     *            .apply1(5);\n     *     assert.equal(15, plus5(1,2,3,4));\n     */\n    apply1(param1:T1): Function4<T2,T3,T4,T5,R>;\n\n    /**\n     * Applies this function partially to two arguments.\n     *\n     *     const plus51 = Function5.of(\n     *         (x:number,y:number,z:number,a:number,b:number)=>x+y+z+a+b)\n     *            .apply2(5,1);\n     *     assert.equal(15, plus51(2,3,4));\n     */\n    apply2(param1:T1, param2: T2): Function3<T3,T4,T5,R>;\n\n    /**\n     * Applies this function partially to three arguments.\n     *\n     *     const plus512 = Function5.of(\n     *         (x:number,y:number,z:number,a:number,b:number)=>x+y+z+a+b)\n     *            .apply3(5,1,2);\n     *     assert.equal(15, plus512(3,4));\n     */\n    apply3(param1:T1, param2: T2, param3: T3): Function2<T4,T5,R>;\n\n    /**\n     * Applies this function partially to four arguments.\n     *\n     *     const plus5123 = Function5.of(\n     *         (x:number,y:number,z:number,a:number,b:number)=>x+y+z+a+b)\n     *            .apply4(5,1,2,3);\n     *     assert.equal(15, plus5123(4));\n     */\n    apply4(param1:T1, param2: T2, param3: T3, param4: T4): Function1<T5,R>;\n}\n\n/**\n * This is the type of the Function0 constant, which\n * offers some helper functions to deal\n * with [[Function0]] including\n * the ability to build [[Function0]]\n * from functions using [[Function0Static.of]].\n * It also offers some builtin functions like [[Function0Static.constant]].\n */\nexport class Function0Static {\n\n    /**\n     * The constant function of one parameter:\n     * will always return the value you give, no\n     * matter the parameter it's given.\n     */\n    constant<R>(val:R): Function0<R> {\n        return Function0.of(()=>val);\n    }\n\n    /**\n     * Take a one-parameter function and lift it to become a [[Function1Static]],\n     * enabling you to call [[Function1.andThen]] and other such methods on it.\n     */\n    of<R>(fn:()=>R): Function0<R> {\n        const r = <Function0<R>>(() => fn());\n        r.andThen = <V>(fn2:(x:R)=>V) => Function0.of(() => fn2(r()));\n        return r;\n    }\n}\n\n/**\n * The Function1 constant allows to call the [[Function0]] \"static\" methods.\n */\nexport const Function0 = new Function0Static();\n\n/**\n * This is the type of the Function1 constant, which\n * offers some helper functions to deal\n * with [[Function1]] including\n * the ability to build [[Function1]]\n * from functions using [[Function1Static.of]].\n * It also offers some builtin functions like [[Function1Static.constant]].\n */\nexport class Function1Static {\n\n    /**\n     * The identity function.\n     */\n    id<T>(): Function1<T,T> {\n        return Function1.of((x:T)=>x);\n    }\n\n    /**\n     * The constant function of one parameter:\n     * will always return the value you give, no\n     * matter the parameter it's given.\n     */\n    constant<U,T>(val:T): Function1<U,T> {\n        return Function1.of((x:U)=>val);\n    }\n\n    /**\n     * Take a one-parameter function and lift it to become a [[Function1Static]],\n     * enabling you to call [[Function1.andThen]] and other such methods on it.\n     */\n    of<T,U>(fn:(x:T)=>U): Function1<T,U> {\n        const r = <Function1<T,U>>(x => fn(x));\n        r.andThen = <V>(fn2:(x:U)=>V) => Function1.of((x:T) => fn2(r(x)));\n        r.compose = <S>(fn2:(x:S)=>T) => Function1.of((x:S) => r(fn2(x)));\n        return r;\n    }\n}\n\n/**\n * The Function1 constant allows to call the [[Function1]] \"static\" methods.\n */\nexport const Function1 = new Function1Static();\n\n/**\n * This is the type of the Function2 constant, which\n * offers some helper functions to deal\n * with [[Function2]] including\n * the ability to build [[Function2]]\n * from functions using [[Function2Static.of]].\n * It also offers some builtin functions like [[Function2Static.constant]].\n */\nexport class Function2Static {\n    /**\n     * The constant function of two parameters:\n     * will always return the value you give, no\n     * matter the parameters it's given.\n     */\n    constant<T1,T2,R>(val:R): Function2<T1,T2,R> {\n        return Function2.of((x:T1,y:T2)=>val);\n    }\n\n    /**\n     * Take a two-parameter function and lift it to become a [[Function2]],\n     * enabling you to call [[Function2.andThen]] and other such methods on it.\n     */\n    of<T1,T2,R>(fn:(x:T1,y:T2)=>R): Function2<T1,T2,R> {\n        const r = <Function2<T1,T2,R>>((x,y)=>fn(x,y));\n        r.andThen = <V>(fn2:(x:R)=>V) => Function2.of((x:T1,y:T2) => fn2(r(x,y)));\n        r.curried = () => Function1.of((x:T1) => Function1.of((y:T2) => r(x,y)));\n        r.tupled = () => Function1.of((pair:[T1,T2]) => r(pair[0],pair[1]));\n        r.flipped = () => Function2.of((x:T2,y:T1) => r(y,x));\n        r.apply1 = (x:T1) => Function1.of((y:T2) => r(x,y));\n        return r;\n    }\n}\n\n/**\n * The Function2 constant allows to call the [[Function2]] \"static\" methods.\n */\nexport const Function2 = new Function2Static();\n\n/**\n * This is the type of the Function3 constant, which\n * offers some helper functions to deal\n * with [[Function3]] including\n * the ability to build [[Function3]]\n * from functions using [[Function3Static.of]].\n * It also offers some builtin functions like [[Function3Static.constant]].\n */\nexport class Function3Static {\n    /**\n     * The constant function of three parameters:\n     * will always return the value you give, no\n     * matter the parameters it's given.\n     */\n    constant<T1,T2,T3,R>(val:R): Function3<T1,T2,T3,R> {\n        return Function3.of((x:T1,y:T2,z:T3)=>val);\n    }\n\n    /**\n     * Take a three-parameter function and lift it to become a [[Function3]],\n     * enabling you to call [[Function3.andThen]] and other such methods on it.\n     */\n    of<T1,T2,T3,R>(fn:(x:T1,y:T2,z:T3)=>R): Function3<T1,T2,T3,R> {\n        const r = <Function3<T1,T2,T3,R>>((x,y,z)=>fn(x,y,z));\n        r.andThen = <V>(fn2:(x:R)=>V) => Function3.of((x:T1,y:T2,z:T3) => fn2(r(x,y,z)));\n        r.curried = () => Function1.of((x:T1) => Function1.of((y:T2) => Function1.of((z:T3) => r(x,y,z))));\n        r.tupled = () => Function1.of((tuple:[T1,T2,T3]) => r(tuple[0],tuple[1],tuple[2]));\n        r.flipped = () => Function3.of((x:T3,y:T2,z:T1) => r(z,y,x));\n        r.apply1 = (x:T1) => Function2.of((y:T2,z:T3) => r(x,y,z));\n        r.apply2 = (x:T1,y:T2) => Function1.of((z:T3) => r(x,y,z));\n        return r;\n    }\n}\n\n/**\n * The Function3 constant allows to call the [[Function3]] \"static\" methods.\n */\nexport const Function3 = new Function3Static();\n\n/**\n * This is the type of the Function4 constant, which\n * offers some helper functions to deal\n * with [[Function4]] including\n * the ability to build [[Function4]]\n * from functions using [[Function4Static.of]].\n * It also offers some builtin functions like [[Function4Static.constant]].\n */\nexport class Function4Static {\n\n    /**\n     * The constant function of four parameters:\n     * will always return the value you give, no\n     * matter the parameters it's given.\n     */\n    constant<T1,T2,T3,T4,R>(val:R): Function4<T1,T2,T3,T4,R> {\n        return Function4.of((x:T1,y:T2,z:T3,a:T4)=>val);\n    }\n\n    /**\n     * Take a four-parameter function and lift it to become a [[Function4]],\n     * enabling you to call [[Function4.andThen]] and other such methods on it.\n     */\n    of<T1,T2,T3,T4,R>(fn:(x:T1,y:T2,z:T3,a:T4)=>R): Function4<T1,T2,T3,T4,R> {\n        const r = <Function4<T1,T2,T3,T4,R>>((x,y,z,a)=>fn(x,y,z,a));\n        r.andThen = <V>(fn2:(x:R)=>V) => Function4.of((x:T1,y:T2,z:T3,a:T4) => fn2(r(x,y,z,a)));\n        r.curried = () => Function1.of((x:T1) => Function1.of(\n            (y:T2) => Function1.of((z:T3) => Function1.of((a:T4)=>r(x,y,z,a)))));\n        r.tupled = () => Function1.of((tuple:[T1,T2,T3,T4]) => r(tuple[0],tuple[1],tuple[2],tuple[3]));\n        r.flipped = () => Function4.of((x:T4,y:T3,z:T2,a:T1) => r(a,z,y,x));\n        r.apply1 = (x:T1) => Function3.of((y:T2,z:T3,a:T4) => r(x,y,z,a));\n        r.apply2 = (x:T1,y:T2) => Function2.of((z:T3,a:T4) => r(x,y,z,a));\n        r.apply3 = (x:T1,y:T2,z:T3) => Function1.of((a:T4) => r(x,y,z,a));\n        return r;\n    }\n\n};\n\n/**\n * The Function4 constant allows to call the [[Function4]] \"static\" methods.\n */\nexport const Function4 = new Function4Static();\n\n/**\n * This is the type of the Function5 constant, which\n * offers some helper functions to deal\n * with [[Function5]] including\n * the ability to build [[Function5]]\n * from functions using [[Function5Static.of]].\n * It also offers some builtin functions like [[Function5Static.constant]].\n */\nexport class Function5Static {\n    /**\n     * The constant function of five parameters:\n     * will always return the value you give, no\n     * matter the parameters it's given.\n     */\n    constant<T1,T2,T3,T4,T5,R>(val:R): Function5<T1,T2,T3,T4,T5,R> {\n        return Function5.of((x:T1,y:T2,z:T3,a:T4,b:T5)=>val);\n    }\n\n    /**\n     * Take a five-parameter function and lift it to become a [[Function5]],\n     * enabling you to call [[Function5.andThen]] and other such methods on it.\n     */\n    of<T1,T2,T3,T4,T5,R>(fn:(x:T1,y:T2,z:T3,a:T4,b:T5)=>R): Function5<T1,T2,T3,T4,T5,R> {\n        const r = <Function5<T1,T2,T3,T4,T5,R>>((x,y,z,a,b)=>fn(x,y,z,a,b));\n        r.andThen = <V>(fn2:(x:R)=>V) => Function5.of((x:T1,y:T2,z:T3,a:T4,b:T5) => fn2(r(x,y,z,a,b)));\n        r.curried = () => Function1.of((x:T1) => Function1.of(\n            (y:T2) => Function1.of((z:T3) => Function1.of((a:T4)=>Function1.of((b:T5) => r(x,y,z,a,b))))));\n        r.tupled = () => Function1.of((tuple:[T1,T2,T3,T4,T5]) => r(tuple[0],tuple[1],tuple[2],tuple[3],tuple[4]));\n        r.flipped = () => Function5.of((x:T5,y:T4,z:T3,a:T2,b:T1) => r(b,a,z,y,x));\n        r.apply1 = (x:T1) => Function4.of((y:T2,z:T3,a:T4,b:T5) => r(x,y,z,a,b));\n        r.apply2 = (x:T1,y:T2) => Function3.of((z:T3,a:T4,b:T5) => r(x,y,z,a,b));\n        r.apply3 = (x:T1,y:T2,z:T3) => Function2.of((a:T4,b:T5) => r(x,y,z,a,b));\n        r.apply4 = (x:T1,y:T2,z:T3,a:T4) => Function1.of((b:T5) => r(x,y,z,a,b));\n        return r;\n    }\n}\n\n/**\n * The Function5 constant allows to call the [[Function5]] \"static\" methods.\n */\nexport const Function5 = new Function5Static();\n"
  },
  {
    "path": "src/Future.ts",
    "content": "import { Vector } from \"./Vector\";\nimport { Option } from \"./Option\";\nimport { Either } from \"./Either\";\nimport { HashMap } from \"./HashMap\";\n\n/**\n * A Future is the equivalent, and ultimately wraps, a javascript Promise.\n * While Futures support the [[Future.then]] call (so that among others\n * you can use `await` on them), you should call [[Future.map]] and\n * [[Future.flatMap]].\n *\n * Futures represent an asynchronous computation. A Future will only ever\n * be computed once at most. Once it's computed, calling [[Future.map]] or\n * `await` will return instantly.\n */\nexport class Future<T> {\n\n    // careful cause i can't have my type be F<F<T>>\n    // while the code does F<T> as JS's then does!!!\n    // for that reason I wrap the value in an array\n    // to make sure JS will never turn a Promise<Promise<T>>\n    // in a Promise<T>\n    private constructor(private promise: Promise<T[]>) { }\n\n    /**\n     * Build a Future in the same way as the 'new Promise'\n     * constructor.\n     * You get one callback to signal success (resolve),\n     * failure (reject), or you can throw to signal failure.\n     *\n     *     Future.ofPromiseCtor<string>((resolve,reject) => setTimeout(resolve, 10, \"hello!\"))\n     */\n    static ofPromiseCtor<T>(executor: (resolve:(x:T)=>void, reject: (x:any)=>void)=>void): Future<T> {\n        return new Future(new Promise(executor).then(v=>[v]));\n    }\n\n    /**\n     * Build a Future from an existing javascript Promise.\n     */\n    static of<T>(promise: Promise<T>): Future<T> {\n        return new Future(promise.then(x => [x]));\n    }\n\n    /**\n     * Build a Future from a node-style callback API, for instance:\n     *\n     *     Future.ofCallback<string>(cb => fs.readFile('/etc/passwd', 'utf-8', cb))\n     */\n    static ofCallback<T>(fn: (cb:(err:any, val:T)=>void)=>void): Future<T> {\n        return Future.ofPromiseCtor((resolve,reject)=>fn((err, data)=>{\n            if (err) {\n                reject(err);\n            } else {\n                resolve(data);\n            }\n        }));\n    }\n\n    /**\n     * Build a successful Future with the value you provide.\n     */\n    static ok<T>(val:T): Future<T> {\n        return new Future(Promise.resolve([val]));\n    }\n\n    /**\n     * Build a failed Future with the error data you provide.\n     */\n    static failed<T>(reason: any): Future<T> {\n        return new Future(Promise.reject(reason));\n    }\n\n    /**\n     * Creates a Future from a function returning a Promise,\n     * which can be inline in the call, for instance:\n     *\n     *     const f1 = Future.ok(1);\n     *     const f2 = Future.ok(2);\n     *     return Future.do(async () => {\n     *         const v1 = await f1;\n     *         const v2 = await f2;\n     *         return v1 + v2;\n     *     });\n     */\n    static do<T>(fn: ()=>Promise<T>): Future<T> {\n        return Future.of(fn())\n    }\n\n    /**\n     * The `then` call is not meant to be a part of the `Future` API,\n     * we need then so that `await` works directly.\n     *\n     * Please rather use [[Future.map]] or [[Future.flatMap]].\n     */\n    then<TResult1 = T, TResult2 = never>(\n        onfulfilled: ((value: T) => TResult1 | PromiseLike<TResult1>),\n        onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): PromiseLike<TResult1 | TResult2> {\n        return this.promise.then(([x]) => onfulfilled(x), rejected => onrejected?onrejected(rejected):Promise.reject<TResult2>(rejected)); \n    }\n\n    /**\n     * Get a `Promise` from this `Future`.\n     */\n    toPromise(): Promise<T> {\n        return this.promise.then(([x]) => x);\n    }\n\n    /**\n     * Returns a `Future` that'll complete when the first `Future` of\n     * the iterable you give will complete, with the value of that first\n     * future. Be careful, completing doesn't necessarily mean completing\n     * successfully!\n     *\n     * Also see [[Future.firstSuccessfulOf]]\n     */\n    static firstCompletedOf<T>(elts: Iterable<Future<T>>): Future<T> {\n        return Future.of(\n            Promise.race(Vector.ofIterable(elts).map(f => f.toPromise())));\n    }\n\n    /**\n     * Returns a `Future` that'll complete when the first `Future` of\n     * the iterable you give will complete successfully, with the value of that first\n     * future.\n     *\n     * Also see [[Future.firstCompletedOf]]\n     */\n    static firstSuccessfulOf<T>(elts: Iterable<Future<T>>): Future<T> {\n        // https://stackoverflow.com/a/37235274/516188\n        return Future.of(\n            Promise.all(Vector.ofIterable(elts).map(p => {\n                // If a request fails, count that as a resolution so it will keep\n                // waiting for other possible successes. If a request succeeds,\n                // treat it as a rejection so Promise.all immediately bails out.\n                return p.then(\n                    val => Promise.reject(val),\n                    err => Promise.resolve(err)\n                );\n            })).then(\n                // If '.all' resolved, we've just got an array of errors.\n                errors => Promise.reject(errors),\n                // If '.all' rejected, we've got the result we wanted.\n                val => Promise.resolve(val)\n                )\n        );\n    }\n\n    /**\n     * Turns a list of futures in a future containing a list of items.\n     * Useful in many contexts.\n     *\n     * But if a single future is failed, you get back a failed Future.\n     *\n     * Also see [[Future.traverse]]\n     */\n    static sequence<T>(elts: Iterable<Future<T>>): Future<Vector<T>> {\n        return Future.traverse(elts, x=>x);\n    }\n\n    /**\n     * Takes a list, a function that can transform list elements\n     * to futures, then return a Future containing a list of\n     * the transformed elements. \n     *\n     * But if a single element results in failure, the result also\n     * resolves to a failure.\n     *\n     * There is an optional third parameter to specify options.\n     * You can specify `{maxConcurrent: number}` to request that\n     * the futures are not all triggered at the same time, but\n     * rather only 'number' at a time.\n     *\n     * Also see [[Future.sequence]]\n     */\n    static traverse<T,U>(elts: Iterable<T>, fn: (x:T)=>Future<U>,\n                         opts?: {maxConcurrent:number}): Future<Vector<U>> {\n        if (!opts) {\n            return Future.of(\n                Promise.all(Vector.ofIterable(elts).map(x => fn(x).toPromise()))\n                    .then(Vector.ofIterable));\n        }\n        // maxConcurrent algorithm inspired by https://stackoverflow.com/a/38778887/516188\n        let index = 0;\n        let active: Future<U>[] = [];\n        const results: {[idx:number]:U} = {};\n        const it = elts[Symbol.iterator]();\n        let failed: Future<U>|undefined;\n        const addAsNeeded = (_?:U): Future<Vector<U>> => {\n            if (failed) {\n                return <any>failed;\n            }\n            let cur;\n            while (active.length < opts.maxConcurrent &&\n                   !(cur = it.next()).done) {\n                const p = fn(cur.value);\n                active.push(p);\n                const curIdx = index++;\n                p.onComplete(eitherRes => {\n                    active.splice(active.indexOf(p), 1)\n                    if (eitherRes.isLeft()) {\n                        failed = p;\n                    } else {\n                        results[curIdx] = eitherRes.get();\n                    }\n                });\n            }\n            if (!failed && active.length === 0 && cur && cur.done) {\n                return Future.ok(\n                    HashMap.ofObjectDictionary<U>(results)\n                        .toVector()\n                        .sortOn(kv => parseInt(kv[0]))\n                        .map(kv => kv[1]));\n            }\n            return Future.firstCompletedOf(active).flatMap(addAsNeeded);\n        };\n        return addAsNeeded();\n    }\n\n    /**\n     * From the list of Futures you give, will attempt to find a successful\n     * Future which value matches the predicate you give.\n     * We return a Future of an [[Option]], which will [[None]] in case\n     * no matching Future is found.\n     */\n    static find<T>(elts: Iterable<Future<T>>, p: (x: T) => boolean): Future<Option<T>> {\n        const origElts = Vector.ofIterable(elts)\n        if (origElts.isEmpty()) {\n            return Future.ok(Option.none<T>());\n        }\n        type FutOptPair = [Future<T>,Option<T>];\n        // map the failures to successes with option.none\n        // backup the original future object matching the new future\n        const velts = origElts\n            .map(\n                f => f\n                    .map<FutOptPair>(item => [f, Option.of(item)])\n                    .recoverWith(_=>Future.ok<FutOptPair>([f, Option.none<T>()])));\n        // go for the first completed of the iterable\n        // remember after our map they're all successful now\n        const success = Future.firstCompletedOf(velts);\n        return success\n            .flatMap(([originalFuture, option]) => {\n                if (option.isSome() && p(option.get())) {\n                    // this successful future matches our predicate, that's it.\n                    return success.map(x => x[1]);\n                } else {\n                    // this future failed or doesn't match our predicate.\n                    // remove the future from the input list (we can do that\n                    // because we \"backed up\" the original future in the future\n                    // result), and try again only with the remaining candidates\n                    return Future.find(origElts.removeFirst(future => future === originalFuture), p);\n                }\n            });\n    }\n\n    /**\n     * Applicative lifting for Future. 'p' stands for 'properties'.\n     *\n     * Takes a function which operates on a simple JS object, and turns it\n     * in a function that operates on the same JS object type except which each field\n     * wrapped in a Future ('lifts' the function).\n     * It's an alternative to [[Future.liftA2]] when the number of parameters\n     * is not two.\n     *\n     * @param A the object property type specifying the parameters for your function\n     * @param B the type returned by your function, returned wrapped in a future by liftAp.\n     */\n    static liftAp<A,B>(fn:(x:A)=>B): (x: {[K in keyof A]: Future<A[K]>;}) => Future<B> {\n        return x => {\n            const fieldNames: Array<keyof A> = <any>Object.keys(x);\n            const promisesAr = fieldNames.map(n => x[n]);\n            let i=0;\n            return Future.of(\n                Promise.all(promisesAr)\n                    .then(resultAr => resultAr.reduce<{[K in keyof A]: A[K]}>((sofar,cur) => {\n                        sofar[fieldNames[i++]] = cur;\n                        return sofar;\n                    }, <any>{}))).map(fn);\n        };\n    }\n\n    /**\n     * Applicative lifting for Future.\n     * Takes a function which operates on basic values, and turns it\n     * in a function that operates on futures of these values ('lifts'\n     * the function). The 2 is because it works on functions taking two\n     * parameters.\n     *\n     * @param R1 the first future type\n     * @param R2 the second future type\n     * @param V the new future type as returned by the combining function.\n     */\n    static liftA2<R1,R2,V>(fn:(v1:R1,v2:R2)=>V) : (p1:Future<R1>, p2:Future<R2>) => Future<V> {\n        return (p1,p2) => p1.flatMap(a1 => p2.map(a2 => fn(a1,a2)));\n    }\n\n    /**\n     * Take a function returning a Promise\n     * and lift it to return a [[Future]] instead.\n     */\n    static lift<T extends any[],U>(fn: (...args: T)=>Promise<U>): (...args:T)=>Future<U> {\n        return (...args:T) => Future.of(fn(...args));\n    }\n\n    /**\n     * Transform the value contained in a successful Future. Has no effect\n     * if the Future was failed. Will turn a successful Future in a failed\n     * one if you throw an exception in the map callback (but please don't\n     * do it.. Rather use [[Future.filter]] or another mechanism).\n     */\n    map<U>(fn: (x:T)=>U): Future<U> {\n        return new Future<U>(this.promise.then(([x]) => [fn(x)]));\n    }\n\n    /**\n     * Transform the value contained in a successful Future. You return a\n     * Future, but it is then \"flattened\" so we still return a Future<T>\n     * (and not a Future<Future<T>>).\n     * Has no effect if the Future was failed. Will turn a successful Future in a failed\n     * one if you throw an exception in the map callback (but please don't\n     * do it.. Rather use [[Future.filter]] or another mechanism).\n     * This is the monadic bind.\n     */\n    flatMap<U>(fn: (x:T)=>Future<U>): Future<U> {\n        return new Future<U>(this.promise.then(([x]) => fn(x).promise));\n    }\n\n    /**\n     * Transform the value contained in a failed Future. Has no effect\n     * if the Future was successful.\n     */\n    mapFailure(fn: (x:any)=>any): Future<T> {\n        return new Future<T>(this.promise.catch(x => {throw fn(x)}));\n    }\n\n    /**\n     * Execute the side-effecting function you give if the Future is a failure.\n     *\n     * The Future is unchanged by this call.\n     */\n    onFailure(fn: (x:any)=>void): Future<T> {\n        this.promise.catch(x => fn(x));\n        return this;\n    }\n\n    /**\n     * Execute the side-effecting function you give if the Future is a success.\n     *\n     * The Future is unchanged by this call.\n     */\n    onSuccess(fn: (x:T)=>void): Future<T> {\n        // we create a new promise here, need to catch errors on it,\n        // to avoid node UnhandledPromiseRejectionWarning warnings\n        this.promise.then(x => {fn(x[0]); return x;}).catch(_ => {});\n        return this;\n    }\n\n    /**\n     * Execute the side-effecting function you give when the Future is\n     * completed. You get an [[Either]], a `Right` if the Future is a\n     * success, a `Left` if it's a failure.\n     *\n     * The Future is unchanged by this call.\n     */\n    onComplete(fn: (x:Either<any,T>)=>void): Future<T> {\n        this.promise.then(\n            x => {fn(Either.right(x[0])); return x;},\n            x => fn(Either.left(x)));\n        return this;\n    }\n\n    /**\n     * Has no effect on a failed Future. If the Future was successful,\n     * will check whether its value matches the predicate you give as\n     * first parameter. If the value matches the predicate, an equivalent\n     * Future to the input one is returned.\n     *\n     * If the value doesn't match predicate however, the second parameter\n     * function is used to compute the contents of a failed Future that'll\n     * be returned.\n     */\n    filter(p: (x:T)=>boolean, ifFail: (x:T)=>any): Future<T> {\n        return this.flatMap(\n            x => p(x) ? Future.ok(x) : Future.failed(ifFail(x)));\n    }\n    \n    /**\n     * Has no effect if this Future is successful. If it's failed however,\n     * the function you give will be called, receiving as parameter\n     * the error contents, and a Future equivalent to the one your\n     * function returns will be returned.\n     */\n    recoverWith(f: (err:any)=>Future<T>): Future<T> {\n        return new Future<T>(this.promise.catch(err => f(err).promise));\n    }\n\n    /**\n     * Transform this value to another value type.\n     * Enables fluent-style programming by chaining calls.\n     */\n    transform<U>(fn: (x:Future<T>)=>U): U {\n        return fn(this);\n    }\n}\n"
  },
  {
    "path": "src/HashMap.ts",
    "content": "import { IMap } from \"./IMap\";\nimport { hasEquals, HasEquals, WithEquality,\n         getHashCode, areEqual, fieldsHashCode } from \"./Comparison\";\nimport { toStringHelper } from \"./SeqHelpers\";\nimport { contractTrueEquality } from \"./Contract\"\nimport { Option, none, None } from \"./Option\";\nimport { HashSet } from \"./HashSet\";\nimport { Vector } from \"./Vector\";\nimport { LinkedList } from \"./LinkedList\";\nimport * as SeqHelpers from \"./SeqHelpers\";\nimport { inspect } from \"./Value\";\nconst hamt: any = require(\"hamt_plus\");\n\n// HashMap could extend Collection, conceptually. But I'm\n// not super happy of having the callbacks get a pair, for instance\n// 'HashMap.filter' takes two parameters in the current HashMap;\n// if HashMap did implement Collection, it would have to take a k,v\n// pair. There's also another trick with 'contains'. The Collection signature\n// says T&WithEquality, but here we get [K&WithEquality,V&WithEquality],\n// but arrays don't have equality so that doesn't type-check :-(\n\n/**\n * A dictionary, mapping keys to values.\n * @param K the key type\n * @param V the value type\n */\nexport class HashMap<K,V> implements IMap<K,V> {\n\n    /**\n     * @hidden\n     */\n    protected constructor(private hamt: any) {}\n\n    /**\n     * The empty map.\n     * @param K the key type\n     * @param V the value type\n     */\n    static empty<K,V>(): HashMap<K,V> {\n        return <EmptyHashMap<K,V>>emptyHashMap;\n    }\n\n    /**\n     * Build a HashMap from key-value pairs.\n     *\n     *     HashMap.of([1,\"a\"],[2,\"b\"])\n     *\n     */\n    static of<K,V>(...entries: Array<[K&WithEquality, V]>): HashMap<K,V> {\n        return HashMap.ofIterable<K,V>(entries);\n    }\n\n    /**\n     * Build a HashMap from an iterable containing key-value pairs.\n     *\n     *    HashMap.ofIterable(Vector.of<[number,string]>([1,\"a\"],[2,\"b\"]));\n     */\n    static ofIterable<K,V>(entries: Iterable<[K&WithEquality, V]>): HashMap<K,V> {\n        // remember we must set up the hamt with the custom equality\n        const iterator = entries[Symbol.iterator]();\n        let curItem = iterator.next();\n        if (curItem.done) {\n            return new EmptyHashMap<K,V>();\n        }\n        // emptyhashmap.put sets up the custom equality+hashcode\n        let startH = (new EmptyHashMap<K,V>()).put(curItem.value[0], curItem.value[1]).hamt;\n        curItem = iterator.next();\n        return new HashMap<K,V>(startH.mutate((h:any) => {\n            while (!curItem.done) {\n                h.set(curItem.value[0], curItem.value[1]);\n                curItem = iterator.next();\n            }\n        }));\n    }\n\n    /**\n     * Build a HashMap from a javascript object literal representing\n     * a dictionary. Note that the key type must always be string,\n     * as that's the way it works in javascript.\n     * Also note that entries with undefined values will be stripped\n     * from the map.\n     *\n     *     HashMap.ofObjectDictionary<number>({a:1,b:2})\n     *     => HashMap.of([\"a\",1],[\"b\",2])\n     */\n    static ofObjectDictionary<V>(object: {[index:string]: V|undefined}): HashMap<string,V> {\n        // no need to bother with the proper equals & hashcode\n        // as I know the key type supports ===\n        const h: any = hamt.make().beginMutation();\n        for (let property in object) {\n            // the reason we strip entries with undefined values on\n            // import from object dictionaries are: sanity, and also\n            // partial object definitions like {[TKey in MyEnum]?:number}\n            // where typescript sees the value type as 'number|undefined'\n            // (there is a test covering that)\n            if (object.hasOwnProperty(property) &&\n                (typeof object[property] !== \"undefined\")) {\n                h.set(property, object[property]);\n            }\n        }\n        return new HashMap<string,V>(h.endMutation());\n    }\n\n    /**\n     * Curried predicate to find out whether the HashMap is empty.\n     *\n     *     Vector.of(HashMap.of([1,2]), HashMap.empty<number,number>())\n     *         .filter(HashMap.isEmpty)\n     *     => Vector.of(HashMap.empty<number,number>())\n     */\n    static isEmpty<K,V>(v: HashMap<K,V>): boolean {\n        return v.isEmpty();\n    }\n\n    /**\n     * Curried predicate to find out whether the HashMap is empty.\n     *\n     *     Vector.of(HashMap.of([1,2]), HashMap.empty<number,number>())\n     *         .filter(HashMap.isNotEmpty)\n     *     => Vector.of(HashMap.of([1,2]))\n     */\n    static isNotEmpty<K,V>(v: HashMap<K,V>): boolean {\n        return !v.isEmpty();\n    }\n\n    /**\n     * Get the value for the key you give, if the key is present.\n     */\n    get(k: K & WithEquality): Option<V> {\n        return Option.of<V>(this.hamt.get(k));\n    }\n\n    /**\n     * Implementation of the Iterator interface.\n     */\n    [Symbol.iterator](): Iterator<[K,V]> {\n        return this.hamt.entries();\n    }\n\n    /**\n     * @hidden\n     */\n    hasTrueEquality(): boolean {\n        // for true equality, need both key & value to have true\n        // equality. but i can't check when they're in an array,\n        // as array doesn't have true equality => extract them\n        // and check them separately.\n        return Option.of(this.hamt.entries().next().value)\n            .map(x => x[0]).hasTrueEquality() &&\n            Option.of(this.hamt.entries().next().value)\n            .map(x => x[1]).hasTrueEquality()\n    }\n\n    /**\n     * Add a new entry in the map. If there was entry with the same\n     * key, it will be overwritten.\n     * @param k the key\n     * @param v the value\n     */\n    put(k: K & WithEquality, v: V): HashMap<K,V> {\n        return new HashMap<K,V>(this.hamt.set(k,v));\n    }\n\n    /**\n     * Return a new map with the key you give removed.\n     */\n    remove(k: K&WithEquality): HashMap<K,V> {\n        return new HashMap<K,V>(this.hamt.remove(k));\n    }\n\n    /**\n     * Add a new entry in the map; in case there was already an\n     * entry with the same key, the merge function will be invoked\n     * with the old and the new value to produce the value to take\n     * into account.\n     *\n     * It is guaranteed that the merge function first parameter\n     * will be the entry from this map, and the second parameter\n     * from the map you give.\n     * @param k the key\n     * @param v the value\n     * @param merge a function to merge old and new values in case of conflict.\n     */\n    putWithMerge(k: K & WithEquality, v: V, merge: (v1: V, v2: V) => V): HashMap<K,V> {\n        return new HashMap<K,V>(this.hamt.modify(k, (curV?: V) => {\n            if (curV === undefined) {\n                return v;\n            }\n            return merge(curV, v);\n        }))\n    }\n\n    /**\n     * number of items in the map\n     */\n    length(): number {\n        return this.hamt.size;\n    }\n\n    /**\n     * If the collection contains a single element,\n     * return Some of its value, otherwise return None.\n     */\n    single(): Option<[K,V]> {\n        return this.hamt.size === 1\n            ? Option.of(this.hamt.entries().next().value)\n            : Option.none();\n    }\n\n    /**\n     * true if the map is empty, false otherwise.\n     */\n    isEmpty(): boolean {\n        return this.hamt.size === 0;\n    }\n\n    /**\n     * Get a Set containing all the keys in the map\n     */\n    keySet(): HashSet<K> {\n        return HashSet.ofIterable<K>(this.hamt.keys());\n    }\n\n    /**\n     * Get an iterable containing all the values in the map\n     * (can't return a set as we don't constrain map values\n     * to have equality in the generics type)\n     */\n    valueIterable(): Iterable<V> {\n        const hamt = this.hamt;\n        return {\n            [Symbol.iterator]() { return hamt.values(); }\n        };\n    }\n\n    /**\n     * Create a new map combining the entries of this map, and\n     * the other map you give. In case an entry from this map\n     * and the other map have the same key, the merge function\n     * will be invoked to get a combined value.\n     *\n     * It is guaranteed that the merge function first parameter\n     * will be the entry from this map, and the second parameter\n     * from the map you give.\n     * @param other another map to merge with this one\n     * @param merge a merge function to combine two values\n     *        in case two entries share the same key.\n     */\n    mergeWith(elts: Iterable<[K & WithEquality,V]>, merge:(v1: V, v2: V) => V): HashMap<K,V> {\n        const iterator = elts[Symbol.iterator]();\n        let map: HashMap<K,V> = this;\n        let curItem = iterator.next();\n        while (!curItem.done) {\n            map = map.putWithMerge(curItem.value[0], curItem.value[1], merge);\n            curItem = iterator.next();\n        }\n        return map;\n    }\n\n    /**\n     * Return a new map where each entry was transformed\n     * by the mapper function you give. You return key,value\n     * as pairs.\n     */\n    map<K2,V2>(fn:(k:K&WithEquality, v:V)=>[K2&WithEquality,V2]): HashMap<K2,V2> {\n        return this.hamt.fold(\n            (acc: HashMap<K2,V2>, value: V, key: K&WithEquality) => {\n                const [newk,newv] = fn(key, value);\n                return acc.put(newk,newv);\n            }, HashMap.empty());\n    }\n\n    /**\n     * Return a new map where keys are the same as in this one,\n     * but values are transformed\n     * by the mapper function you give. You return key,value\n     * as pairs.\n     */\n    mapValues<V2>(fn:(v:V)=>V2): HashMap<K,V2> {\n        return this.hamt.fold(\n            (acc: HashMap<K,V2>, value: V, key: K&WithEquality) =>\n                acc.put(key,fn(value)), HashMap.empty());\n    }\n\n    /**\n     * Call a function for element in the collection.\n     */\n    forEach(fun:(x:[K,V])=>void): HashMap<K,V> {\n        const iterator: Iterator<[K,V]> = this.hamt.entries();\n        let curItem = iterator.next();\n        while (!curItem.done) {\n            fun(curItem.value);\n            curItem = iterator.next();\n        }\n        return this;\n    }\n\n    /**\n     * Calls the function you give for each item in the map,\n     * your function returns a map, all the maps are\n     * merged.\n     */\n    flatMap<K2,V2>(fn:(k:K, v:V)=>Iterable<[K2&WithEquality,V2]>): HashMap<K2,V2> {\n        return this.foldLeft(HashMap.empty<K2,V2>(),\n                             (soFar,cur) => soFar.mergeWith(fn(cur[0],cur[1]), (a,b)=>b));\n    }\n\n    /**\n     * Returns true if the predicate returns true for all the\n     * elements in the collection.\n     */\n    allMatch(predicate:(k:K,v:V)=>boolean): boolean {\n        const iterator: Iterator<[K,V]> = this.hamt.entries();\n        let curItem = iterator.next();\n        while (!curItem.done) {\n            if (!predicate(curItem.value[0], curItem.value[1])) {\n                return false;\n            }\n            curItem = iterator.next();\n        }\n        return true;\n    }\n\n    /**\n     * Returns true if there the predicate returns true for any\n     * element in the collection.\n     */\n    anyMatch(predicate:(k:K,v:V)=>boolean): boolean {\n        const iterator: Iterator<[K,V]> = this.hamt.entries();\n        let curItem = iterator.next();\n        while (!curItem.done) {\n            if (predicate(curItem.value[0], curItem.value[1])) {\n                return true;\n            }\n            curItem = iterator.next();\n        }\n        return false;\n    }\n\n    /**\n     * Returns true if the item is in the collection,\n     * false otherwise.\n     */\n    contains(val: [K&WithEquality,V&WithEquality]): boolean {\n        return areEqual(this.hamt.get(val[0]), val[1]);\n    }\n\n    /**\n     * Returns true if there is item with that key in the collection,\n     * false otherwise.\n     *\n     *     HashMap.of<number,string>([1,\"a\"],[2,\"b\"]).containsKey(1);\n     *     => true\n     *\n     *     HashMap.of<number,string>([1,\"a\"],[2,\"b\"]).containsKey(3);\n     *     => false\n     */\n    containsKey(key: K&WithEquality): boolean {\n        return this.hamt.has(key);\n    }\n\n    /**\n     * Call a predicate for each element in the collection,\n     * build a new collection holding only the elements\n     * for which the predicate returned true.\n     */\n    filter(predicate:(k:K,v:V)=>boolean): HashMap<K,V> {\n        return new HashMap<K,V>(\n            hamt.make({hash:this.hamt._config.hash, keyEq:this.hamt._config.keyEq}).mutate((h:any) => {\n                const iterator: Iterator<[K,V]> = this.hamt.entries();\n                let curItem = iterator.next();\n                while (!curItem.done) {\n                    if (predicate(curItem.value[0], curItem.value[1])) {\n                        h.set(curItem.value[0], curItem.value[1]);\n                    }\n                    curItem = iterator.next();\n                }\n            }));\n    }\n\n    /**\n     * Search for an item matching the predicate you pass,\n     * return Option.Some of that element if found,\n     * Option.None otherwise.\n     * We name the method findAny instead of find to emphasize\n     * that there is not ordering in a hashset.\n     *\n     *     HashMap.of<number,string>([1,'a'],[2,'b'],[3,'c'])\n     *         .findAny((k,v) => k>=2 && v === \"c\")\n     *     => Option.of([3,'c'])\n     *\n     *     HashMap.of<number,string>([1,'a'],[2,'b'],[3,'c'])\n     *         .findAny((k,v) => k>=3 && v === \"b\")\n     *     => Option.none<[number,string]>()\n     */\n    findAny(predicate:(k:K,v:V)=>boolean): Option<[K,V]> {\n        const iterator: Iterator<[K,V]> = this.hamt.entries();\n        let curItem = iterator.next();\n        while (!curItem.done) {\n            if (predicate(curItem.value[0], curItem.value[1])) {\n                return Option.of(curItem.value);\n            }\n            curItem = iterator.next();\n        }\n        return Option.none<[K,V]>();\n    }\n\n    /**\n     * Call a predicate for each key in the collection,\n     * build a new collection holding only the elements\n     * for which the predicate returned true.\n     *\n     *     HashMap.of<number,string>([1,\"a\"],[2,\"b\"]).filterKeys(k=>k%2===0)\n     *     => HashMap.of<number,string>([2,\"b\"])\n     */\n    filterKeys<U extends K>(fn:(v:K)=>v is U): HashMap<U,V>;\n    filterKeys(predicate:(k:K)=>boolean): HashMap<K,V>;\n    filterKeys(predicate:(k:K)=>boolean): HashMap<K,V> {\n        return this.filter((k,v)=>predicate(k));\n    }\n\n    /**\n     * Call a predicate for each value in the collection,\n     * build a new collection holding only the elements\n     * for which the predicate returned true.\n     *\n     *     HashMap.of<number,string>([1,\"a\"],[2,\"ab\"]).filterValues(v=>v.length>1)\n     *     => HashMap.of<number,string>([2,\"ab\"])\n     */\n    filterValues<U extends V>(fn:(v:V)=>v is U): HashMap<K,U>;\n    filterValues(predicate:(k:V)=>boolean): HashMap<K,V>;\n    filterValues(predicate:(k:V)=>boolean): HashMap<K,V> {\n        return this.filter((k,v)=>predicate(v));\n    }\n\n    /**\n     * Reduces the collection to a single value using the\n     * associative binary function you give. Since the function\n     * is associative, order of application doesn't matter.\n     *\n     * Example:\n     *\n     *     HashMap.of<number,string>([1,\"a\"],[2,\"b\"],[3,\"c\"])\n     *      .fold([0,\"\"], ([a,b],[c,d])=>[a+c, b>d?b:d])\n     *     => [6,\"c\"]\n     */\n    fold(zero:[K,V], fn:(v1:[K,V],v2:[K,V])=>[K,V]): [K,V] {\n        return this.foldLeft(zero, fn);\n    }\n\n    /**\n     * Reduces the collection to a single value.\n     * Left-associative.\n     * No guarantees for the order of items in a hashset!\n     *\n     * Example:\n     *\n     *     HashMap.of([1,\"a\"], [2,\"bb\"], [3,\"ccc\"])\n     *     .foldLeft(0, (soFar,[item,val])=>soFar+val.length);\n     *     => 6\n     *\n     * @param zero The initial value\n     * @param fn A function taking the previous value and\n     *           the current collection item, and returning\n     *           an updated value.\n     */\n    foldLeft<U>(zero: U, fn:(soFar:U,cur:[K,V])=>U): U {\n        return this.hamt.fold(\n            (acc: U, v: V, k: K&WithEquality) =>\n                fn(acc, [k,v]), zero);\n    }\n\n    /**\n     * Reduces the collection to a single value.\n     * Right-associative.\n     * No guarantees for the order of items in a hashset!\n     *\n     * Example:\n     *\n     *     HashMap.of([1,\"a\"], [2,\"bb\"], [3,\"ccc\"])\n     *     .foldRight(0, ([item,value],soFar)=>soFar+value.length);\n     *     => 6\n     *\n     * @param zero The initial value\n     * @param fn A function taking the current collection item and\n     *           the previous value , and returning\n     *           an updated value.\n     */\n    foldRight<U>(zero: U, fn:(cur:[K,V], soFar:U)=>U): U {\n        return this.foldLeft(zero, (cur, soFar) => fn(soFar, cur));\n    }\n\n    /**\n     * Reduces the collection to a single value by repeatedly\n     * calling the combine function.\n     * No starting value. The order in which the elements are\n     * passed to the combining function is undetermined.\n     */\n    reduce(combine: (v1:[K,V],v2:[K,V])=>[K,V]): Option<[K,V]> {\n        // not really glorious with any...\n        return <Option<[K,V]>>SeqHelpers.reduce<any>(<any>this, combine);\n    }\n\n    /**\n     * Convert to array.\n     */\n    toArray(): Array<[K,V]> {\n        return this.hamt.fold(\n            (acc: [[K,V]], value: V, key: K&WithEquality) =>\n                {acc.push([key,value]); return acc; }, []);\n    }\n\n    /**\n     * Convert this map to a vector of key,value pairs.\n     * Note that Map is already an iterable of key,value pairs!\n     */\n    toVector(): Vector<[K,V]> {\n        return this.hamt.fold(\n            (acc: Vector<[K,V]>, value: V, key: K&WithEquality) =>\n                acc.append([key,value]), Vector.empty());\n    }\n\n    /**\n     * Convert this map to a list of key,value pairs.\n     * Note that Map is already an iterable of key,value pairs!\n     */\n    toLinkedList(): LinkedList<[K,V]> {\n        return LinkedList.ofIterable(this);\n    }\n\n    /**\n     * Convert to a javascript object dictionary\n     * You must provide a function to convert the\n     * key to a string.\n     *\n     *     HashMap.of<string,number>([\"a\",1],[\"b\",2])\n     *         .toObjectDictionary(x=>x);\n     *     => {a:1,b:2}\n     */\n    toObjectDictionary(keyConvert:(k:K)=>string): {[index:string]:V} {\n        return this.foldLeft<{[index:string]:V}>({}, (soFar,cur)=> {\n            soFar[keyConvert(cur[0])] = cur[1];\n            return soFar;\n        });\n    }\n\n    /**\n     * Convert to an ES6 Map.\n     * You must provide a function to convert the\n     * key to a string, number or boolean, because\n     * with other types equality is not correctly\n     * managed by JS.\n     * https://stackoverflow.com/questions/29759480/how-to-customize-object-equality-for-javascript-set\n     * https://esdiscuss.org/topic/maps-with-object-keys\n     *\n     *     HashMap.of<string,number>([\"a\",1],[\"b\",2])\n     *         .toJsMap(x=>x);\n     *     => new Map([[\"a\",1], [\"b\",2]])\n     */\n    toJsMap(keyConvert:(k:K)=>string): Map<string,V>;\n    toJsMap(keyConvert:(k:K)=>number): Map<number,V>;\n    toJsMap(keyConvert:(k:K)=>boolean): Map<boolean,V>;\n    toJsMap<K2 extends number|string|boolean>(keyConvert:(k:K)=>K2): Map<K2,V> {\n        return this.foldLeft(\n            new Map<K2,V>(),\n            (soFar,cur)=> soFar.set(keyConvert(cur[0]), cur[1]));\n    }\n\n    /**\n     * Transform this value to another value type.\n     * Enables fluent-style programming by chaining calls.\n     */\n    transform<U>(converter:(x:HashMap<K,V>)=>U): U {\n        return converter(this);\n    }\n\n    /**\n     * Two objects are equal if they represent the same value,\n     * regardless of whether they are the same object physically\n     * in memory.\n     */\n    equals(other: IMap<K&WithEquality,V&WithEquality>): boolean {\n        if (<any>other === this) {\n            return true;\n        }\n        if (!other || !other.valueIterable) {\n            return false;\n        }\n        contractTrueEquality(\"HashMap.equals\", this, other);\n        const sz = this.hamt.size;\n        if (other.length() === 0 && sz === 0) {\n            // we could get that i'm not the empty map\n            // but my size is zero, after some filtering and such.\n            return true;\n        }\n        if (sz !== other.length()) {\n            return false;\n        }\n        const keys: Array<K & WithEquality> = Array.from<K & WithEquality>(this.hamt.keys());\n        for (let k of keys) {\n            const myVal: V|null|undefined = this.hamt.get(k);\n            const hisVal: V|null|undefined = other.get(k).getOrUndefined();\n            if (myVal === undefined || hisVal === undefined) {\n                return false;\n            }\n            if (!areEqual(myVal, hisVal)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Get a number for that object. Two different values\n     * may get the same number, but one value must always get\n     * the same number. The formula can impact performance.\n     */\n    hashCode(): number {\n        // references:\n        // https://github.com/clojure/clojure/blob/5ffe3833508495ca7c635d47ad7a1c8b820eab76/src/jvm/clojure/lang/APersistentMap.java#L98\n        // https://github.com/AdoptOpenJDK/openjdk-jdk11/blob/19fb8f93c59dfd791f62d41f332db9e306bc1422/src/java.base/share/classes/java/util/HashMap.java#L296\n\n        // Both the Clojure and AdoptOpenJDK references calculate the bitwise XOR\n        // of the key/value pairs. The significance of the bitwise XOR is that,\n        // unlike just adding the hashcode of the key and value pair, they become\n        // intertwined, which prevents collisions when identical values are swapped\n        // between keys.\n\n        // This algorithm only intertwines the keys and the values. The calculations\n        // for the pairs are summed up, to make sure that we get the same result\n        // if the pairs are in a different order.\n\n        // The Clojure implementation also caches the result of the calculation, but\n        // we've decided not to do that yet, see the discussion on the PR for context:\n        // https://github.com/emmanueltouzery/prelude-ts/pull/67\n        return this.hamt.fold(\n            (acc: number, value: V, key: K & WithEquality) =>\n                acc + (getHashCode(key) ^ getHashCode(value)), 0);\n    }\n\n    /*\n     * Get a human-friendly string representation of that value.\n     */\n    toString(): string {\n        return \"HashMap(\" +\n            this.hamt.fold(\n                (acc: string[], value: V, key: K) =>\n                    {acc.push(\n                        toStringHelper(key, {quoteStrings:false}) +\n                            \": \" + toStringHelper(value)); return acc;}, [])\n            .join(\", \") + \")\";\n    }\n\n    [inspect](): string {\n        return this.toString();\n    }\n}\n\n// we need to override the empty hashmap\n// because i don't know how to get the hash & keyset\n// functions for the keys without a key value to get\n// the functions from\nclass EmptyHashMap<K,V> extends HashMap<K,V> {\n\n    constructor() {\n        super({}); // we must override all the functions\n    }\n\n    get(k: K & WithEquality): Option<V> {\n        return <None<V>>none;\n    }\n\n    [Symbol.iterator](): Iterator<[K,V]> {\n        return { next: () => ({ done: true, value: <any>undefined }) };\n    }\n\n    put(k: K & WithEquality, v: V): HashMap<K,V> {\n        contractTrueEquality(\"Error building a HashMap\", k);\n        if (hasEquals(k)) {\n            return new HashMap<K,V>(hamt.make({\n                hash: (v: K & HasEquals) => v.hashCode(),\n                keyEq: (a: K & HasEquals, b: K & HasEquals) => a.equals(b)\n            }).set(k,v));\n        }\n        return new HashMap<K,V>(hamt.make().set(k,v));\n    }\n\n    remove(k: K&WithEquality): HashMap<K,V> {\n        return this;\n    }\n\n    hasTrueEquality(): boolean {\n        return true;\n    }\n\n    putWithMerge(k: K & WithEquality, v: V, merge: (v1: V, v2: V) => V): HashMap<K,V> {\n        return this.put(k,v);\n    }\n\n    length(): number {\n        return 0;\n    }\n\n    /**\n     * If the collection contains a single element,\n     * return Some of its value, otherwise return None.\n     */\n    single(): Option<[K,V]> {\n        return Option.none<[K,V]>();\n    }\n\n    isEmpty(): boolean {\n        return true;\n    }\n\n    keySet(): HashSet<K> {\n        return HashSet.empty<K>();\n    }\n\n    valueIterable(): Iterable<V> {\n        return {\n            [Symbol.iterator](): Iterator<V> {\n                return {\n                    next(): IteratorResult<V> {\n                        return {\n                            done: true,\n                            value: <any>undefined\n                        };\n                    }\n                };\n            }\n        };\n    }\n\n    mergeWith(other: Iterable<[K & WithEquality,V]>, merge:(v1: V, v2: V) => V): HashMap<K,V> {\n        return HashMap.ofIterable(other);\n    }\n\n    map<K2,V2>(fn:(k:K&WithEquality, v:V)=>[K2&WithEquality,V2]): HashMap<K2,V2> {\n        return HashMap.empty<K2,V2>();\n    }\n\n    mapValues<V2>(fn:(v:V)=>V2): HashMap<K,V2> {\n        return HashMap.empty<K,V2>();\n    }\n\n    forEach(fun:(x:[K,V])=>void): HashMap<K,V> {\n        return this;\n    }\n\n    allMatch(predicate:(k:K,v:V)=>boolean): boolean {\n        return true;\n    }\n\n    anyMatch(predicate:(k:K,v:V)=>boolean): boolean {\n        return false;\n    }\n\n    contains(val: [K&WithEquality,V&WithEquality]): boolean {\n        return false;\n    }\n\n    containsKey(key: K&WithEquality) : boolean {\n        return false;\n    }\n\n    filter(predicate:(k:K,v:V)=>boolean): HashMap<K,V> {\n        return this;\n    }\n\n    findAny(predicate:(k:K,v:V)=>boolean): Option<[K,V]> {\n        return Option.none<[K,V]>();\n    }\n\n    foldLeft<U>(zero: U, fn:(soFar:U,cur:[K,V])=>U): U {\n        return zero;\n    }\n\n    toArray(): Array<[K,V]> {\n        return [];\n    }\n\n    toVector(): Vector<[K,V]> {\n        return Vector.empty<[K,V]>();\n    }\n\n    toLinkedList(): LinkedList<[K,V]> {\n        return LinkedList.empty<[K,V]>();\n    }\n\n    equals(other: IMap<K&WithEquality,V&WithEquality>): boolean {\n        if (!other || !other.valueIterable) {\n            return false;\n        }\n        return <any>other === emptyHashMap || other.length() === 0;\n    }\n\n    hashCode(): number {\n        return 0;\n    }\n\n    toString(): string {\n        return \"HashMap()\";\n    }\n}\n\nconst emptyHashMap = new EmptyHashMap<any,any>();\n"
  },
  {
    "path": "src/HashSet.ts",
    "content": "import { ISet,\n         SortOnSpec, SortBySpec, isSortOnSpec } from \"./ISet\";\nimport { Vector } from \"./Vector\";\nimport { HashMap } from \"./HashMap\";\nimport { LinkedList } from \"./LinkedList\";\nimport { Option } from \"./Option\";\nimport { WithEquality, hasEquals, HasEquals,\n         getHashCode, areEqual, Ordering, ToOrderable  } from \"./Comparison\";\nimport * as SeqHelpers from \"./SeqHelpers\";\nimport { contractTrueEquality } from \"./Contract\";\nimport { inspect } from \"./Value\";\nconst hamt: any = require(\"hamt_plus\");\n\n/**\n * An unordered collection of values, where no two values\n * may be equal. A value can only be present once.\n * @param T the item type\n */\nexport class HashSet<T> implements ISet<T> {\n\n    /**\n     * @hidden\n     */\n    protected constructor(private hamt: any) {}\n\n    /**\n     * The empty hashset.\n     * @param T the item type\n     */\n    static empty<T>(): HashSet<T> {\n        return <EmptyHashSet<T>>emptyHashSet;\n    }\n\n    /**\n     * Build a hashset from any iterable, which means also\n     * an array for instance.\n     * @param T the item type\n     */\n    static ofIterable<T>(elts: Iterable<T & WithEquality>): HashSet<T> {\n        return new EmptyHashSet<T>().addAll(elts);\n    }\n\n    /**\n     * Build a hashset from a series of items (any number, as parameters)\n     * @param T the item type\n     */\n    static of<T>(...arr: Array<T & WithEquality>): HashSet<T> {\n        return HashSet.ofIterable(arr);\n    }\n\n    /**\n     * Curried predicate to find out whether the HashSet is empty.\n     *\n     *     Vector.of(HashSet.of(1), HashSet.empty<number>())\n     *         .filter(HashSet.isEmpty)\n     *     => Vector.of(HashSet.empty<number>())\n     */\n    static isEmpty<T>(v: HashSet<T>): boolean {\n        return v.isEmpty();\n    }\n\n    /**\n     * Curried predicate to find out whether the HashSet is empty.\n     *\n     *     Vector.of(HashSet.of(1), HashSet.empty<number>())\n     *         .filter(HashSet.isNotEmpty)\n     *     => Vector.of(HashSet.of(1))\n     */\n    static isNotEmpty<T>(v: HashSet<T>): boolean {\n        return !v.isEmpty();\n    }\n\n    /**\n     * Implementation of the Iterator interface.\n     */\n    [Symbol.iterator](): Iterator<T> {\n        return this.hamt.keys();\n    }\n\n    /**\n     * Add an element to this set.\n     */\n    add(elt: T & WithEquality): HashSet<T> {\n        return new HashSet<T>(this.hamt.set(elt,elt));\n    }\n\n    private addAllArray(elts: Array<T&WithEquality>): HashSet<T> {\n        return new HashSet<T>(this.hamt.mutate((h:any) => {\n            if (elts.length > 0) {\n                contractTrueEquality(\"Error building a HashSet\", elts[0]);\n            }\n            for (const val of elts) {\n                h.set(val, val);\n            }\n        }));\n    }\n\n    /**\n     * Add multiple elements to this set.\n     */\n    addAll(elts: Iterable<T & WithEquality>): HashSet<T> {\n        if (Array.isArray(elts)) {\n            return this.addAllArray(elts);\n        }\n        return new HashSet<T>(this.hamt.mutate((h:any) => {\n            let checkedEq = false;\n            const iterator = elts[Symbol.iterator]();\n            let curItem = iterator.next();\n            if (!curItem.done && curItem.value && !checkedEq) {\n                contractTrueEquality(\"Error building a HashSet\", curItem.value);\n                checkedEq = true;\n            }\n            while (!curItem.done) {\n                h.set(curItem.value, curItem.value);\n                curItem = iterator.next();\n            }\n        }));\n    }\n\n    /**\n     * Returns true if the element you give is present in\n     * the set, false otherwise.\n     */\n    contains(elt: T & WithEquality): boolean {\n        return this.hamt.has(elt);\n    }\n\n    /**\n     * Return a new collection where each element was transformed\n     * by the mapper function you give.\n     * The resulting set may be smaller than the source.\n     */\n    map<U>(mapper:(v:T)=>U&WithEquality): HashSet<U> {\n        return this.hamt.fold(\n            (acc: HashSet<U>, value: T&WithEquality, key: T&WithEquality) => {\n                return acc.add(mapper(value));\n            }, HashSet.empty());\n    }\n\n    /**\n     * Apply the mapper function on every element of this collection.\n     * The mapper function returns an Option; if the Option is a Some,\n     * the value it contains is added to the result Collection, if it's\n     * a None, the value is discarded.\n     *\n     *     HashSet.of(1,2,6).mapOption(x => x%2===0 ?\n     *         Option.of(x+1) : Option.none<number>())\n     *     => HashSet.of(3, 7)\n     */\n    mapOption<U>(mapper:(v:T)=>Option<U&WithEquality>): HashSet<U> {\n        return this.hamt.fold(\n            (acc: HashSet<U>, value: T&WithEquality, key: T&WithEquality) => {\n                const val = mapper(value);\n                return val.isSome() ? acc.add(val.get()) : acc\n            }, HashSet.empty());\n    }\n\n    /**\n     * Call a function for element in the collection.\n     */\n    forEach(fun:(x:T)=>void): HashSet<T> {\n        const iterator: Iterator<T> = this.hamt.values();\n        let curItem = iterator.next();\n        while (!curItem.done) {\n            fun(curItem.value);\n            curItem = iterator.next();\n        }\n        return this;\n    }\n\n    /**\n     * Calls the function you give for each item in the set,\n     * your function returns a set, all the sets are\n     * merged.\n     */\n    flatMap<U>(mapper:(v:T)=>HashSet<U&WithEquality>): HashSet<U> {\n        return this.foldLeft(HashSet.empty<U>(),\n                             (soFar,cur) => soFar.addAll(mapper(cur)));\n    }\n\n    /**\n     * Call a predicate for each element in the collection,\n     * build a new collection holding only the elements\n     * for which the predicate returned true.\n     */\n    filter<U extends T>(fn:(v:T)=>v is U): HashSet<U>;\n    filter(predicate:(v:T)=>boolean): HashSet<T>;\n    filter(predicate:(v:T)=>boolean): HashSet<T> {\n        return new HashSet<T>(\n            hamt.make({hash:this.hamt._config.hash, keyEq:this.hamt._config.keyEq}).mutate((h:any) => {\n                const iterator: Iterator<T> = this.hamt.values();\n                let curItem = iterator.next();\n                while (!curItem.done) {\n                    if (predicate(curItem.value)) {\n                        h.set(curItem.value, curItem.value);\n                    }\n                    curItem = iterator.next();\n                }\n            }));\n    }\n\n    /**\n     * Search for an item matching the predicate you pass,\n     * return Option.Some of that element if found,\n     * Option.None otherwise.\n     * We name the method findAny instead of find to emphasize\n     * that there is not ordering in a hashset.\n     *\n     *     HashSet.of(1,2,3).findAny(x => x>=3)\n     *     => Option.of(3)\n     *\n     *     HashSet.of(1,2,3).findAny(x => x>=4)\n     *     => Option.none<number>()\n     */\n    findAny(predicate:(v:T)=>boolean): Option<T> {\n        const iterator: Iterator<T> = this.hamt.values();\n        let curItem = iterator.next();\n        while (!curItem.done) {\n            if (predicate(curItem.value)) {\n                return Option.of(curItem.value);\n            }\n            curItem = iterator.next();\n        }\n        return Option.none<T>();\n    }\n\n    /**\n     * Reduces the collection to a single value using the\n     * associative binary function you give. Since the function\n     * is associative, order of application doesn't matter.\n     *\n     * Example:\n     *\n     *     HashSet.of(1,2,3).fold(0, (a,b) => a + b);\n     *     => 6\n     */\n    fold(zero:T, fn:(v1:T,v2:T)=>T): T {\n        return this.foldLeft(zero, fn);\n    }\n\n    /**\n     * Reduces the collection to a single value.\n     * Left-associative.\n     * No guarantees for the order of items in a hashset!\n     *\n     * Example:\n     *\n     *     HashSet.of(\"a\", \"bb\", \"ccc\").foldLeft(0, (soFar,item) => soFar+item.length);\n     *     => 6\n     *\n     * @param zero The initial value\n     * @param fn A function taking the previous value and\n     *           the current collection item, and returning\n     *           an updated value.\n     */\n    foldLeft<U>(zero: U, fn:(soFar:U,cur:T)=>U): U {\n        return this.hamt.fold(\n            (acc: U, v: T&WithEquality, k: T&WithEquality) =>\n                fn(acc, v), zero);\n    }\n\n    /**\n     * Reduces the collection to a single value.\n     * Right-associative.\n     * No guarantees for the order of items in a hashset!\n     *\n     * Example:\n     *\n     *     HashSet.of(\"a\", \"bb\", \"ccc\").foldRight(0, (item,soFar) => soFar+item.length);\n     *     => 6\n     *\n     * @param zero The initial value\n     * @param fn A function taking the current collection item and\n     *           the previous value , and returning\n     *           an updated value.\n     */\n    foldRight<U>(zero: U, fn:(cur:T, soFar:U)=>U): U {\n        return this.foldLeft(zero, (cur, soFar) => fn(soFar, cur));\n    }\n\n    /**\n     * Converts this set to an array. Since a Set is not ordered\n     * and since this method returns a JS array, it can be awkward\n     * to get an array sorted in the way you'd like. So you can pass\n     * an optional sorting function too.\n     *\n     *     HashSet.of(1,2,3).toArray().sort()\n     *     => [1,2,3]\n     *\n     *     HashSet.of(1,2,3).toArray({sortOn:x=>x})\n     *     => [1,2,3]\n     *\n     *     HashSet.of(1,2,3).toArray({sortBy:(x,y)=>x-y})\n     *     => [1,2,3]\n     *\n     * You can also pass an array in sortOn, listing lambdas to\n     * several fields to sort by those fields, and also {desc:lambda}\n     * to sort by some fields descending.\n     */\n    toArray(sort?: SortOnSpec<T> | SortBySpec<T>): Array<T & WithEquality> {\n        if (!sort) {\n            return Array.from<T&WithEquality>(this.hamt.keys());\n        }\n        if (isSortOnSpec(sort)) {\n            const sortOn = sort.sortOn instanceof Array ? sort.sortOn : [sort.sortOn];\n            return Vector.ofIterable<T&WithEquality>(this.hamt.keys())\n                .sortOn(...sortOn)\n                .toArray();\n        }\n        return Array.from<T&WithEquality>(this.hamt.keys()).sort(sort.sortBy);\n    }\n\n    /**\n     * Converts this set to an vector\n     */\n    toVector(): Vector<T & WithEquality> {\n        return Vector.ofIterable<T&WithEquality>(this.hamt.keys());\n    }\n\n    /**\n     * Converts this set to an list\n     */\n    toLinkedList(): LinkedList<T & WithEquality> {\n        return LinkedList.ofIterable<T&WithEquality>(this.hamt.keys());\n    }\n\n    /**\n     * Returns the number of elements in the set.\n     */\n    length(): number {\n        return this.hamt.size;\n    }\n\n    /**\n     * If the collection contains a single element,\n     * return Some of its value, otherwise return None.\n     */\n    single(): Option<T> {\n        return this.hamt.size === 1\n            ? Option.of(this.hamt.keys().next().value)\n            : Option.none();\n    }\n\n    /**\n     * true if the set is empty, false otherwise.\n     */\n    isEmpty(): boolean {\n        return this.hamt.size === 0;\n    }\n\n    /**\n     * Returns a new Set containing the difference\n     * between this set and the other Set passed as parameter.\n     * also see [[HashSet.intersect]]\n     */\n    diff(elts: ISet<T&WithEquality>): HashSet<T> {\n        return new HashSet<T>(this.hamt.fold(\n            (acc: any, v: T&WithEquality, k: T&WithEquality) =>\n                elts.contains(k) ? acc : acc.set(k,k), hamt.empty));\n    }\n\n    /**\n     * Returns a new Set containing the intersection\n     * of this set and the other Set passed as parameter\n     * (the elements which are common to both sets)\n     * also see [[HashSet.diff]]\n     */\n    intersect(other: ISet<T&WithEquality>): HashSet<T> {\n        return new HashSet<T>(this.hamt.fold(\n            (acc: any, v: T&WithEquality, k: T&WithEquality) =>\n                other.contains(k) ? acc.set(k,k) : acc, hamt.empty));\n    }\n\n    isSubsetOf(other: ISet<T&WithEquality>): boolean {\n        return this.allMatch((x:T) => other.contains(<T&WithEquality>x));\n    }\n\n    /**\n     * Returns a new set with the element you give removed\n     * if it was present in the set.\n     */\n    remove(elt: T&WithEquality): HashSet<T> {\n        return new HashSet<T>(this.hamt.remove(elt));\n    }\n\n    /**\n     * Returns a new set with all the elements of the current\n     * Set, minus the elements of the iterable you give as a parameter.\n     * If you call this function with a HashSet as parameter,\n     * rather call 'diff', as it'll be faster.\n     */\n    removeAll(elts: Iterable<T&WithEquality>): HashSet<T> {\n        return this.diff(HashSet.ofIterable<T&WithEquality>(elts));\n    }\n\n    /**\n     * Returns true if the predicate returns true for all the\n     * elements in the collection.\n     */\n    allMatch<U extends T>(predicate:(v:T)=>v is U): this is HashSet<U>;\n    allMatch(predicate:(v:T)=>boolean): boolean;\n    allMatch(predicate:(v:T)=>boolean): boolean {\n        const iterator: Iterator<T> = this.hamt.values();\n        let curItem = iterator.next();\n        while (!curItem.done) {\n            if (!predicate(curItem.value)) {\n                return false;\n            }\n            curItem = iterator.next();\n        }\n        return true;\n    }\n\n    /**\n     * Returns true if there the predicate returns true for any\n     * element in the collection.\n     */\n    anyMatch(predicate:(v:T)=>boolean): boolean {\n        const iterator: Iterator<T> = this.hamt.values();\n        let curItem = iterator.next();\n        while (!curItem.done) {\n            if (predicate(curItem.value)) {\n                return true;\n            }\n            curItem = iterator.next();\n        }\n        return false;\n    }\n\n    /**\n     * Group elements in the collection using a classifier function.\n     * Elements are then organized in a map. The key is the value of\n     * the classifier, and in value we get the list of elements\n     * matching that value.\n     *\n     * also see [[HashSet.arrangeBy]]\n     */\n    groupBy<C>(classifier: (v:T)=>C&WithEquality): HashMap<C,HashSet<T>> {\n        // make a singleton set with the same equality as this\n        const singletonHamtSet = (v:T) => hamt.make({\n            hash:this.hamt._config.hash, keyEq:this.hamt._config.keyEq\n        }).set(v,v);\n        // merge two mutable hamt sets, but I know the second has only 1 elt\n        const mergeSets = (v1:any,v2:any)=> {\n            const k = v2.keys().next().value;\n            v1.set(k,k);\n            return v1;\n        };\n        return this.hamt.fold(\n            // fold operation: combine a new value from the set with the accumulator\n            (acc: HashMap<C,any>, v:T&WithEquality, k:T&WithEquality) =>\n                acc.putWithMerge(\n                    classifier(v), singletonHamtSet(v).beginMutation(),\n                    mergeSets),\n            // fold accumulator: the empty hashmap\n            HashMap.empty())\n            .mapValues((h:any) => new HashSet<T>(h.endMutation()));\n    }\n\n    /**\n     * Matches each element with a unique key that you extract from it.\n     * If the same key is present twice, the function will return None.\n     *\n     * also see [[HashSet.groupBy]]\n     */\n    arrangeBy<K>(getKey: (v:T)=>K&WithEquality): Option<HashMap<K,T>> {\n        return SeqHelpers.arrangeBy<T,K>(this, getKey);\n    }\n\n    /**\n     * Returns a pair of two sets; the first one\n     * will only contain the items from this sets for\n     * which the predicate you give returns true, the second\n     * will only contain the items from this collection where\n     * the predicate returns false.\n     *\n     *     HashSet.of(1,2,3,4).partition(x => x%2===0)\n     *     => [HashSet.of(2,4), HashSet.of(1,3)]\n     */\n    partition<U extends T>(predicate:(v:T)=>v is U): [HashSet<U>,HashSet<Exclude<T,U>>];\n    partition(predicate:(x:T)=>boolean): [HashSet<T>,HashSet<T>];\n    partition(predicate:(v:T)=>boolean): [HashSet<T>,HashSet<T>] {\n        let r1 = hamt.make({\n            hash:this.hamt._config.hash, keyEq:this.hamt._config.keyEq\n        }).beginMutation();\n        let r2 = hamt.make({\n            hash:this.hamt._config.hash, keyEq:this.hamt._config.keyEq\n        }).beginMutation();\n        const iterator: Iterator<T&WithEquality> = this.hamt.values();\n        let curItem = iterator.next();\n        while (!curItem.done) {\n            if (predicate(curItem.value)) {\n                r1.set(curItem.value, curItem.value);\n            } else {\n                r2.set(curItem.value, curItem.value);\n            }\n            curItem = iterator.next();\n        }\n        return [new HashSet<T>(r1), new HashSet<T>(r2)];\n    }\n\n    /**\n     * Reduces the collection to a single value by repeatedly\n     * calling the combine function.\n     * No starting value. The order in which the elements are\n     * passed to the combining function is undetermined.\n     */\n    reduce(combine: (v1:T,v2:T)=>T): Option<T> {\n        return SeqHelpers.reduce(this, combine);\n    }\n\n    /**\n     * Compare values in the collection and return the smallest element.\n     * Returns Option.none if the collection is empty.\n     *\n     * also see [[HashSet.minOn]]\n     */\n    minBy(compare: (v1:T,v2:T)=>Ordering): Option<T> {\n        return SeqHelpers.minBy(this, compare);\n    }\n\n    /**\n     * Call the function you give for each value in the collection\n     * and return the element for which the result was the smallest.\n     * Returns Option.none if the collection is empty.\n     *\n     * also see [[HashSet.minBy]]\n     */\n    minOn(getOrderable: ToOrderable<T>): Option<T> {\n        return SeqHelpers.minOn(this, getOrderable);\n    }\n\n    /**\n     * Compare values in the collection and return the largest element.\n     * Returns Option.none if the collection is empty.\n     *\n     * also see [[HashSet.maxOn]]\n     */\n    maxBy(compare: (v1:T,v2:T)=>Ordering): Option<T> {\n        return SeqHelpers.maxBy(this, compare);\n    }\n\n    /**\n     * Call the function you give for each value in the collection\n     * and return the element for which the result was the largest.\n     * Returns Option.none if the collection is empty.\n     *\n     * also see [[HashSet.maxBy]]\n     */\n    maxOn(getOrderable: ToOrderable<T>): Option<T> {\n        return SeqHelpers.maxOn(this, getOrderable);\n    }\n\n    /**\n     * Call the function you give for each element in the collection\n     * and sum all the numbers, return that sum.\n     * Will return 0 if the collection is empty.\n     *\n     *     HashSet.of(1,2,3).sumOn(x=>x)\n     *     => 6\n     */\n    sumOn(getNumber: (v:T)=>number): number {\n        return SeqHelpers.sumOn(this, getNumber);\n    }\n\n    /**\n     * Transform this value to another value type.\n     * Enables fluent-style programming by chaining calls.\n     */\n    transform<U>(converter:(x:HashSet<T>)=>U): U {\n        return converter(this);\n    }\n\n    /**\n     * Convert to an ES6 Set.\n     * You must provide a function to convert the\n     * key to a string, number or boolean, because\n     * with other types equality is not correctly\n     * managed by JS.\n     * https://stackoverflow.com/questions/29759480/how-to-customize-object-equality-for-javascript-set\n     * https://esdiscuss.org/topic/maps-with-object-keys\n     *\n     *     HashSet.of(\"a\", \"b\").toJsSet(x=>x);\n     *     => new Set([\"a\", \"b\"])\n     */\n    toJsSet(keyConvert:(k:T)=>string): Set<string>;\n    toJsSet(keyConvert:(k:T)=>number): Set<number>;\n    toJsSet(keyConvert:(k:T)=>boolean): Set<boolean>;\n    toJsSet<K extends string|number|boolean>(keyConvert:(k:T)=>K): Set<K> {\n        return this.foldLeft(new Set<K>(), (sofar,cur) => sofar.add(keyConvert(cur)));\n    }\n\n    /**\n     * Two objects are equal if they represent the same value,\n     * regardless of whether they are the same object physically\n     * in memory.\n     */\n    equals(other: HashSet<T>): boolean {\n        if (<any>other === this) {\n            return true;\n        }\n        const sz = this.hamt.size;\n        if (other === <EmptyHashSet<T>>emptyHashSet && sz === 0) {\n            // we could get that i'm not the empty map\n            // but my size is zero, after some filtering and such.\n            return true;\n        }\n        if (!other || !other.hamt) {\n            return false;\n        }\n        if (sz !== other.hamt.size) {\n            return false;\n        }\n        contractTrueEquality(\"HashSet.equals\", this, other);\n        const keys: Array<T & WithEquality> = Array.from<T & WithEquality>(this.hamt.keys());\n        for (let k of keys) {\n            const hisVal: T & WithEquality|null|undefined = other.hamt.get(k);\n            if (hisVal === undefined) {\n                return false;\n            }\n            if (!areEqual(k, hisVal)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Get a number for that object. Two different values\n     * may get the same number, but one value must always get\n     * the same number. The formula can impact performance.\n     */\n    hashCode(): number {\n        return this.hamt.fold(\n            (acc: number, value: T & WithEquality, key: T & WithEquality) =>\n                acc + getHashCode(key), 0);\n    }\n\n    /**\n     * Get a human-friendly string representation of that value.\n     *\n     * Also see [[HashSet.mkString]]\n     */\n    toString(): string {\n        return \"HashSet(\" +\n            this.hamt.fold(\n                (acc: string[], value: T, key: T) =>\n                    {acc.push(SeqHelpers.toStringHelper(key)); return acc;}, []).join(\", \")\n            + \")\";\n    }\n\n    [inspect](): string {\n        return this.toString();\n    }\n\n    /**\n     * Joins elements of the collection by a separator.\n     * Example:\n     *\n     *     HashSet.of(1,2,3).mkString(\", \")\n     *     => \"1, 2, 3\"\n     *\n     * (of course, order is not guaranteed)\n     */\n    mkString(separator: string): string {\n        return this.hamt.fold(\n            (acc: string[], value: T, key: T) =>\n                {acc.push(SeqHelpers.toStringHelper(key, {quoteStrings: false})); return acc;}, []).join(separator);\n    }\n}\n\n// we need to override the empty hashmap\n// because i don't know how to get the hash & keyset\n// functions for the keys without a key value to get\n// the functions from\nclass EmptyHashSet<T> extends HashSet<T> {\n\n    constructor() {\n        super({}); // we must override all the functions\n    }\n\n    add(elt: T & WithEquality): HashSet<T> {\n        contractTrueEquality(\"Error building a HashSet\", elt);\n        if (!elt) {\n            // special case if we get null for the first element...\n            // less optimized variant because we don't know\n            // if we should use '===' or 'equals'\n            return new HashSet<T>(hamt.make({\n                hash: (v: T & HasEquals) => getHashCode(v),\n                keyEq: (a: T & HasEquals, b: T & HasEquals) => areEqual(a, b)\n            }).set(elt,elt));\n        }\n        // if the element is not null, save a if later by finding\n        // out right now whether we should call equals or ===\n        if (hasEquals(elt)) {\n            return new HashSet<T>(hamt.make({\n                hash: (v: T & HasEquals) => v.hashCode(),\n                keyEq: (a: T & HasEquals, b: T & HasEquals) => a.equals(b)\n            }).set(elt,elt));\n        }\n        return new HashSet<T>(hamt.make().set(elt,elt));\n    }\n\n    addAll(elts: Iterable<T & WithEquality>): HashSet<T> {\n        const it = elts[Symbol.iterator]();\n        let curItem = it.next();\n        if (curItem.done) {\n            return <EmptyHashSet<T>>emptyHashSet;\n        }\n        return this.add(curItem.value).addAll({[Symbol.iterator]: () => it});\n    }\n\n    contains(elt: T & WithEquality): boolean {\n        return false;\n    }\n\n    map<U>(mapper:(v:T)=>U&WithEquality): HashSet<U> {\n        return <EmptyHashSet<U>>emptyHashSet;\n    }\n\n    mapOption<U>(mapper:(v:T)=>Option<U&WithEquality>): HashSet<U> {\n        return <EmptyHashSet<U>>emptyHashSet;\n    }\n\n    forEach(fun:(x:T)=>void): HashSet<T> {\n        return this;\n    }\n\n    filter<U extends T>(fn:(v:T)=>v is U): HashSet<U>;\n    filter(predicate:(v:T)=>boolean): HashSet<T>;\n    filter(predicate:(v:T)=>boolean): HashSet<T> {\n        return this;\n    }\n\n    findAny(predicate:(v:T)=>boolean): Option<T> {\n        return Option.none();\n    }\n\n    foldLeft<U>(zero: U, fn:(soFar:U,cur:T)=>U): U {\n        return zero;\n    }\n\n    toArray(sort?: SortOnSpec<T> | SortBySpec<T>): Array<T & WithEquality> {\n        return [];\n    }\n\n    toVector(): Vector<T & WithEquality> {\n        return Vector.empty<T&WithEquality>();\n    }\n\n    toLinkedList(): LinkedList<T & WithEquality> {\n        return LinkedList.empty<T&WithEquality>();\n    }\n\n    [Symbol.iterator](): Iterator<T> {\n        return { next: () => ({ done: true, value: <any>undefined }) };\n    }\n\n    length(): number {\n        return 0;\n    }\n\n    isEmpty(): boolean {\n        return true;\n    }\n\n    diff(elts: ISet<T&WithEquality>): HashSet<T> {\n        return this;\n    }\n\n    intersect(other: ISet<T&WithEquality>): HashSet<T> {\n        return this;\n    }\n\n    anyMatch(predicate:(v:T)=>boolean): boolean {\n        return false;\n    }\n\n    groupBy<C>(classifier: (v:T)=>C&WithEquality): HashMap<C,HashSet<T>> {\n        return HashMap.empty();\n    }\n\n    allMatch<U extends T>(predicate:(v:T)=>v is U): this is HashSet<U>;\n    allMatch(predicate:(v:T)=>boolean): boolean;\n    allMatch(predicate:(v:T)=>boolean): boolean {\n        return true;\n    }\n\n    partition<U extends T>(predicate:(v:T)=>v is U): [HashSet<U>,HashSet<Exclude<T,U>>];\n    partition(predicate:(x:T)=>boolean): [HashSet<T>,HashSet<T>];\n    partition<U extends T>(predicate:(v:T)=>boolean): [HashSet<U>,HashSet<any>] {\n        return [<any>this, <any>this];\n    }\n\n    remove(elt: T&WithEquality): HashSet<T> {\n        return this;\n    }\n\n    equals(other: HashSet<T>): boolean {\n        if (!other || !other.length) {\n            return false;\n        }\n        return <any>other === emptyHashSet || other.length() === 0;\n    }\n\n    hashCode(): number {\n        return 0;\n    }\n\n    toString(): string {\n        return \"HashSet()\";\n    }\n\n    mkString(separator: string): string {\n        return \"\";\n    }\n}\n\nconst emptyHashSet = new EmptyHashSet<any>();\n"
  },
  {
    "path": "src/IMap.ts",
    "content": "import { WithEquality } from \"./Comparison\";\nimport { Option } from \"./Option\";\nimport { Value } from \"./Value\"\nimport { ISet } from \"./ISet\";\nimport { Vector } from \"./Vector\";\nimport { LinkedList } from \"./LinkedList\";\nimport { Foldable } from \"./Foldable\";\n\n/**\n * A generic interface for a dictionary, mapping keys to values.\n * @param K the key type\n * @param V the value type\n */\nexport interface IMap<K,V> extends Value, Iterable<[K,V]>, Foldable<[K,V]> {\n\n    /**\n     * Get a Set containing all the keys in the map\n     */\n    keySet(): ISet<K>;\n\n    /**\n     * Get an iterable containing all the values in the map\n     * (can't return a set as we don't constrain map values\n     * to have equality in the generics type)\n     */\n    valueIterable(): Iterable<V>;\n\n    /**\n     * Get the value for the key you give, if the key is present.\n     */\n    get(k: K & WithEquality): Option<V>;\n\n    /**\n     * Add a new entry in the map. If there was entry with the same\n     * key, it will be overwritten.\n     * @param k the key\n     * @param v the value\n     */\n    put(k: K & WithEquality, v: V): IMap<K,V>;\n\n\n    /**\n     * Return a new map with the key you give removed.\n     */\n    remove(k: K&WithEquality): IMap<K,V>;\n\n    /**\n     * Add a new entry in the map; in case there was already an\n     * entry with the same key, the merge function will be invoked\n     * with the old and the new value to produce the value to take\n     * into account.\n     * @param k the key\n     * @param v the value\n     * @param merge a function to merge old and new values in case of conflict.\n     */\n    putWithMerge(k: K & WithEquality, v: V, merge: (v1: V, v2: V) => V): IMap<K,V>;\n\n    /**\n     * Return a new map where each entry was transformed\n     * by the mapper function you give. You return key,value\n     * as pairs.\n     */\n    map<K2,V2>(fn:(k:K&WithEquality, v:V)=>[K2&WithEquality,V2]): IMap<K2,V2>;\n\n    /**\n     * Return a new map where keys are the same as in this one,\n     * but values are transformed\n     * by the mapper function you give. You return key,value\n     * as pairs.\n     */\n    mapValues<V2>(fn:(v:V)=>V2): IMap<K,V2>;\n\n    /**\n     * Call a function for element in the collection.\n     */\n    forEach(fun:(x:[K,V])=>void):IMap<K,V>;\n\n    /**\n     * Calls the function you give for each item in the map,\n     * your function returns a map, all the maps are\n     * merged.\n     */\n    flatMap<K2,V2>(fn:(k:K, v:V)=>Iterable<[K2&WithEquality,V2]>): IMap<K2,V2>;\n\n    /**\n     * Convert this map to a vector of key,value pairs.\n     * Note that Map is already an iterable of key,value pairs!\n     */\n    toVector(): Vector<[K,V]>;\n\n    /**\n     * Convert this map to a List of key,value pairs.\n     * Note that Map is already an iterable of key,value pairs!\n     */\n    toLinkedList(): LinkedList<[K,V]>;\n\n    /**\n     * Convert to array.\n     */\n    toArray(): Array<[K,V]>;\n\n    /**\n     * Convert to a javascript object dictionary\n     * You must provide a function to convert the\n     * key to a string.\n     *\n     *     HashMap.of<string,number>([\"a\",1],[\"b\",2])\n     *         .toObjectDictionary(x=>x);\n     *     => {a:1,b:2}\n     */\n    toObjectDictionary(keyConvert:(k:K)=>string): {[index:string]:V};\n\n    /**\n     * Convert to an ES6 Map.\n     * You must provide a function to convert the\n     * key to a string, number or boolean, because\n     * with other types equality is not correctly\n     * managed by JS.\n     * https://stackoverflow.com/questions/29759480/how-to-customize-object-equality-for-javascript-set\n     * https://esdiscuss.org/topic/maps-with-object-keys\n     *\n     *     HashMap.of<string,number>([\"a\",1],[\"b\",2])\n     *         .toJsMap(x=>x);\n     *     => new Map([[\"a\",1], [\"b\",2]])\n     */\n    toJsMap(keyConvert:(k:K)=>string): Map<string,V>;\n    toJsMap(keyConvert:(k:K)=>number): Map<number,V>;\n    toJsMap(keyConvert:(k:K)=>boolean): Map<boolean,V>;\n\n    /**\n     * number of items in the map\n     */\n    length(): number;\n\n    /**\n     * true if the map is empty, false otherwise.\n     */\n    isEmpty(): boolean;\n\n    /**\n     * Create a new map combining the entries of this map, and\n     * the other map you give. In case an entry from this map\n     * and the other map have the same key, the merge function\n     * will be invoked to get a combined value.\n     * @param other another map to merge with this one\n     * @param merge a merge function to combine two values\n     *        in case two entries share the same key.\n     */\n    mergeWith(other: Iterable<[K & WithEquality,V]>, merge:(v1: V, v2: V) => V): IMap<K,V>;\n\n    /**\n     * Transform this value to another value type.\n     * Enables fluent-style programming by chaining calls.\n     */\n    transform<U>(converter:(x:IMap<K,V>)=>U): U;\n\n    /**\n     * Returns true if the predicate returns true for all the\n     * elements in the collection.\n     */\n    allMatch(predicate:(k:K,v:V)=>boolean): boolean;\n\n    /**\n     * Returns true if there the predicate returns true for any\n     * element in the collection.\n     */\n    anyMatch(predicate:(k:K,v:V)=>boolean): boolean;\n\n    /**\n     * Returns true if the item is in the collection,\n     * false otherwise.\n     */\n    contains(val: [K&WithEquality,V&WithEquality]): boolean;\n\n    /**\n     * Returns true if there is item with that key in the collection,\n     * false otherwise.\n     */\n    containsKey(key: K&WithEquality): boolean;\n\n    /**\n     * Call a predicate for each element in the collection,\n     * build a new collection holding only the elements\n     * for which the predicate returned true.\n     */\n    filter(predicate:(k:K,v:V)=>boolean): IMap<K,V>;\n\n    /**\n     * Call a predicate for each key in the collection,\n     * build a new collection holding only the elements\n     * for which the predicate returned true.\n     */\n    filterKeys<U extends K>(fn:(v:K)=>v is U): IMap<U,V>\n    filterKeys(predicate:(k:K)=>boolean): IMap<K,V>;\n\n    /**\n     * Call a predicate for each value in the collection,\n     * build a new collection holding only the elements\n     * for which the predicate returned true.\n     */\n    filterValues<U extends V>(fn:(v:V)=>v is U): IMap<K,U>\n    filterValues(predicate:(v:V)=>boolean): IMap<K,V>;\n}\n"
  },
  {
    "path": "src/ISet.ts",
    "content": "import { WithEquality, Ordering, ToOrderable } from \"./Comparison\";\nimport { Value} from \"./Value\";\nimport { Collection } from \"./Collection\";\nimport { Vector } from \"./Vector\";\nimport { LinkedList } from \"./LinkedList\";\nimport { Option } from \"./Option\";\n\n/**\n * Ability to specify a sorting function.\n * See [[Seq.sortOn]].\n *\n * You can give a lambda getting a sortable value (number or string) from your\n * object, or a list of lambdas, and in the list you can also put {desc:lambda}\n * items to request descending sorting\n *\n * `{sortOn: ToOrderable<T>|Array<ToOrderable<T>|{desc:ToOrderable<T>}>}`\n */\nexport type SortOnSpec<T> = {sortOn: ToOrderable<T>|Array<ToOrderable<T>|{desc:ToOrderable<T>}>};\n\n/**\n * Ability to specify a sorting function.\n * See [[Seq.sortBy]].\n *\n * `{sortBy: (v1:T,v2:T)=>Ordering}`\n */\nexport type SortBySpec<T> = {sortBy: (v1:T,v2:T)=>Ordering};\n\n/**\n * @hidden\n */\nexport function isSortOnSpec<T>(sortSpec: SortOnSpec<T> | SortBySpec<T>): sortSpec is SortOnSpec<T> {\n    return (<any>sortSpec).sortOn !== undefined;\n}\n\n/**\n * A generic interface for set-like implementations.\n * @param T the item type\n */\nexport interface ISet<T> extends Collection<T> {\n\n    /**\n     * Returns the number of elements in the set.\n     */\n    length(): number;\n\n    /**\n     * true if the set is empty, false otherwise.\n     */\n    isEmpty(): boolean;\n\n    /**\n     * Add an element to this set.\n     */\n    add(elt: T & WithEquality): ISet<T>;\n\n    /**\n     * Add multiple elements to this set.\n     */\n    addAll(elts: Iterable<T & WithEquality>): ISet<T>;\n\n    /**\n     * Returns true if the element you give is present in\n     * the set, false otherwise.\n     */\n    contains(elt: T & WithEquality): boolean;\n\n    /**\n     * Return a new collection where each element was transformed\n     * by the mapper function you give.\n     * The resulting set may be smaller than the source.\n     */\n    map<U>(mapper:(v:T)=>U&WithEquality): ISet<U>;\n\n    /**\n     * Apply the mapper function on every element of this collection.\n     * The mapper function returns an Option; if the Option is a Some,\n     * the value it contains is added to the result Collection, if it's\n     * a None, the value is discarded.\n     */\n    mapOption<U>(mapper:(v:T)=>Option<U&WithEquality>): ISet<U>;\n\n    /**\n     * Call a function for element in the collection.\n     */\n    forEach(fun:(x:T)=>void):ISet<T>;\n\n    /**\n     * Calls the function you give for each item in the set,\n     * your function returns a set, all the sets are\n     * merged.\n     */\n    flatMap<U>(mapper:(v:T)=>ISet<U&WithEquality>): ISet<U>;\n\n    /**\n     * Returns a new Set containing the difference\n     * between this set and the other Set passed as parameter.\n     * also see [[ISet.intersect]]\n     */\n    diff(other: ISet<T&WithEquality>): ISet<T>;\n\n    /**\n     * Returns a new Set containing the intersection\n     * of this set and the other Set passed as parameter\n     * (the elements which are common to both sets)\n     * also see [[ISet.diff]]\n     */\n    intersect(other: ISet<T&WithEquality>): ISet<T>;\n\n    /**\n     * Returns whether this set is a subset of the\n     * set you give as parameter (will return true\n     * also if both sets are equal)\n     */\n    isSubsetOf(other: ISet<T&WithEquality>): boolean;\n\n    /**\n     * Returns a new set with all the elements of the current\n     * Set, minus the elements of the iterable you give as a parameter.\n     * If you call this function with a HashSet as parameter,\n     * rather call 'diff', as it'll be faster.\n     */\n    removeAll(elts: Iterable<T&WithEquality>): ISet<T>;\n\n    /**\n     * Returns true if the predicate returns true for all the\n     * elements in the collection.\n     */\n    allMatch<U extends T>(predicate:(v:T)=>v is U): this is ISet<U>;\n    allMatch(predicate:(v:T)=>boolean): boolean;\n\n    /**\n     * Returns true if there the predicate returns true for any\n     * element in the collection.\n     */\n    anyMatch(predicate:(v:T)=>boolean): boolean;\n\n    /**\n     * Transform this value to another value type.\n     * Enables fluent-style programming by chaining calls.\n     */\n    transform<U>(converter:(x:ISet<T>)=>U): U;\n\n    /**\n     * Converts this set to an array. Since a Set is not ordered\n     * and since this method returns a JS array, it can be awkward\n     * to get an array sorted in the way you'd like. So you can pass\n     * an optional sorting function too.\n     *\n     *     HashSet.of(1,2,3).toArray().sort()\n     *     => [1,2,3]\n     *\n     *     HashSet.of(1,2,3).toArray({sortOn:x=>x})\n     *     => [1,2,3]\n     *\n     *     HashSet.of(1,2,3).toArray({sortBy:(x,y)=>x-y})\n     *     => [1,2,3]\n     *\n     * You can also pass an array in sortOn, listing lambdas to\n     * several fields to sort by those fields, and also {desc:lambda}\n     * to sort by some fields descending.\n     */\n    toArray(sort?: SortOnSpec<T> | SortBySpec<T>): Array<T & WithEquality>;\n\n    /**\n     * Converts this set to an vector\n     */\n    toVector(): Vector<T & WithEquality>;\n\n    /**\n     * Converts this set to an list\n     */\n    toLinkedList(): LinkedList<T & WithEquality>;\n\n    /**\n     * Convert to an ES6 Set.\n     * You must provide a function to convert the\n     * key to a string, number or boolean, because\n     * with other types equality is not correctly\n     * managed by JS.\n     * https://stackoverflow.com/questions/29759480/how-to-customize-object-equality-for-javascript-set\n     * https://esdiscuss.org/topic/maps-with-object-keys\n     *\n     *     HashSet.of(\"a\", \"b\").toJsSet(x=>x);\n     *     => new Set([\"a\", \"b\"])\n     */\n    toJsSet(keyConvert:(k:T)=>string): Set<string>;\n    toJsSet(keyConvert:(k:T)=>number): Set<number>;\n    toJsSet(keyConvert:(k:T)=>boolean): Set<boolean>;\n}\n"
  },
  {
    "path": "src/Lazy.ts",
    "content": "import { inspect } from \"./Value\";\nimport { toStringHelper } from \"./SeqHelpers\";\n\n/**\n * Represent a lazily evaluated value. You give a function which\n * will return a value; that function is only called when the value\n * is requested from Lazy, but it will be computed at most once.\n * If the value is requested again, the previously computed result\n * will be returned: Lazy is memoizing.\n */\nexport class Lazy<T> {\n\n    private thunk: (()=>T)|undefined;\n    private value: T|undefined;\n\n    private constructor(thunk: ()=>T) {\n        this.thunk = thunk;\n    }\n    \n    /**\n     * Build a Lazy from a computation returning a value.\n     * The computation will be called at most once.\n     */\n    static of<T>(thunk: ()=>T) {\n        return new Lazy(thunk);\n    }\n\n    /**\n     * Evaluate the value, cache its value, and return it, or return the\n     * previously computed value.\n     */\n    get(): T {\n        if (this.thunk) {\n            this.value = this.thunk();\n            this.thunk = undefined;\n        }\n        return <T>this.value;\n    }\n\n    /**\n     * Returns true if the computation underlying this Lazy was already\n     * performed, false otherwise.\n     */\n    isEvaluated(): boolean {\n        return this.thunk === undefined;\n    }\n\n    /**\n     * Return a new lazy where the element was transformed\n     * by the mapper function you give.\n     */\n    map<U>(mapper:(v:T)=>U): Lazy<U> {\n        return new Lazy(()=>mapper(this.get()));\n    }\n\n    /**\n     * Get a human-friendly string representation of that value.\n     */\n    toString(): string {\n        return this.isEvaluated() ?\n            `Lazy(${toStringHelper(this.get())})` :\n            \"Lazy(?)\";\n    }\n\n    /**\n     * Used by the node REPL to display values.\n     * Most of the time should be the same as toString()\n     */\n    [inspect](): string {\n        return this.toString();\n    }\n}\n"
  },
  {
    "path": "src/LinkedList.ts",
    "content": "/**\n * A sequence of values, organized in-memory as a strict linked list.\n * Each element has an head (value) and a tail (the rest of the list).\n *\n * The code is organized through the class [[EmptyLinkedList]] (empty list\n * or tail), the class [[ConsLinkedList]] (list value and pointer to next),\n * and the type alias [[LinkedList]] (empty or cons).\n *\n * Finally, \"static\" functions on Option are arranged in the class\n * [[LinkedListStatic]] and are accessed through the global constant LinkedList.\n *\n * Random access is expensive, appending is expensive, prepend or getting\n * the tail of the list is very cheap.\n * If you often need random access you should rather use [[Vector]].\n * Avoid appending at the end of the list in a loop, prefer prepending and\n * then reversing the list.\n *\n * Examples:\n *\n *     LinkedList.of(1,2,3);\n *     LinkedList.of(1,2,3).map(x => x*2).last();\n */\nimport { Option, Some, None } from \"./Option\";\nimport { Vector } from \"./Vector\";\nimport { WithEquality, getHashCode,\n         areEqual, Ordering, ToOrderable } from \"./Comparison\";\nimport { contractTrueEquality } from \"./Contract\";\nimport { inspect } from \"./Value\";\nimport { HashMap } from \"./HashMap\";\nimport { HashSet } from \"./HashSet\";\nimport { Seq, IterableArray } from \"./Seq\";\nimport { Stream } from \"./Stream\";\nimport * as SeqHelpers from \"./SeqHelpers\";\n\n/**\n * Holds the \"static methods\" for [[LinkedList]]\n */\nexport class LinkedListStatic {\n    /**\n     * The empty stream\n     */\n    empty<T>(): LinkedList<T> {\n        return <EmptyLinkedList<T>>emptyLinkedList;\n    }\n\n    /**\n     * Create a LinkedList with the elements you give.\n     */\n    of<T>(elt: T, ...elts:T[]): ConsLinkedList<T>;\n    of<T>(...elts:T[]): LinkedList<T>;\n    of<T>(...elts:T[]): LinkedList<T> {\n        return LinkedList.ofIterable(elts);\n    }\n\n    /**\n     * Build a stream from any iterable, which means also\n     * an array for instance.\n     * @param T the item type\n     */\n    ofIterable<T>(elts: Iterable<T>): LinkedList<T> {\n        const iterator = elts[Symbol.iterator]();\n        let curItem = iterator.next();\n        let result: LinkedList<T> = <EmptyLinkedList<T>>emptyLinkedList;\n        while (!curItem.done) {\n            result = new ConsLinkedList(curItem.value, result);\n            curItem = iterator.next();\n        }\n        return result.reverse();\n    }\n\n    /**\n     * Curried type guard for LinkedList.\n     * Sometimes needed also due to https://github.com/Microsoft/TypeScript/issues/20218\n     *\n     *     Vector.of(LinkedList.of(1), LinkedList.empty<number>())\n     *         .filter(LinkedList.isEmpty)\n     *     => Vector.of(LinkedList.empty<number>())\n     */\n    isEmpty<T>(l: LinkedList<T>): l is EmptyLinkedList<T> {\n        return l.isEmpty();\n    }\n\n    /**\n     * Curried type guard for LinkedList.\n     * Sometimes needed also due to https://github.com/Microsoft/TypeScript/issues/20218\n     *\n     *     Vector.of(Stream.of(1), Stream.empty<number>())\n     *         .filter(Stream.isNotEmpty)\n     *         .map(s => s.head().get()+1)\n     *     => Vector.of(2)\n     */\n    isNotEmpty<T>(l: LinkedList<T>): l is ConsLinkedList<T> {\n        return !l.isEmpty();\n    }\n\n    /**\n     * Dual to the foldRight function. Build a collection from a seed.\n     * Takes a starting element and a function.\n     * It applies the function on the starting element; if the\n     * function returns None, it stops building the list, if it\n     * returns Some of a pair, it adds the first element to the result\n     * and takes the second element as a seed to keep going.\n     *\n     *     LinkedList.unfoldRight(\n     *          10, x=>Option.of(x)\n     *              .filter(x => x!==0)\n     *              .map<[number,number]>(x => [x,x-1]))\n     *     => LinkedList.of(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)\n     */\n    unfoldRight<T,U>(seed: T, fn: (x:T)=>Option<[U,T]>): LinkedList<U> {\n        let nextVal = fn(seed);\n        let result = <LinkedList<U>><EmptyLinkedList<U>>emptyLinkedList;\n        while (!nextVal.isNone()) {\n            result = new ConsLinkedList(\n                nextVal.get()[0],\n                result);\n            nextVal = fn(nextVal.get()[1]);\n        }\n        return result.reverse();\n    }\n\n    /**\n     * Combine any number of iterables you give in as\n     * parameters to produce a new collection which combines all,\n     * in tuples. For instance:\n     *\n     *     LinkedList.zip(LinkedList.of(1,2,3), [\"a\",\"b\",\"c\"], Vector.of(8,9,10))\n     *     => LinkedList.of([1,\"a\",8], [2,\"b\",9], [3,\"c\",10])\n     *\n     * The result collection will have the length of the shorter\n     * of the input iterables. Extra elements will be discarded.\n     *\n     * Also see the non-static version [[ConsLinkedList.zip]], which only combines two\n     * collections.\n     * @param A A is the type of the tuple that'll be generated\n     *          (`[number,string,number]` for the code sample)\n     */\n    zip<A extends any[]>(...iterables: IterableArray<A>): LinkedList<A> {\n        let r = LinkedList.empty<A>();\n        const iterators = iterables.map(i => i[Symbol.iterator]());\n        let items = iterators.map(i => i.next());\n\n        while (!items.some(item => item.done)) {\n            r = r.prepend(<any>items.map(item => item.value));\n            items = iterators.map(i => i.next());\n        }\n        return r.reverse();\n    }\n}\n\n/**\n * The LinkedList constant allows to call the LinkedList \"static\" methods\n */\nexport const LinkedList = new LinkedListStatic();\n\n/**\n * A LinkedList is either [[EmptyLinkedList]] or [[ConsLinkedList]]\n * \"static methods\" available through [[LinkedListStatic]]\n * @param T the item type\n */\nexport type LinkedList<T> = EmptyLinkedList<T> | ConsLinkedList<T>;\n\n/**\n * EmptyLinkedList is the empty linked list; every non-empty\n * linked list also has a pointer to an empty linked list\n * after its last element.\n * \"static methods\" available through [[LinkedListStatic]]\n * @param T the item type\n */\nexport class EmptyLinkedList<T> implements Seq<T> {\n\n    /**\n     * @hidden\n     */\n    hasTrueEquality(): boolean {\n        return SeqHelpers.seqHasTrueEquality<T>(this);\n    }\n\n    /**\n     * Implementation of the Iterator interface.\n     */\n    [Symbol.iterator](): Iterator<T> {\n        return {\n            next(): IteratorResult<T> {\n                return {\n                    done: true,\n                    value: <any>undefined\n                };\n            }\n        }\n    }\n\n    /**\n     * @hidden\n     */\n    readonly className: \"EmptyLinkedList\" = <any>undefined;  // https://stackoverflow.com/a/47841595/516188\n\n    /**\n     * View this Some a as LinkedList. Useful to help typescript type\n     * inference sometimes.\n     */\n    asLinkedList(): LinkedList<T> {\n        return this;\n    }\n\n    /**\n     * Get the length of the collection.\n     */\n    length(): number {\n        return 0;\n    }\n\n    /**\n     * If the collection contains a single element,\n     * return Some of its value, otherwise return None.\n     */\n    single(): Option<T> {\n        return Option.none<T>();\n    }\n\n    /**\n     * true if the collection is empty, false otherwise.\n     */\n    isEmpty(): this is EmptyLinkedList<T> {\n        return true;\n    }\n\n    /**\n     * Get the first value of the collection, if any.\n     * In this case the list is empty, so returns Option.none\n     */\n    head(): None<T> {\n        return <None<T>>Option.none<T>();\n    }\n\n    /**\n     * Get all the elements in the collection but the first one.\n     * If the collection is empty, return None.\n     */\n    tail(): Option<LinkedList<T>> {\n        return Option.none<LinkedList<T>>();\n    }\n\n    /**\n     * Get the last value of the collection, if any.\n     * returns Option.Some if the collection is not empty,\n     * Option.None if it's empty.\n     */\n    last(): Option<T> {\n        return Option.none<T>();\n    }\n\n    /**\n     * Retrieve the element at index idx.\n     * Returns an option because the collection may\n     * contain less elements than the index.\n     *\n     * Careful this is going to have poor performance\n     * on LinkedList, which is not a good data structure\n     * for random access!\n     */\n    get(idx: number): Option<T> {\n        return Option.none<T>();\n    }\n\n    /**\n     * Search for an item matching the predicate you pass,\n     * return Option.Some of that element if found,\n     * Option.None otherwise.\n     */\n    find(predicate:(v:T)=>boolean): Option<T> {\n        return Option.none<T>();\n    }\n\n    /**\n     * Returns true if the item is in the collection,\n     * false otherwise.\n     */\n    contains(v:T&WithEquality): boolean {\n        return false;\n    }\n\n    /**\n     * Return a new stream keeping only the first n elements\n     * from this stream.\n     */\n    take(n: number): LinkedList<T> {\n        return this;\n    }\n\n    /**\n     * Returns a new collection, discarding the elements\n     * after the first element which fails the predicate.\n     */\n    takeWhile(predicate: (x:T)=>boolean): LinkedList<T> {\n        return this;\n    }\n\n    /**\n     * Returns a new collection, discarding the elements\n     * after the first element which fails the predicate,\n     * but starting from the end of the collection.\n     *\n     *     LinkedList.of(1,2,3,4).takeRightWhile(x => x > 2)\n     *     => LinkedList.of(3,4)\n     */\n    takeRightWhile(predicate:(x:T)=>boolean): LinkedList<T> {\n        return this;\n    }\n\n    /**\n     * Returns a new collection with the first\n     * n elements discarded.\n     * If the collection has less than n elements,\n     * returns the empty collection.\n     */\n    drop(n:number): LinkedList<T> {\n        return this;\n    }\n\n    /**\n     * Returns a new collection, discarding the first elements\n     * until one element fails the predicate. All elements\n     * after that point are retained.\n     */\n    dropWhile(predicate:(x:T)=>boolean): LinkedList<T> {\n        return this;\n    }\n\n    /**\n     * Returns a new collection with the last\n     * n elements discarded.\n     * If the collection has less than n elements,\n     * returns the empty collection.\n     */\n    dropRight(n:number): LinkedList<T> {\n        return this;\n    }\n\n    /**\n     * Returns a new collection, discarding the last elements\n     * until one element fails the predicate. All elements\n     * before that point are retained.\n     */\n    dropRightWhile(predicate:(x:T)=>boolean): LinkedList<T> {\n        return this;\n    }\n\n    /**\n     * Reduces the collection to a single value using the\n     * associative binary function you give. Since the function\n     * is associative, order of application doesn't matter.\n     *\n     * Example:\n     *\n     *     LinkedList.of(1,2,3).fold(0, (a,b) => a + b);\n     *     => 6\n     */\n    fold(zero:T, fn:(v1:T,v2:T)=>T): T {\n        return zero;\n    }\n\n    /**\n     * Reduces the collection to a single value.\n     * Left-associative.\n     *\n     * Example:\n     *\n     *     Vector.of(\"a\", \"b\", \"c\").foldLeft(\"!\", (xs,x) => x+xs);\n     *     => \"cba!\"\n     *\n     * @param zero The initial value\n     * @param fn A function taking the previous value and\n     *           the current collection item, and returning\n     *           an updated value.\n     */\n    foldLeft<U>(zero: U, fn:(soFar:U,cur:T)=>U): U {\n        return zero;\n    }\n\n    /**\n     * Reduces the collection to a single value.\n     * Right-associative.\n     *\n     * Example:\n     *\n     *     Vector.of(\"a\", \"b\", \"c\").foldRight(\"!\", (x,xs) => xs+x);\n     *     => \"!cba\"\n     *\n     * @param zero The initial value\n     * @param fn A function taking the current collection item and\n     *           the previous value , and returning\n     *           an updated value.\n     */\n    foldRight<U>(zero: U, fn:(cur:T, soFar:U)=>U): U {\n        return zero;\n    }\n\n    /**\n     * Combine this collection with the collection you give in\n     * parameter to produce a new collection which combines both,\n     * in pairs. For instance:\n     *\n     *     Vector.of(1,2,3).zip([\"a\",\"b\",\"c\"])\n     *     => Vector.of([1,\"a\"], [2,\"b\"], [3,\"c\"])\n     *\n     * The result collection will have the length of the shorter\n     * of both collections. Extra elements will be discarded.\n     *\n     * Also see [[LinkedListStatic.zip]] (static version which can more than two\n     * iterables)\n     */\n    zip<U>(other: Iterable<U>): LinkedList<[T,U]> {\n        return <EmptyLinkedList<[T,U]>>emptyLinkedList;\n    }\n\n    /**\n     * Combine this collection with the index of the elements\n     * in it. Handy if you need the index when you map on\n     * the collection for instance:\n     *\n     *     LinkedList.of(\"a\",\"b\").zipWithIndex().map(([v,idx]) => v+idx);\n     *     => LinkedList.of(\"a0\", \"b1\")\n     */\n    zipWithIndex(): LinkedList<[T,number]> {\n        return <EmptyLinkedList<[T,number]>><any>this;\n    }\n\n    /**\n     * Reverse the collection. For instance:\n     *\n     *     LinkedList.of(1,2,3).reverse();\n     *     => LinkedList.of(3,2,1)\n     */\n    reverse(): LinkedList<T> {\n        return this;\n    }\n\n    /**\n     * Takes a predicate; returns a pair of collections.\n     * The first one is the longest prefix of this collection\n     * which satisfies the predicate, and the second collection\n     * is the remainder of the collection.\n     *\n     *    LinkedList.of(1,2,3,4,5,6).span(x => x <3)\n     *    => [LinkedList.of(1,2), LinkedList.of(3,4,5,6)]\n     */\n    span(predicate:(x:T)=>boolean): [LinkedList<T>,LinkedList<T>] {\n        return [this, this];\n    }\n\n    /**\n     * Split the collection at a specific index.\n     *\n     *     LinkedList.of(1,2,3,4,5).splitAt(3)\n     *     => [LinkedList.of(1,2,3), LinkedList.of(4,5)]\n     */\n    splitAt(index:number): [LinkedList<T>,LinkedList<T>] {\n        return [this, this];\n    }\n\n    /**\n     * Returns a pair of two collections; the first one\n     * will only contain the items from this collection for\n     * which the predicate you give returns true, the second\n     * will only contain the items from this collection where\n     * the predicate returns false.\n     *\n     *     LinkedList.of(1,2,3,4).partition(x => x%2===0)\n     *     => [LinkedList.of(2,4),LinkedList.of(1,3)]\n     */\n    partition<U extends T>(predicate:(v:T)=>v is U): [LinkedList<U>,LinkedList<Exclude<T,U>>];\n    partition(predicate:(x:T)=>boolean): [LinkedList<T>,LinkedList<T>];\n    partition<U extends T>(predicate:(v:T)=>boolean): [LinkedList<U>,LinkedList<any>] {\n        return [LinkedList.empty<U>(), LinkedList.empty<T>()];\n    }\n\n    /**\n     * Group elements in the collection using a classifier function.\n     * Elements are then organized in a map. The key is the value of\n     * the classifier, and in value we get the list of elements\n     * matching that value.\n     *\n     * also see [[ConsLinkedList.arrangeBy]]\n     */\n    groupBy<C>(classifier: (v:T)=>C & WithEquality): HashMap<C,LinkedList<T>> {\n        return HashMap.empty<C,LinkedList<T>>();\n    }\n\n    /**\n     * Matches each element with a unique key that you extract from it.\n     * If the same key is present twice, the function will return None.\n     *\n     * also see [[ConsLinkedList.groupBy]]\n     */\n    arrangeBy<K>(getKey: (v:T)=>K&WithEquality): Option<HashMap<K,T>> {\n        return SeqHelpers.arrangeBy<T,K>(this, getKey);\n    }\n\n    /**\n     * Randomly reorder the elements of the collection.\n     */\n    shuffle(): LinkedList<T> {\n        return this;\n    }\n\n    /**\n     * Append an element at the end of this LinkedList.\n     * Warning: appending in a loop on a linked list is going\n     * to be very slow!\n     */\n    append(v:T): LinkedList<T> {\n        return LinkedList.of(v);\n    }\n\n    /*\n     * Append multiple elements at the end of this LinkedList.\n     */\n    appendAll(elts:Iterable<T>): LinkedList<T> {\n        return LinkedList.ofIterable(elts);\n    }\n\n    /**\n     * Remove multiple elements from a LinkedList\n     *\n     *     LinkedList.of(1,2,3,4,3,2,1).removeAll([2,4])\n     *     => LinkedList.of(1,3,3,1)\n     */\n    removeAll(elts:Iterable<T&WithEquality>): LinkedList<T> {\n        return this;\n    }\n\n    /**\n     * Removes the first element matching the predicate\n     * (use [[Seq.filter]] to remove all elements matching a predicate)\n     */\n    removeFirst(predicate: (x:T)=>boolean): LinkedList<T> {\n        return this;\n    }\n\n    /**\n     * Prepend an element at the beginning of the collection.\n     */\n    prepend(elt: T): LinkedList<T> {\n        return new ConsLinkedList(elt, this);\n    }\n\n    /**\n     * Prepend multiple elements at the beginning of the collection.\n     */\n    prependAll(elt: Iterable<T>): LinkedList<T> {\n        return LinkedList.ofIterable(elt);\n    }\n\n    /**\n     * Return a new collection where each element was transformed\n     * by the mapper function you give.\n     */\n    map<U>(mapper:(v:T)=>U): LinkedList<U> {\n        return <EmptyLinkedList<U>>emptyLinkedList;\n    }\n\n    /**\n     * Apply the mapper function on every element of this collection.\n     * The mapper function returns an Option; if the Option is a Some,\n     * the value it contains is added to the result Collection, if it's\n     * a None, the value is discarded.\n     *\n     *     LinkedList.of(1,2,6).mapOption(x => x%2===0 ?\n     *         Option.of(x+1) : Option.none<number>())\n     *     => LinkedList.of(3, 7)\n     */\n    mapOption<U>(mapper:(v:T)=>Option<U>): LinkedList<U> {\n        return <EmptyLinkedList<U>>emptyLinkedList;\n    }\n\n    /**\n     * Calls the function you give for each item in the collection,\n     * your function returns a collection, all the collections are\n     * concatenated.\n     * This is the monadic bind.\n     */\n    flatMap<U>(mapper:(v:T)=>LinkedList<U>): LinkedList<U> {\n        return <EmptyLinkedList<U>>emptyLinkedList;\n    }\n\n    /**\n     * Returns true if the predicate returns true for all the\n     * elements in the collection.\n     */\n    allMatch<U extends T>(predicate:(v:T)=>v is U): this is LinkedList<U>;\n    allMatch(predicate:(v:T)=>boolean): boolean;\n    allMatch(predicate:(v:T)=>boolean): boolean {\n        return true;\n    }\n\n    /**\n     * Returns true if there the predicate returns true for any\n     * element in the collection.\n     */\n    anyMatch(predicate:(v:T)=>boolean): boolean {\n        return false;\n    }\n\n    /**\n     * Call a predicate for each element in the collection,\n     * build a new collection holding only the elements\n     * for which the predicate returned true.\n     */\n    filter<U extends T>(predicate:(v:T)=>v is U): LinkedList<U>;\n    filter(predicate:(v:T)=>boolean): LinkedList<T>;\n    filter(predicate:(v:T)=>boolean): LinkedList<T> {\n        return this;\n    }\n\n    /**\n     * Returns a new collection with elements\n     * sorted according to the comparator you give.\n     *\n     *     const activityOrder = [\"Writer\", \"Actor\", \"Director\"];\n     *     LinkedList.of({name:\"George\", activity: \"Director\"}, {name:\"Robert\", activity: \"Actor\"})\n     *         .sortBy((p1,p2) => activityOrder.indexOf(p1.activity) - activityOrder.indexOf(p2.activity));\n     *     => LinkedList.of({\"name\":\"Robert\",\"activity\":\"Actor\"}, {\"name\":\"George\",\"activity\":\"Director\"})\n     *\n     * also see [[ConsLinkedList.sortOn]]\n     */\n    sortBy(compare: (v1:T,v2:T)=>Ordering): LinkedList<T> {\n        return this;\n    }\n\n    /**\n     * Give a function associating a number or a string with\n     * elements from the collection, and the elements\n     * are sorted according to that value.\n     *\n     *     LinkedList.of({a:3,b:\"b\"},{a:1,b:\"test\"},{a:2,b:\"a\"}).sortOn(elt=>elt.a)\n     *     => LinkedList.of({a:1,b:\"test\"},{a:2,b:\"a\"},{a:3,b:\"b\"})\n     *\n     * You can also sort by multiple criteria, and request 'descending'\n     * sorting:\n     *\n     *     LinkedList.of({a:1,b:\"b\"},{a:1,b:\"test\"},{a:2,b:\"a\"}).sortOn(elt=>elt.a,{desc:elt=>elt.b})\n     *     => LinkedList.of({a:1,b:\"test\"},{a:1,b:\"b\"},{a:2,b:\"a\"})\n     *\n     * also see [[ConsLinkedList.sortBy]]\n     */\n    sortOn(...getKeys: Array<ToOrderable<T>|{desc:ToOrderable<T>}>): LinkedList<T> {\n        return this;\n    }\n\n    /**\n     * Remove duplicate items; elements are mapped to keys, those\n     * get compared.\n     *\n     *     LinkedList.of(1,1,2,3,2,3,1).distinctBy(x => x)\n     *     => LinkedList.of(1,2,3)\n     */\n    distinctBy<U>(keyExtractor: (x:T)=>U&WithEquality): LinkedList<T> {\n        return this;\n    }\n\n    /**\n     * Call a function for element in the collection.\n     */\n    forEach(fn: (v:T)=>void): LinkedList<T> {\n        return this;\n    }\n\n    /**\n     * Reduces the collection to a single value by repeatedly\n     * calling the combine function.\n     * No starting value. The order in which the elements are\n     * passed to the combining function is undetermined.\n     */\n    reduce(combine: (v1:T,v2:T)=>T): Option<T> {\n        return SeqHelpers.reduce(this, combine);\n    }\n\n    /**\n     * Compare values in the collection and return the smallest element.\n     * Returns Option.none if the collection is empty.\n     *\n     * also see [[ConsLinkedList.minOn]]\n     */\n    minBy(compare: (v1:T,v2:T)=>Ordering): Option<T> {\n        return SeqHelpers.minBy(this, compare);\n    }\n\n    /**\n     * Call the function you give for each value in the collection\n     * and return the element for which the result was the smallest.\n     * Returns Option.none if the collection is empty.\n     *\n     *     LinkedList.of({name:\"Joe\", age:12}, {name:\"Paula\", age:6}).minOn(x=>x.age)\n     *     => Option.of({name:\"Paula\", age:6})\n     *\n     * also see [[ConsLinkedList.minBy]]\n     */\n    minOn(getOrderable: ToOrderable<T>): Option<T> {\n        return SeqHelpers.minOn(this, getOrderable);\n    }\n\n    /**\n     * Compare values in the collection and return the largest element.\n     * Returns Option.none if the collection is empty.\n     *\n     * also see [[ConsLinkedList.maxOn]]\n     */\n    maxBy(compare: (v1:T,v2:T)=>Ordering): Option<T> {\n        return SeqHelpers.maxBy(this, compare);\n    }\n\n    /**\n     * Call the function you give for each value in the collection\n     * and return the element for which the result was the largest.\n     * Returns Option.none if the collection is empty.\n     *\n     *     LinkedList.of({name:\"Joe\", age:12}, {name:\"Paula\", age:6}).maxOn(x=>x.age)\n     *     => Option.of({name:\"Joe\", age:12})\n     *\n     * also see [[ConsLinkedList.maxBy]]\n     */\n    maxOn(getOrderable: ToOrderable<T>): Option<T> {\n        return SeqHelpers.maxOn(this, getOrderable);\n    }\n\n    /**\n     * Call the function you give for each element in the collection\n     * and sum all the numbers, return that sum.\n     * Will return 0 if the collection is empty.\n     *\n     *     LinkedList.of(1,2,3).sumOn(x=>x)\n     *     => 6\n     */\n    sumOn(getNumber: (v:T)=>number): number {\n        return SeqHelpers.sumOn(this, getNumber);\n    }\n\n    /**\n     * Slides a window of a specific size over the sequence.\n     * Returns a lazy stream so memory use is not prohibitive.\n     *\n     *     LinkedList.of(1,2,3,4,5,6,7,8).sliding(3)\n     *     => Stream.of(LinkedList.of(1,2,3), LinkedList.of(4,5,6), LinkedList.of(7,8))\n     */\n    sliding(count:number): Stream<ConsLinkedList<T>> {\n        return <Stream<ConsLinkedList<T>>>SeqHelpers.sliding(this, count);\n    }\n\n    /**\n     * Apply the function you give to all elements of the sequence\n     * in turn, keeping the intermediate results and returning them\n     * along with the final result in a list.\n     * The last element of the result is the final cumulative result.\n     *\n     *     LinkedList.of(1,2,3).scanLeft(0, (soFar,cur)=>soFar+cur)\n     *     => LinkedList.of(0,1,3,6)\n     */\n    scanLeft<U>(init:U, fn:(soFar:U,cur:T)=>U): LinkedList<U> {\n        return LinkedList.of<U>(init);\n    }\n\n    /**\n     * Apply the function you give to all elements of the sequence\n     * in turn, keeping the intermediate results and returning them\n     * along with the final result in a list.\n     * The first element of the result is the final cumulative result.\n     *\n     *     LinkedList.of(1,2,3).scanRight(0, (cur,soFar)=>soFar+cur)\n     *     => LinkedList.of(6,5,3,0)\n     */\n    scanRight<U>(init:U, fn:(cur:T,soFar:U)=>U): LinkedList<U> {\n        return LinkedList.of<U>(init);\n    }\n\n    /**\n     * Joins elements of the collection by a separator.\n     * Example:\n     *\n     *     LinkedList.of(1,2,3).mkString(\", \")\n     *     => \"1, 2, 3\"\n     */\n    mkString(separator: string): string {\n        return \"\";\n    }\n\n    /**\n     * Convert to array.\n     * Don't do it on an infinite stream!\n     */\n    toArray(): T[] {\n        return [];\n    }\n\n    /**\n     * Convert to vector.\n     * Don't do it on an infinite stream!\n     */\n    toVector(): Vector<T> {\n        return Vector.empty<T>();\n    }\n\n    /**\n     * Convert this collection to a map. You give a function which\n     * for each element in the collection returns a pair. The\n     * key of the pair will be used as a key in the map, the value,\n     * as a value in the map. If several values get the same key,\n     * entries will be lost.\n     *\n     *     LinkedList.of(1,2,3).toMap(x=>[x.toString(), x])\n     *     => HashMap.of([\"1\",1], [\"2\",2], [\"3\",3])\n     */\n    toMap<K,V>(converter:(x:T)=>[K & WithEquality,V]): HashMap<K,V> {\n        return HashMap.empty<K,V>();\n    }\n\n    /**\n     * Convert this collection to a set. Since the elements of the\n     * Seq may not support equality, you must pass a function returning\n     * a value supporting equality.\n     *\n     *     LinkedList.of(1,2,3,3,4).toSet(x=>x)\n     *     => HashSet.of(1,2,3,4)\n     */\n    toSet<K>(converter:(x:T)=>K&WithEquality): HashSet<K> {\n        return HashSet.empty<K>();\n    }\n\n    /**\n     * Transform this value to another value type.\n     * Enables fluent-style programming by chaining calls.\n     */\n    transform<U>(converter:(x:LinkedList<T>)=>U): U {\n        return converter(this);\n    }\n\n    /**\n     * Two objects are equal if they represent the same value,\n     * regardless of whether they are the same object physically\n     * in memory.\n     */\n    equals(other: LinkedList<T&WithEquality>): boolean {\n        if (!other) {\n            return false;\n        }\n        return other.isEmpty();\n    }\n\n    /**\n     * Get a number for that object. Two different values\n     * may get the same number, but one value must always get\n     * the same number. The formula can impact performance.\n     */\n    hashCode(): number {\n        return 1;\n    }\n\n    [inspect](): string {\n        return this.toString();\n    }\n\n    /**\n     * Get a human-friendly string representation of that value.\n     *\n     * Also see [[ConsLinkedList.mkString]]\n     */\n    toString(): string {\n        return \"LinkedList()\";\n    }\n}\n\n/**\n * ConsLinkedList holds a value and a pointer to a next element,\n * which could be [[ConsLinkedList]] or [[EmptyLinkedList]].\n * A ConsLinkedList is basically a non-empty linked list. It will\n * contain at least one element.\n * \"static methods\" available through [[LinkedListStatic]]\n * @param T the item type\n */\nexport class ConsLinkedList<T> implements Seq<T> {\n\n    /**\n     * @hidden\n     */\n    readonly className: \"ConsLinkedList\" = <any>undefined;  // https://stackoverflow.com/a/47841595/516188\n\n    /**\n     * @hidden\n     */\n    public constructor(protected value: T, protected _tail: LinkedList<T>) {}\n\n    /**\n     * @hidden\n     */\n    hasTrueEquality(): boolean {\n        return SeqHelpers.seqHasTrueEquality<T>(this);\n    }\n\n    /**\n     * View this Some a as LinkedList. Useful to help typescript type\n     * inference sometimes.\n     */\n    asLinkedList(): LinkedList<T> {\n        return this;\n    }\n\n    /**\n     * Implementation of the Iterator interface.\n     */\n    [Symbol.iterator](): Iterator<T> {\n        let item: LinkedList<T> = this;\n        return {\n            next(): IteratorResult<T> {\n                if (item.isEmpty()) {\n                    return { done: true, value: <any>undefined };\n                }\n                const value = item.head().get();\n                item = item.tail().get();\n                return {done: false, value};\n            }\n        };\n    }\n\n    /**\n     * Get the length of the collection.\n     */\n    length(): number {\n        return this.foldLeft(0, (n, ignored) => n + 1);\n    }\n\n    /**\n     * If the collection contains a single element,\n     * return Some of its value, otherwise return None.\n     */\n    single(): Option<T> {\n        return this._tail.isEmpty() ?\n            Option.of(this.value) :\n            Option.none<T>();\n    }\n\n    /**\n     * true if the collection is empty, false otherwise.\n     */\n    isEmpty(): this is EmptyLinkedList<T> {\n        return false;\n    }\n\n    /**\n     * Get the first value of the collection, if any.\n     * In this case the list is not empty, so returns Option.some\n     */\n    head(): Some<T> {\n        return Option.some(this.value);\n    }\n\n    /**\n     * Get all the elements in the collection but the first one.\n     * If the collection is empty, return None.\n     */\n    tail(): Some<LinkedList<T>> {\n        return Option.some(this._tail);\n    }\n\n    /**\n     * Get the last value of the collection, if any.\n     * returns Option.Some if the collection is not empty,\n     * Option.None if it's empty.\n     */\n    last(): Some<T> {\n        let curItem: LinkedList<T> = this;\n        while (true) {\n            const item = (<ConsLinkedList<T>>curItem).value;\n            curItem = (<ConsLinkedList<T>>curItem)._tail;\n            if (curItem.isEmpty()) {\n                return Option.some(item);\n            }\n        }\n    }\n\n    /**\n     * Retrieve the element at index idx.\n     * Returns an option because the collection may\n     * contain less elements than the index.\n     *\n     * Careful this is going to have poor performance\n     * on LinkedList, which is not a good data structure\n     * for random access!\n     */\n    get(idx: number): Option<T> {\n        let curItem: LinkedList<T> = this;\n        let i=0;\n        while (!curItem.isEmpty()) {\n            if (i === idx) {\n                const item = curItem.value;\n                return Option.of(item);\n            }\n            curItem = curItem._tail;\n            ++i;\n        }\n        return Option.none<T>();\n    }\n\n    /**\n     * Search for an item matching the predicate you pass,\n     * return Option.Some of that element if found,\n     * Option.None otherwise.\n     */\n    find(predicate:(v:T)=>boolean): Option<T> {\n        let curItem: LinkedList<T> = this;\n        while (!curItem.isEmpty()) {\n            const item = curItem.value;\n            if (predicate(item)) {\n                return Option.of(item);\n            }\n            curItem = curItem._tail;\n        }\n        return Option.none<T>();\n    }\n\n    /**\n     * Returns true if the item is in the collection,\n     * false otherwise.\n     */\n    contains(v:T&WithEquality): boolean {\n        return this.find(x => areEqual(x,v)).isSome();\n    }\n\n    /**\n     * Return a new stream keeping only the first n elements\n     * from this stream.\n     */\n    take(n: number): LinkedList<T> {\n        let result = <LinkedList<T>><EmptyLinkedList<T>>emptyLinkedList;\n        let curItem: LinkedList<T> = this;\n        let i = 0;\n        while (i++ < n && (!curItem.isEmpty())) {\n            result = new ConsLinkedList(curItem.value, result);\n            curItem = curItem._tail;\n        }\n        return result.reverse();\n    }\n\n    /**\n     * Returns a new collection, discarding the elements\n     * after the first element which fails the predicate.\n     */\n    takeWhile(predicate: (x:T)=>boolean): LinkedList<T> {\n        let result = <LinkedList<T>><EmptyLinkedList<T>>emptyLinkedList;\n        let curItem: LinkedList<T> = this;\n        while ((!curItem.isEmpty()) && predicate(curItem.value)) {\n            result = new ConsLinkedList(curItem.value, result);\n            curItem =curItem._tail;\n        }\n        return result.reverse();\n    }\n\n    /**\n     * Returns a new collection, discarding the elements\n     * after the first element which fails the predicate,\n     * but starting from the end of the collection.\n     *\n     *     LinkedList.of(1,2,3,4).takeRightWhile(x => x > 2)\n     *     => LinkedList.of(3,4)\n     */\n    takeRightWhile(predicate:(x:T)=>boolean): LinkedList<T> {\n        return this.reverse().takeWhile(predicate).reverse();\n    }\n\n    /**\n     * Returns a new collection with the first\n     * n elements discarded.\n     * If the collection has less than n elements,\n     * returns the empty collection.\n     */\n    drop(n:number): LinkedList<T> {\n        let i = n;\n        let curItem: LinkedList<T> = this;\n        while (i-- > 0 && !curItem.isEmpty()) {\n            curItem = curItem._tail;\n        }\n        return curItem;\n    }\n\n    /**\n     * Returns a new collection, discarding the first elements\n     * until one element fails the predicate. All elements\n     * after that point are retained.\n     */\n    dropWhile(predicate:(x:T)=>boolean): LinkedList<T> {\n        let curItem: LinkedList<T> = this;\n        while (!curItem.isEmpty() && predicate(curItem.value)) {\n            curItem = curItem._tail;\n        }\n        return curItem;\n    }\n\n    /**\n     * Returns a new collection with the last\n     * n elements discarded.\n     * If the collection has less than n elements,\n     * returns the empty collection.\n     */\n    dropRight(n:number): LinkedList<T> {\n        // going twice through the list...\n        const length = this.length();\n        return this.take(length-n);\n    }\n\n    /**\n     * Returns a new collection, discarding the last elements\n     * until one element fails the predicate. All elements\n     * before that point are retained.\n     */\n    dropRightWhile(predicate:(x:T)=>boolean): LinkedList<T> {\n        return this.reverse().dropWhile(predicate).reverse();\n    }\n\n    /**\n     * Reduces the collection to a single value using the\n     * associative binary function you give. Since the function\n     * is associative, order of application doesn't matter.\n     *\n     * Example:\n     *\n     *     LinkedList.of(1,2,3).fold(0, (a,b) => a + b);\n     *     => 6\n     */\n    fold(zero:T, fn:(v1:T,v2:T)=>T): T {\n        return this.foldLeft(zero, fn);\n    }\n\n    /**\n     * Reduces the collection to a single value.\n     * Left-associative.\n     *\n     * Example:\n     *\n     *     Vector.of(\"a\", \"b\", \"c\").foldLeft(\"!\", (xs,x) => x+xs);\n     *     => \"cba!\"\n     *\n     * @param zero The initial value\n     * @param fn A function taking the previous value and\n     *           the current collection item, and returning\n     *           an updated value.\n     */\n    foldLeft<U>(zero: U, fn:(soFar:U,cur:T)=>U): U {\n        let r = zero;\n        let curItem: LinkedList<T> = this;\n        while (!curItem.isEmpty()) {\n            r = fn(r, curItem.value);\n            curItem = curItem._tail;\n        }\n        return r;\n    }\n\n    /**\n     * Reduces the collection to a single value.\n     * Right-associative.\n     *\n     * Example:\n     *\n     *     Vector.of(\"a\", \"b\", \"c\").foldRight(\"!\", (x,xs) => xs+x);\n     *     => \"!cba\"\n     *\n     * @param zero The initial value\n     * @param fn A function taking the current collection item and\n     *           the previous value , and returning\n     *           an updated value.\n     */\n    foldRight<U>(zero: U, fn:(cur:T, soFar:U)=>U): U {\n        return this.reverse().foldLeft(zero, (xs,x)=>fn(x,xs));\n    }\n\n    /**\n     * Combine this collection with the collection you give in\n     * parameter to produce a new collection which combines both,\n     * in pairs. For instance:\n     *\n     *     Vector.of(1,2,3).zip([\"a\",\"b\",\"c\"])\n     *     => Vector.of([1,\"a\"], [2,\"b\"], [3,\"c\"])\n     *\n     * The result collection will have the length of the shorter\n     * of both collections. Extra elements will be discarded.\n     *\n     * Also see [[LinkedListStatic.zip]] (static version which can more than two\n     * iterables)\n     */\n    zip<U>(other: Iterable<U>): LinkedList<[T,U]> {\n        const otherIterator = other[Symbol.iterator]();\n        let otherCurItem = otherIterator.next();\n\n        let curItem: LinkedList<T> = this;\n        let result: LinkedList<[T,U]> = <EmptyLinkedList<[T,U]>>emptyLinkedList;\n\n        while ((!curItem.isEmpty()) && (!otherCurItem.done)) {\n            result = new ConsLinkedList(\n                [curItem.value, otherCurItem.value] as [T,U], result);\n            curItem = curItem._tail;\n            otherCurItem = otherIterator.next();\n        }\n        return result.reverse();\n    }\n\n    /**\n     * Combine this collection with the index of the elements\n     * in it. Handy if you need the index when you map on\n     * the collection for instance:\n     *\n     *     LinkedList.of(\"a\",\"b\").zipWithIndex().map(([v,idx]) => v+idx);\n     *     => LinkedList.of(\"a0\", \"b1\")\n     */\n    zipWithIndex(): LinkedList<[T,number]> {\n        return <LinkedList<[T,number]>>SeqHelpers.zipWithIndex<T>(this);\n    }\n\n    /**\n     * Reverse the collection. For instance:\n     *\n     *     LinkedList.of(1,2,3).reverse();\n     *     => LinkedList.of(3,2,1)\n     */\n    reverse(): LinkedList<T> {\n        return this.foldLeft(<LinkedList<T>><EmptyLinkedList<T>>emptyLinkedList, (xs,x) => xs.prepend(x));\n    }\n\n    /**\n     * Takes a predicate; returns a pair of collections.\n     * The first one is the longest prefix of this collection\n     * which satisfies the predicate, and the second collection\n     * is the remainder of the collection.\n     *\n     *    LinkedList.of(1,2,3,4,5,6).span(x => x <3)\n     *    => [LinkedList.of(1,2), LinkedList.of(3,4,5,6)]\n     */\n    span(predicate:(x:T)=>boolean): [LinkedList<T>,LinkedList<T>] {\n        let first: LinkedList<T> = <EmptyLinkedList<T>>emptyLinkedList;\n        let curItem: LinkedList<T> = this;\n        while ((!curItem.isEmpty()) && predicate(curItem.value)) {\n            first = new ConsLinkedList(curItem.value, first);\n            curItem = curItem._tail;\n        }\n        return [first.reverse(), curItem];\n    }\n\n    /**\n     * Split the collection at a specific index.\n     *\n     *     LinkedList.of(1,2,3,4,5).splitAt(3)\n     *     => [LinkedList.of(1,2,3), LinkedList.of(4,5)]\n     */\n    splitAt(index:number): [LinkedList<T>,LinkedList<T>] {\n        let first: LinkedList<T> = <EmptyLinkedList<T>>emptyLinkedList;\n        let curItem: LinkedList<T> = this;\n        let i = 0;\n        while (i++ < index && (!curItem.isEmpty())) {\n            first = new ConsLinkedList(curItem.value, first);\n            curItem = curItem._tail;\n        }\n        return [first.reverse(), curItem];\n    }\n\n    /**\n     * Returns a pair of two collections; the first one\n     * will only contain the items from this collection for\n     * which the predicate you give returns true, the second\n     * will only contain the items from this collection where\n     * the predicate returns false.\n     *\n     *     LinkedList.of(1,2,3,4).partition(x => x%2===0)\n     *     => [LinkedList.of(2,4),LinkedList.of(1,3)]\n     */\n    partition<U extends T>(predicate:(v:T)=>v is U): [LinkedList<U>,LinkedList<Exclude<T,U>>];\n    partition(predicate:(x:T)=>boolean): [LinkedList<T>,LinkedList<T>];\n    partition(predicate:(v:T)=>boolean): [LinkedList<T>,LinkedList<T>] {\n        let fst = LinkedList.empty<T>();\n        let snd = LinkedList.empty<T>();\n        let curItem: LinkedList<T> = this;\n        while (!curItem.isEmpty()) {\n            if (predicate(curItem.value)) {\n                fst = new ConsLinkedList(curItem.value, fst);\n            } else {\n                snd = new ConsLinkedList(curItem.value, snd);\n            }\n            curItem = curItem._tail;\n        }\n        return [fst.reverse(), snd.reverse()];\n    }\n\n    /**\n     * Group elements in the collection using a classifier function.\n     * Elements are then organized in a map. The key is the value of\n     * the classifier, and in value we get the list of elements\n     * matching that value.\n     *\n     * also see [[ConsLinkedList.arrangeBy]]\n     */\n    groupBy<C>(classifier: (v:T)=>C & WithEquality): HashMap<C,LinkedList<T>> {\n        return this.foldLeft(\n            HashMap.empty<C,LinkedList<T>>(),\n            (acc: HashMap<C,LinkedList<T>>, v:T) =>\n                acc.putWithMerge(\n                    classifier(v), LinkedList.of(v),\n                    (v1:LinkedList<T>,v2:LinkedList<T>)=>\n                        v1.prepend(v2.single().getOrThrow())))\n            .mapValues(l => l.reverse());\n    }\n\n    /**\n     * Matches each element with a unique key that you extract from it.\n     * If the same key is present twice, the function will return None.\n     *\n     * also see [[ConsLinkedList.groupBy]]\n     */\n    arrangeBy<K>(getKey: (v:T)=>K&WithEquality): Option<HashMap<K,T>> {\n        return SeqHelpers.arrangeBy<T,K>(this, getKey);\n    }\n\n    /**\n     * Randomly reorder the elements of the collection.\n     */\n    shuffle(): LinkedList<T> {\n        return LinkedList.ofIterable<T>(SeqHelpers.shuffle(this.toArray()));\n    }\n\n    /**\n     * Append an element at the end of this LinkedList.\n     * Warning: appending in a loop on a linked list is going\n     * to be very slow!\n     */\n    append(v:T): LinkedList<T> {\n        return new ConsLinkedList(\n            this.value,\n            this._tail.append(v));\n    }\n\n    /*\n     * Append multiple elements at the end of this LinkedList.\n     */\n    appendAll(elts:Iterable<T>): LinkedList<T> {\n        return LinkedList.ofIterable(elts).prependAll(<LinkedList<T>>this);\n    }\n\n    /**\n     * Remove multiple elements from a LinkedList\n     *\n     *     LinkedList.of(1,2,3,4,3,2,1).removeAll([2,4])\n     *     => LinkedList.of(1,3,3,1)\n     */\n    removeAll(elts:Iterable<T&WithEquality>): LinkedList<T> {\n        return <LinkedList<T>><any>SeqHelpers.removeAll(this, elts);\n    }\n\n    /**\n     * Removes the first element matching the predicate\n     * (use [[Seq.filter]] to remove all elements matching a predicate)\n     */\n    removeFirst(predicate: (x:T)=>boolean): LinkedList<T> {\n        let curItem: LinkedList<T> = this;\n        let result: LinkedList<T> = <EmptyLinkedList<T>>emptyLinkedList;\n        let removed = false;\n        while (!curItem.isEmpty()) {\n            if (predicate(curItem.value) && !removed) {\n                removed = true;\n            } else {\n                result = new ConsLinkedList(curItem.value, result);\n            }\n            curItem = curItem._tail;\n        }\n        return result.reverse();\n    }\n\n    /**\n     * Prepend an element at the beginning of the collection.\n     */\n    prepend(elt: T): LinkedList<T> {\n        return new ConsLinkedList(elt, this);\n    }\n\n    /**\n     * Prepend multiple elements at the beginning of the collection.\n     */\n    prependAll(elts: Iterable<T>): LinkedList<T> {\n        let leftToAdd = LinkedList.ofIterable(elts).reverse();\n        let result: LinkedList<T> = this;\n        while (!leftToAdd.isEmpty()) {\n            result = new ConsLinkedList(leftToAdd.value, result);\n            leftToAdd = leftToAdd._tail;\n        }\n        return result;\n    }\n\n    /**\n     * Return a new collection where each element was transformed\n     * by the mapper function you give.\n     */\n    map<U>(mapper:(v:T)=>U): LinkedList<U> {\n        let curItem: LinkedList<T> = this;\n        let result: LinkedList<U> = <EmptyLinkedList<U>>emptyLinkedList;\n        while (!curItem.isEmpty()) {\n            result = new ConsLinkedList(mapper(curItem.value), result);\n            curItem = curItem._tail;\n        }\n        return result.reverse();\n    }\n\n    /**\n     * Apply the mapper function on every element of this collection.\n     * The mapper function returns an Option; if the Option is a Some,\n     * the value it contains is added to the result Collection, if it's\n     * a None, the value is discarded.\n     *\n     *     LinkedList.of(1,2,6).mapOption(x => x%2===0 ?\n     *         Option.of(x+1) : Option.none<number>())\n     *     => LinkedList.of(3, 7)\n     */\n    mapOption<U>(mapper:(v:T)=>Option<U>): LinkedList<U> {\n        let curItem: LinkedList<T> = this;\n        let result: LinkedList<U> = <EmptyLinkedList<U>>emptyLinkedList;\n        while (!curItem.isEmpty()) {\n            const mapped = mapper(curItem.value);\n            if (mapped.isSome()) {\n                result = new ConsLinkedList(mapped.get(), result);\n            }\n            curItem = curItem._tail;\n        }\n        return result.reverse();\n    }\n\n    /**\n     * Calls the function you give for each item in the collection,\n     * your function returns a collection, all the collections are\n     * concatenated.\n     * This is the monadic bind.\n     */\n    flatMap<U>(mapper:(v:T)=>LinkedList<U>): LinkedList<U> {\n        let curItem: LinkedList<T> = this;\n        let result: LinkedList<U> = <EmptyLinkedList<U>>emptyLinkedList;\n        while (!curItem.isEmpty()) {\n            result = result.prependAll(mapper(curItem.value).reverse());\n            curItem = curItem._tail;\n        }\n        return result.reverse();\n    }\n\n    /**\n     * Returns true if the predicate returns true for all the\n     * elements in the collection.\n     */\n    allMatch<U extends T>(predicate:(v:T)=>v is U): this is LinkedList<U>;\n    allMatch(predicate:(v:T)=>boolean): boolean;\n    allMatch(predicate:(v:T)=>boolean): boolean {\n        return this.find(x => !predicate(x)).isNone();\n    }\n\n    /**\n     * Returns true if there the predicate returns true for any\n     * element in the collection.\n     */\n    anyMatch(predicate:(v:T)=>boolean): boolean {\n        return this.find(predicate).isSome();\n    }\n\n    /**\n     * Call a predicate for each element in the collection,\n     * build a new collection holding only the elements\n     * for which the predicate returned true.\n     */\n    filter<U extends T>(predicate:(v:T)=>v is U): LinkedList<U>;\n    filter(predicate:(v:T)=>boolean): LinkedList<T>;\n    filter(predicate:(v:T)=>boolean): LinkedList<T> {\n        let curItem: LinkedList<T> = this;\n        let result: LinkedList<T> = <EmptyLinkedList<T>>emptyLinkedList;\n        while (!curItem.isEmpty()) {\n            if (predicate(curItem.value)) {\n                result = new ConsLinkedList(curItem.value, result);\n            }\n            curItem = curItem._tail;\n        }\n        return result.reverse();\n    }\n\n    /**\n     * Returns a new collection with elements\n     * sorted according to the comparator you give.\n     *\n     *     const activityOrder = [\"Writer\", \"Actor\", \"Director\"];\n     *     LinkedList.of({name:\"George\", activity: \"Director\"}, {name:\"Robert\", activity: \"Actor\"})\n     *         .sortBy((p1,p2) => activityOrder.indexOf(p1.activity) - activityOrder.indexOf(p2.activity));\n     *     => LinkedList.of({\"name\":\"Robert\",\"activity\":\"Actor\"}, {\"name\":\"George\",\"activity\":\"Director\"})\n     *\n     * also see [[ConsLinkedList.sortOn]]\n     */\n    sortBy(compare: (v1:T,v2:T)=>Ordering): LinkedList<T> {\n        return LinkedList.ofIterable<T>(this.toArray().sort(compare));\n    }\n\n    /**\n     * Give a function associating a number or a string with\n     * elements from the collection, and the elements\n     * are sorted according to that value.\n     *\n     *     LinkedList.of({a:3,b:\"b\"},{a:1,b:\"test\"},{a:2,b:\"a\"}).sortOn(elt=>elt.a)\n     *     => LinkedList.of({a:1,b:\"test\"},{a:2,b:\"a\"},{a:3,b:\"b\"})\n     *\n     * You can also sort by multiple criteria, and request 'descending'\n     * sorting:\n     *\n     *     LinkedList.of({a:1,b:\"b\"},{a:1,b:\"test\"},{a:2,b:\"a\"}).sortOn(elt=>elt.a,{desc:elt=>elt.b})\n     *     => LinkedList.of({a:1,b:\"test\"},{a:1,b:\"b\"},{a:2,b:\"a\"})\n     *\n     * also see [[ConsLinkedList.sortBy]]\n     */\n    sortOn(...getKeys: Array<ToOrderable<T>|{desc:ToOrderable<T>}>): LinkedList<T> {\n        return <LinkedList<T>>SeqHelpers.sortOn<T>(this, getKeys);\n    }\n\n    /**\n     * Remove duplicate items; elements are mapped to keys, those\n     * get compared.\n     *\n     *     LinkedList.of(1,1,2,3,2,3,1).distinctBy(x => x)\n     *     => LinkedList.of(1,2,3)\n     */\n    distinctBy<U>(keyExtractor: (x:T)=>U&WithEquality): LinkedList<T> {\n        return <LinkedList<T>>SeqHelpers.distinctBy(this, keyExtractor);\n    }\n\n    /**\n     * Call a function for element in the collection.\n     */\n    forEach(fn: (v:T)=>void): LinkedList<T> {\n        let curItem: LinkedList<T> = this;\n        while (!curItem.isEmpty()) {\n            fn(curItem.value);\n            curItem = curItem._tail;\n        }\n        return this;\n    }\n\n    /**\n     * Reduces the collection to a single value by repeatedly\n     * calling the combine function.\n     * No starting value. The order in which the elements are\n     * passed to the combining function is undetermined.\n     */\n    reduce(combine: (v1:T,v2:T)=>T): Option<T> {\n        return SeqHelpers.reduce(this, combine);\n    }\n\n    /**\n     * Compare values in the collection and return the smallest element.\n     * Returns Option.none if the collection is empty.\n     *\n     * also see [[ConsLinkedList.minOn]]\n     */\n    minBy(compare: (v1:T,v2:T)=>Ordering): Option<T> {\n        return SeqHelpers.minBy(this, compare);\n    }\n\n    /**\n     * Call the function you give for each value in the collection\n     * and return the element for which the result was the smallest.\n     * Returns Option.none if the collection is empty.\n     *\n     *     LinkedList.of({name:\"Joe\", age:12}, {name:\"Paula\", age:6}).minOn(x=>x.age)\n     *     => Option.of({name:\"Paula\", age:6})\n     *\n     * also see [[ConsLinkedList.minBy]]\n     */\n    minOn(getOrderable: ToOrderable<T>): Option<T> {\n        return SeqHelpers.minOn(this, getOrderable);\n    }\n\n    /**\n     * Compare values in the collection and return the largest element.\n     * Returns Option.none if the collection is empty.\n     *\n     *     LinkedList.of({name:\"Joe\", age:12}, {name:\"Paula\", age:6}).maxOn(x=>x.age)\n     *     => Option.of({name:\"Joe\", age:12})\n     *\n     * also see [[ConsLinkedList.maxOn]]\n     */\n    maxBy(compare: (v1:T,v2:T)=>Ordering): Option<T> {\n        return SeqHelpers.maxBy(this, compare);\n    }\n\n    /**\n     * Call the function you give for each value in the collection\n     * and return the element for which the result was the largest.\n     * Returns Option.none if the collection is empty.\n     *\n     * also see [[ConsLinkedList.maxBy]]\n     */\n    maxOn(getOrderable: ToOrderable<T>): Option<T> {\n        return SeqHelpers.maxOn(this, getOrderable);\n    }\n\n    /**\n     * Call the function you give for each element in the collection\n     * and sum all the numbers, return that sum.\n     * Will return 0 if the collection is empty.\n     *\n     *     LinkedList.of(1,2,3).sumOn(x=>x)\n     *     => 6\n     */\n    sumOn(getNumber: (v:T)=>number): number {\n        return SeqHelpers.sumOn(this, getNumber);\n    }\n\n    /**\n     * Slides a window of a specific size over the sequence.\n     * Returns a lazy stream so memory use is not prohibitive.\n     *\n     *     LinkedList.of(1,2,3,4,5,6,7,8).sliding(3)\n     *     => Stream.of(LinkedList.of(1,2,3), LinkedList.of(4,5,6), LinkedList.of(7,8))\n     */\n    sliding(count:number): Stream<ConsLinkedList<T>> {\n        return <Stream<ConsLinkedList<T>>>SeqHelpers.sliding(this, count);\n    }\n\n    /**\n     * Apply the function you give to all elements of the sequence\n     * in turn, keeping the intermediate results and returning them\n     * along with the final result in a list.\n     *\n     *     LinkedList.of(1,2,3).scanLeft(0, (soFar,cur)=>soFar+cur)\n     *     => LinkedList.of(0,1,3,6)\n     */\n    scanLeft<U>(init:U, fn:(soFar:U,cur:T)=>U): LinkedList<U> {\n        let result = LinkedList.of(init);\n        let curItem: LinkedList<T> = this;\n        let soFar = init;\n        while (!curItem.isEmpty()) {\n            soFar = fn(soFar, curItem.value);\n            result = new ConsLinkedList(soFar, result);\n            curItem = curItem._tail;\n        }\n        return result.reverse();\n    }\n\n    /**\n     * Apply the function you give to all elements of the sequence\n     * in turn, keeping the intermediate results and returning them\n     * along with the final result in a list.\n     * The first element of the result is the final cumulative result.\n     *\n     *     LinkedList.of(1,2,3).scanRight(0, (cur,soFar)=>soFar+cur)\n     *     => LinkedList.of(6,5,3,0)\n     */\n    scanRight<U>(init:U, fn:(cur:T,soFar:U)=>U): LinkedList<U> {\n        let result = LinkedList.of(init);\n        let curItem: LinkedList<T> = this.reverse();\n        let soFar = init;\n        while (!curItem.isEmpty()) {\n            soFar = fn(curItem.value, soFar);\n            result = new ConsLinkedList(soFar, result);\n            curItem = curItem._tail;\n        }\n        return result;\n    }\n\n    /**\n     * Joins elements of the collection by a separator.\n     * Example:\n     *\n     *     LinkedList.of(1,2,3).mkString(\", \")\n     *     => \"1, 2, 3\"\n     */\n    mkString(separator: string): string {\n        let r = \"\";\n        let curItem: LinkedList<T> = this;\n        let isNotFirst = false;\n        while (!curItem.isEmpty()) {\n            if (isNotFirst) {\n                r += separator;\n            }\n            r += SeqHelpers.toStringHelper(curItem.value, {quoteStrings:false});\n            curItem = curItem._tail;\n            isNotFirst = true;\n        }\n        return r;\n    }\n\n    /**\n     * Convert to array.\n     * Don't do it on an infinite stream!\n     */\n    toArray(): T[] {\n        let r:T[] = [];\n        let curItem: LinkedList<T> = this;\n        while (!curItem.isEmpty()) {\n            r.push(curItem.value);\n            curItem = curItem._tail;\n        }\n        return r;\n    }\n\n    /**\n     * Convert to vector.\n     * Don't do it on an infinite stream!\n     */\n    toVector(): Vector<T> {\n        return Vector.ofIterable<T>(this.toArray());\n    }\n\n    /**\n     * Convert this collection to a map. You give a function which\n     * for each element in the collection returns a pair. The\n     * key of the pair will be used as a key in the map, the value,\n     * as a value in the map. If several values get the same key,\n     * entries will be lost.\n     *\n     *     LinkedList.of(1,2,3).toMap(x=>[x.toString(), x])\n     *     => HashMap.of([\"1\",1], [\"2\",2], [\"3\",3])\n     */\n    toMap<K,V>(converter:(x:T)=>[K & WithEquality,V]): HashMap<K,V> {\n        return this.foldLeft(HashMap.empty<K,V>(), (acc,cur) => {\n            const converted = converter(cur);\n            return acc.put(converted[0], converted[1]);\n        });\n    }\n\n    /**\n     * Convert this collection to a set. Since the elements of the\n     * Seq may not support equality, you must pass a function returning\n     * a value supporting equality.\n     *\n     *     LinkedList.of(1,2,3,3,4).toSet(x=>x)\n     *     => HashSet.of(1,2,3,4)\n     */\n    toSet<K>(converter:(x:T)=>K&WithEquality): HashSet<K> {\n        return this.foldLeft(HashSet.empty<K>(), (acc,cur) => {\n            return acc.add(converter(cur));\n        });\n    }\n\n    /**\n     * Transform this value to another value type.\n     * Enables fluent-style programming by chaining calls.\n     */\n    transform<U>(converter:(x:LinkedList<T>)=>U): U {\n        return converter(this);\n    }\n\n    /**\n     * Two objects are equal if they represent the same value,\n     * regardless of whether they are the same object physically\n     * in memory.\n     */\n    equals(other: LinkedList<T&WithEquality>): boolean {\n        if (<any>other === this) {\n            return true;\n        }\n        if (!other || !other.tail) {\n            return false;\n        }\n        contractTrueEquality(\"LinkedList.equals\", this, other);\n        let myVal: LinkedList<T> = this;\n        let hisVal = other;\n        while (true) {\n            if (myVal.isEmpty() !== hisVal.isEmpty()) {\n                return false;\n            }\n            if (myVal.isEmpty()) {\n                // they are both empty, end of the stream\n                return true;\n            }\n            const myHead = myVal.value;\n            const hisHead = (<ConsLinkedList<T>>hisVal).value;\n\n            if ((myHead === undefined) !== (hisHead === undefined)) {\n                return false;\n            }\n            if (myHead === undefined || hisHead === undefined) {\n                // they are both undefined, the || is for TS's flow analysis\n                // so he realizes none of them is undefined after this.\n                continue;\n            }\n            if (!areEqual(myHead, hisHead)) {\n                return false;\n            }\n            myVal = myVal._tail;\n            hisVal = (<ConsLinkedList<T&WithEquality>>hisVal)._tail;\n        }\n    }\n\n    /**\n     * Get a number for that object. Two different values\n     * may get the same number, but one value must always get\n     * the same number. The formula can impact performance.\n     */\n    hashCode(): number {\n        let hash = 1;\n        let curItem: LinkedList<T> = this;\n        while (!curItem.isEmpty()) {\n            hash = 31 * hash + getHashCode(curItem.value);\n            curItem = curItem._tail;\n        }\n        return hash;\n    }\n\n    [inspect](): string {\n        return this.toString();\n    }\n\n    /**\n     * Get a human-friendly string representation of that value.\n     *\n     * Also see [[ConsLinkedList.mkString]]\n     */\n    toString(): string {\n        let curItem: LinkedList<T> = this;\n        let result = \"LinkedList(\";\n\n        while (!curItem.isEmpty()) {\n            result += SeqHelpers.toStringHelper(curItem.value);\n            const tail: LinkedList<T> = curItem._tail;\n            curItem = tail;\n            if (!curItem.isEmpty()) {\n                result += \", \";\n            }\n        }\n\n        return result + \")\";\n    }\n}\n\nconst emptyLinkedList = new EmptyLinkedList<any>();\n"
  },
  {
    "path": "src/Option.ts",
    "content": "/**\n * The [[Option]] type expresses that a value may be present or not.\n * The code is organized through the class [[None]] (value not\n * present), the class [[Some]] (value present), and the type alias\n * [[Option]] (Some or None).\n *\n * Finally, \"static\" functions on Option are arranged in the class\n * [[OptionStatic]] and are accessed through the global constant Option.\n *\n * Examples:\n *\n *     Option.of(5);\n *     Option.none<number>();\n *     Option.of(5).map(x => x*2);\n *\n * To get the value out of an option, you can use [[Some.getOrThrow]],\n * or [[Some.get]]. The latter is available if you've checked that you\n * indeed have a some, for example:\n *\n *     const opt = Option.of(5);\n *     if (opt.isSome()) {\n *         opt.get();\n *     }\n *\n * You also have other options like [[Some.getOrElse]], [[Some.getOrUndefined]]\n * and so on. [[Some]] and [[None]] have the same methods, except that\n * Some has the extra [[Some.get]] method that [[None]] doesn't have.\n */\n\nimport { Value, inspect } from \"./Value\";\nimport { Vector } from \"./Vector\";\nimport { Either } from \"./Either\";\nimport { WithEquality, areEqual, hasTrueEquality,\n         getHashCode, } from \"./Comparison\";\nimport { toStringHelper } from \"./SeqHelpers\";\nimport { contractTrueEquality} from \"./Contract\";\n\n/**\n * An Option is either [[Some]] or [[None]]\n * \"static methods\" available through [[OptionStatic]]\n * @param T the item type\n */\nexport type Option<T> = Some<T> | None<T>;\n\n/**\n * Holds the \"static methods\" for [[Option]]\n */\nexport class OptionStatic {\n\n    /**\n     * Builds an optional value.\n     * * T is wrapped in a [[Some]]\n     * * undefined becomes a [[None]]\n     * * null becomes a [[Some]].\n     *\n     *     Option.of(5).isSome()\n     *     => true\n     *\n     *     Option.of(undefined).isSome()\n     *     => false\n     *\n     *     Option.of(null).isSome()\n     *     => true\n     *\n     * Also see [[OptionStatic.some]], [[OptionStatic.ofNullable]]\n     */\n    of<T>(v: T|undefined): Option<T> {\n        return (v === undefined) ? <None<T>>none : new Some(v);\n    }\n\n    /**\n     * Build an optional value from a nullable.\n     * * T is wrapped in a [[Some]]\n     * * undefined becomes a [[None]]\n     * * null becomes a [[None]].\n     *\n     *     Option.ofNullable(5).isSome()\n     *     => true\n     *\n     *     Option.ofNullable(undefined).isSome()\n     *     => false\n     *\n     *     Option.ofNullable(null).isSome()\n     *     => false\n     *\n     * Also see [[OptionStatic.some]], [[OptionStatic.of]]\n     */\n    ofNullable<T>(v:T|undefined|null): Option<T> {\n        return (v !== undefined && v !== null) ? new Some(v) : <None<T>>none;\n    }\n\n    /**\n     * Build a [[Some]], unlike [[OptionStatic.of]], which may build a [[Some]]\n     * or a [[None]].\n     * Will throw if given undefined.\n     *\n     *     Option.some(5).isSome()\n     *     => true\n     *\n     *     Option.some(undefined).isSome()\n     *     => throws\n     *\n     *     Option.some(null).isSome()\n     *     => true\n     *\n     * Also see [[OptionStatic.of]], [[OptionStatic.ofNullable]]\n     */\n    some<T>(v: T): Some<T> {\n        // the reason I decided to add a some in addition to 'of'\n        // instead of making 'of' smarter (which is possible in\n        // typescript, see https://github.com/bcherny/tsoption)\n        // is that sometimes you really want an Option, not a Some.\n        // for instance you can't mix an a Some and an Option in a list\n        // if you put the Some first, without calling asOption().\n        if (typeof v === \"undefined\") {\n            throw \"Option.some got undefined!\";\n        }\n        return new Some(v);\n    }\n\n    /**\n     * The optional value expressing a missing value.\n     */\n    none<T>(): Option<T> {\n        return <None<T>>none;\n    }\n\n    /**\n     * Curried type guard for Option\n     * Sometimes needed also due to https://github.com/Microsoft/TypeScript/issues/20218\n     *\n     *     Vector.of(Option.of(2), Option.none<number>())\n     *         .filter(Option.isSome)\n     *         .map(o => o.get())\n     *     => Vector.of(2)\n     */\n    isSome<T>(o: Option<T>): o is Some<T> {\n        return o.isSome();\n    }\n\n    /**\n     * Curried type guard for Option\n     * Sometimes needed also due to https://github.com/Microsoft/TypeScript/issues/20218\n     *\n     *     Vector.of(Option.of(2), Option.none<number>())\n     *         .filter(Option.isNone)\n     *     => Vector.of(Option.none<number>())\n     */\n    isNone<T>(o: Option<T>): o is None<T> {\n        return o.isNone();\n    }\n\n    /**\n     * Turns a list of options in an option containing a list of items.\n     * Useful in many contexts.\n     *\n     *     Option.sequence(Vector.of(Option.of(1),Option.of(2)))\n     *     => Option.of(Vector.of(1,2))\n     *\n     * But if a single element is None, everything is discarded:\n     *\n     *     Option.sequence(Vector.of(Option.of(1), Option.none()))\n     *     => Option.none()\n     *\n     * Also see [[OptionStatic.traverse]]\n     */\n    sequence<T>(elts:Iterable<Option<T>>): Option<Vector<T>> {\n        return Option.traverse(elts, x=>x);\n    }\n\n    /**\n     * Takes a list, a function that can transform list elements\n     * to options, then return an option containing a list of\n     * the transformed elements.\n     *\n     *     const getUserById: (x:number)=>Option<string> = x => x > 0 ?\n     *         Option.of(\"user\" + x.toString()) : Option.none();\n     *     Option.traverse([4, 3, 2], getUserById);\n     *     => Option.of(Vector.of(\"user4\", \"user3\", \"user2\"))\n     *\n     * But if a single element results in None, everything is discarded:\n     *\n     *     const getUserById: (x:number)=>Option<string> = x => x > 0 ?\n     *         Option.of(\"user\" + x.toString()) : Option.none();\n     *     Option.traverse([4, -3, 2], getUserById);\n     *     => Option.none()\n     *\n     * Also see [[OptionStatic.sequence]]\n     */\n    traverse<T,U>(elts:Iterable<T>, fn: (x:T)=>Option<U>): Option<Vector<U>> {\n        let r = Vector.empty<U>();\n        const iterator = elts[Symbol.iterator]();\n        let curItem = iterator.next();\n        while (!curItem.done) {\n            const v = fn(curItem.value);\n            if (v.isNone()) {\n                return <None<Vector<U>>>none;\n            }\n            r = r.append(v.get());\n            curItem = iterator.next();\n        }\n        return Option.of(r);\n    }\n\n    /**\n     * Applicative lifting for Option.\n     * Takes a function which operates on basic values, and turns it\n     * in a function that operates on options of these values ('lifts'\n     * the function). The 2 is because it works on functions taking two\n     * parameters.\n     *\n     *     const lifted = Option.liftA2((x:number,y:number) => x+y);\n     *     lifted(Option.of(5), Option.of(6));\n     *     => Option.of(11)\n     *\n     *     const lifted2 = Option.liftA2((x:number,y:number) => x+y);\n     *     lifted2(Option.of(5), Option.none<number>());\n     *     => Option.none()\n     *\n     * @param T the first option type\n     * @param U the second option type\n     * @param V the new type as returned by the combining function.\n     */\n    liftA2<T,U,V>(fn:(v1:T,v2:U)=>V): (p1:Option<T>, p2:Option<U>) => Option<V> {\n        return (p1,p2) => p1.flatMap(a1 => p2.map(a2 => fn(a1,a2)));\n    }\n\n    /**\n     * Applicative lifting for Option. 'p' stands for 'properties'.\n     *\n     * Takes a function which operates on a simple JS object, and turns it\n     * in a function that operates on the same JS object type except which each field\n     * wrapped in an Option ('lifts' the function).\n     * It's an alternative to [[OptionStatic.liftA2]] when the number of parameters\n     * is not two.\n     *\n     *     const lifted = Option.liftAp((x:{a:number,b:number,c:number}) => x.a+x.b+x.c);\n     *     lifted({a:Option.of(5), b:Option.of(6), c:Option.of(3)});\n     *     => Option.of(14)\n     *\n     *     const lifted = Option.liftAp((x:{a:number,b:number}) => x.a+x.b);\n     *     lifted({a:Option.of(5), b:Option.none<number>()});\n     *     => Option.none()\n     *\n     * @param A the object property type specifying the parameters for your function\n     * @param B the type returned by your function, returned wrapped in an option by liftAp.\n     */\n    liftAp<A,B>(fn:(x:A)=>B): (x: {[K in keyof A]: Option<A[K]>;}) => Option<B> {\n        return x => {\n            const copy:A = <any>{};\n            for (let p in x) {\n                if (x[p].isNone()) {\n                    return Option.none<B>();\n                }\n                copy[p] = x[p].getOrThrow();\n            }\n            return Option.of(fn(copy));\n        }\n    }\n\n    /**\n     * Take a partial function (may return undefined or throw),\n     * and lift it to return an [[Option]] instead.\n     * undefined becomes a [[None]], everything else a [[Some]]\n     *\n     *     const plus = Option.lift((x:number,y:number)=>x+y);\n     *     plus(1,2);\n     *     => Option.of(3)\n     *\n     *     const undef = Option.lift((x:number)=>undefined);\n     *     undef(1);\n     *     => Option.none()\n     *\n     *     const nl = Option.lift((x:number,y:number,z:number)=>null);\n     *     nl(1,2,3);\n     *     => Option.some(null)\n     *\n     *     const throws = Option.lift((x:number,y:number)=>{throw \"x\"});\n     *     throws(1,2);\n     *     => Option.none()\n     */\n    lift<T extends any[],U>(fn: (...args: T)=>U|undefined): (...args:T)=>Option<U> {\n        return (...args:T) => {\n            try {\n                return Option.of(fn(...args));\n            } catch {\n                return Option.none<U>();\n            }\n        };\n    }\n\n    /**\n     * Take a partial function (may return undefined or throw),\n     * and lift it to return an [[Option]] instead.\n     * null and undefined become a [[None]], everything else a [[Some]]\n     *\n     *     const plus = Option.liftNullable((x:number,y:number)=>x+y);\n     *     plus(1,2);\n     *     => Option.of(3)\n     *\n     *     const undef = Option.liftNullable((x:number,y:number,z:string)=>undefined);\n     *     undef(1,2,\"\");\n     *     => Option.none()\n     *\n     *     const nl = Option.liftNullable((x:number)=>null);\n     *     nl(1);\n     *     => Option.none()\n     *\n     *     const throws = Option.liftNullable((x:number,y:number)=>{throw \"x\"});\n     *     throws(1,2);\n     *     => Option.none()\n     */\n    liftNullable<T extends any[],U>(fn: (...args: T)=>U|null|undefined): (...args:T)=>Option<U> {\n        return (...args:T) => {\n            try {\n                return Option.ofNullable(fn(...args));\n            } catch {\n                return Option.none<U>();\n            }\n        };\n    }\n\n    /**\n     * Take a no-parameter partial function (may return undefined or throw),\n     * and call it, return an [[Option]] instead.\n     * undefined becomes a [[None]], everything else a [[Some]]\n     *\n     *     Option.try_(Math.random);\n     *     => Option.of(0.49884723907769635)\n     *\n     *     Option.try_(()=>undefined);\n     *     => Option.none()\n     *\n     *     Option.try_(()=>null);\n     *     => Option.of(null)\n     *\n     *     Option.try_(()=>{throw \"x\"});\n     *     => Option.none()\n     *\n     * Also see [[OptionStatic.tryNullable]], [[OptionStatic.lift]],\n     * [[OptionStatic.liftNullable]], [[EitherStatic.try_]].\n     */\n    try_<T>(fn:()=>T|undefined): Option<T> {\n        return Option.lift(fn)();\n    }\n\n    /**\n     * Take a no-parameter partial function (may return null, undefined or throw),\n     * and call it, return an [[Option]] instead.\n     * null and undefined become a [[None]], everything else a [[Some]]\n     *\n     *     Option.tryNullable(Math.random);\n     *     => Option.of(0.49884723907769635)\n     *\n     *     Option.tryNullable(()=>undefined);\n     *     => Option.none()\n     *\n     *     Option.tryNullable(()=>null);\n     *     => Option.none()\n     *\n     *     Option.tryNullable(()=>{throw \"x\"});\n     *     => Option.none()\n     *\n     * Also see [[OptionStatic.try_]], [[OptionStatic.liftNullable]],\n     * [[OptionStatic.lift]], [[EitherStatic.try_]].\n     */\n    tryNullable<T>(fn:()=>T|null|undefined): Option<T> {\n        return Option.liftNullable(fn)();\n    }\n}\n\n/**\n * The Option constant allows to call the option \"static\" methods\n */\nexport const Option = new OptionStatic();\n\nfunction optionHasTrueEquality<T>(opt: Option<T>): boolean {\n    return opt.flatMap(\n        x => (x && (<any>x).hasTrueEquality) ?\n            Option.of((<any>x).hasTrueEquality()) :\n            hasTrueEquality(x))\n        .getOrElse(true);\n}\n\n/**\n * Some represents an [[Option]] with a value.\n * \"static methods\" available through [[OptionStatic]]\n *\n * [[Some]] and [[None]] have the same methods, except that\n * Some has the extra [[Some.get]] method that [[None]] doesn't have.\n * @param T the item type\n */\nexport class Some<T> implements Value {\n    /**\n     * @hidden\n     */\n    constructor(private value: T) {}\n\n    /**\n     * @hidden\n     */\n    readonly className: \"Some\" = <any>undefined;  // https://stackoverflow.com/a/47841595/516188\n\n    /**\n     * Returns true since this is a Some (contains a value)\n     */\n    isSome(): this is Some<T> {\n        return true;\n    }\n\n    /**\n     * Returns false since this is a Some (contains a value)\n     */\n    isNone(): this is None<T> {\n        return false;\n    }\n\n    /**\n     * View this Some a as Option. Useful to help typescript type\n     * inference sometimes.\n     */\n    asOption(): Option<T> {\n        return this;\n    }\n\n    /**\n     * Get the value contained in this option.\n     * NOTE: we know it's there, since this method\n     * belongs to Some, not Option.\n     */\n    get(): T {\n        return this.value;\n    }\n\n    /**\n     * Combines two options. If this option is a Some, returns it.\n     * If it's a None, returns the other one.\n     */\n    orElse(other: Option<T>): Option<T> {\n        return this;\n    }\n\n    /**\n     * Get the value from this option if it's a Some, otherwise\n     * throw an exception.\n     * You can optionally pass a message that'll be used as the\n     * exception message.\n     */\n    getOrThrow(errorInfo?: Error|string): T {\n        return this.value;\n    }\n\n    /**\n     * Returns true if the option is a Some and contains the\n     * value you give, false otherwise.\n     */\n    contains(v: T&WithEquality): boolean {\n        return v === this.value;\n    }\n\n    /**\n     * Get the value contained in the option if it's a Some,\n     * return undefined if it's a None.\n     *\n     *     Option.of(5).getOrUndefined()\n     *     => 5\n     *\n     *     Option.none<number>().getOrUndefined()\n     *     => undefined\n     */\n    getOrUndefined(): T | undefined {\n        return this.value;\n    }\n\n    /**\n     * Get the value contained in the option if it's a Some,\n     * return null if it's a None.\n     *\n     *     Option.of(5).getOrNull()\n     *     => 5\n     *\n     *     Option.none<number>().getOrNull()\n     *     => null\n     */\n    getOrNull(): T | null {\n        return this.value;\n    }\n\n    /**\n     * Get the value from this option; if it's a None (no value\n     * present), then return the default value that you give.\n     */\n    getOrElse(alt: T): T {\n        return this.value;\n    }\n\n    /**\n     * Get the value from this option; if it's a None (no value\n     * present), then return the value returned by the function that you give.\n     *\n     *     Option.of(5).getOrCall(() => 6)\n     *     => 5\n     *\n     *     Option.none<number>().getOrCall(() => 6)\n     *     => 6\n     */\n    getOrCall(fn: ()=>T): T {\n        return this.value;\n    }\n\n    /**\n     * Return a new option where the element (if present) was transformed\n     * by the mapper function you give. If the option was None it'll stay None.\n     *\n     *     Option.of(5).map(x => x*2)\n     *     => Option.of(10)\n     *\n     *     Option.of(5).map(x => null)\n     *     => Option.of(null)\n     *\n     * Also see [[Some.mapNullable]], [[Some.flatMap]]\n     */\n    map<U>(fn: (v:T)=>U): Option<U> {\n        return Option.of(fn(this.value));\n    }\n\n    /**\n     * Return a new option where the element (if present) was transformed\n     * by the mapper function you give. If the mapped value is `null` or\n     * `undefined`, then a Some will turn into a None.\n     * If the option was None it'll stay None.\n     *\n     *     Option.of(5).mapNullable(x => x*2)\n     *     => Option.of(10)\n     *\n     *     Option.of(5).mapNullable(x => null)\n     *     => Option.none()\n     *\n     * Also see [[Some.map]], [[Some.flatMap]]\n     */\n    mapNullable<U>(fn: (v:T)=>U|null|undefined): Option<U> {\n        return Option.ofNullable(fn(this.value));\n    }\n\n    /**\n     * If this is a Some, calls the function you give on\n     * the item in the option and return its result.\n     * If the option is a None, return none.\n     * This is the monadic bind.\n     */\n    flatMap<U>(mapper:(v:T)=>Option<U>): Option<U> {\n        return mapper(this.value);\n    }\n\n    /**\n     * If this is None, will return None. If it's a Some,\n     * and the contents match your predicate, return the option.\n     * If the contents don't match the predicate, return None.\n     */\n    filter<U extends T>(fn:(v:T)=>v is U): Option<U>;\n    filter(fn: (v:T)=>boolean): Option<T>;\n    filter(fn: (v:T)=>boolean): Option<T> {\n        return fn(this.value) ? this : Option.none<T>();\n    }\n\n    /**\n     * Execute a side-effecting function if the option\n     * is a Some; returns the option.\n     */\n    ifSome(fn:(v:T)=>void): Option<T> {\n        fn(this.value);\n        return this;\n    }\n\n    /**\n     * Execute a side-effecting function if the option\n     * is a None; returns the option.\n     */\n    ifNone(fn:()=>void): Option<T> {\n        return this;\n    }\n\n    /**\n     * Handle both branches of the option and return a value\n     * (can also be used for side-effects).\n     * This is the catamorphism for option.\n     *\n     *     Option.of(5).match({\n     *         Some: x  => \"got \" + x,\n     *         None: () => \"got nothing!\"\n     *     });\n     *     => \"got 5\"\n     */\n    match<U>(cases: {Some: (v:T)=>U, None: ()=>U}): U {\n        return cases.Some(this.value);\n    }\n\n    /**\n     * Transform this value to another value type.\n     * Enables fluent-style programming by chaining calls.\n     */\n    transform<U>(converter:(x:Option<T>)=>U): U {\n        return converter(this);\n    }\n\n    /**\n     * Convert to a vector. If it's a None, it's the empty\n     * vector, if it's a Some, it's a one-element vector with\n     * the contents of the option.\n     */\n    toVector(): Vector<T> {\n        return Vector.of(this.value);\n    }\n\n    /**\n     * Convert to an either. You must provide a left value\n     * in case this is a None.\n     */\n    toEither<L>(left: L): Either<L,T> {\n        return Either.right<L,T>(this.value);\n    }\n\n    /**\n     * If this is a Some, return this object.\n     * If this is a None, return the result of the function.\n     */\n    orCall(_: () => Option<T>): Option<T> {\n      return this;\n    }\n\n    hasTrueEquality<T>(): boolean {\n        return optionHasTrueEquality(this);\n    }\n\n    /**\n     * Two objects are equal if they represent the same value,\n     * regardless of whether they are the same object physically\n     * in memory.\n     */\n    equals(other: Option<T&WithEquality>): boolean {\n        if (<any>other === this) {\n            return true;\n        }\n        // the .isSome doesn't test if it's a Some, but\n        // if the object has a field called isSome.\n        if (other === <None<T>>none || !other || !(<any>other).isSome) {\n            return false;\n        }\n\n        const someOther = <Some<T&WithEquality>>other;\n        contractTrueEquality(\"Option.equals\", this, someOther);\n        return areEqual(this.value, someOther.value);\n    }\n\n    /**\n     * Get a number for that object. Two different values\n     * may get the same number, but one value must always get\n     * the same number. The formula can impact performance.\n     */\n    hashCode(): number {\n        return getHashCode(this.value);\n    }\n\n    /**\n     * Get a human-friendly string representation of that value.\n     */\n    toString(): string {\n        return \"Some(\" + toStringHelper(this.value) + \")\";\n    }\n\n    /**\n     * Used by the node REPL to display values.\n     */\n    [inspect](): string {\n        return this.toString();\n    }\n}\n\n/**\n * None represents an [[Option]] without value.\n * \"static methods\" available through [[OptionStatic]]\n *\n * [[Some]] and [[None]] have the same methods, except that\n * Some has the extra [[Some.get]] method that [[None]] doesn't have.\n * @param T the item type\n */\nexport class None<T> implements Value {\n\n    /**\n     * @hidden\n     */\n    readonly className: \"None\" = <any>undefined;  // https://stackoverflow.com/a/47841595/516188\n\n    /**\n     * Returns false since this is a None (doesn'tcontains a value)\n     */\n    isSome(): this is Some<T> {\n        return false;\n    }\n\n    /**\n     * Returns true since this is a None (doesn'tcontains a value)\n     */\n    isNone(): this is None<T> {\n        return true;\n    }\n\n    /**\n     * View this Some a as Option. Useful to help typescript type\n     * inference sometimes.\n     */\n    asOption(): Option<T> {\n        return this;\n    }\n\n    /**\n     * Combines two options. If this option is a Some, returns it.\n     * If it's a None, returns the other one.\n     */\n    orElse(other: Option<T>): Option<T> {\n        return other;\n    }\n\n    /**\n     * Get the value from this option if it's a Some, otherwise\n     * throw an exception.\n     * You can optionally pass a message that'll be used as the\n     * exception message, or an Error object.\n     */\n    getOrThrow(errorInfo?: Error|string): T & WithEquality {\n        if (typeof errorInfo === 'string') {\n            throw new Error(errorInfo || \"getOrThrow called on none!\");\n        }\n        throw errorInfo || new Error(\"getOrThrow called on none!\");\n    }\n\n    /**\n     * Returns true if the option is a Some and contains the\n     * value you give, false otherwise.\n     */\n    contains(v: T&WithEquality): boolean {\n        return false;\n    }\n\n    /**\n     * Get the value contained in the option if it's a Some,\n     * return undefined if it's a None.\n     *\n     *     Option.of(5).getOrUndefined()\n     *     => 5\n     *\n     *     Option.none<number>().getOrUndefined()\n     *     => undefined\n     */\n    getOrUndefined(): T|undefined {\n        return undefined;\n    }\n\n    /**\n     * Get the value contained in the option if it's a Some,\n     * return null if it's a None.\n     *\n     *     Option.of(5).getOrNull()\n     *     => 5\n     *\n     *     Option.none<number>().getOrNull()\n     *     => null\n     */\n    getOrNull(): T|null {\n        return null;\n    }\n\n    /**\n     * Get the value from this option; if it's a None (no value\n     * present), then return the default value that you give.\n     */\n    getOrElse(alt: T): T {\n        return alt;\n    }\n\n    /**\n     * Get the value from this option; if it's a None (no value\n     * present), then return the value returned by the function that you give.\n     *\n     *     Option.of(5).getOrCall(() => 6)\n     *     => 5\n     *\n     *     Option.none<number>().getOrCall(() => 6)\n     *     => 6\n     */\n    getOrCall(fn: ()=>T): T {\n        return fn();\n    }\n\n    /**\n     * Return a new option where the element (if present) was transformed\n     * by the mapper function you give. If the option was None it'll stay None.\n     *\n     *     Option.of(5).map(x => x*2)\n     *     => Option.of(10)\n     *\n     *     Option.of(5).map(x => null)\n     *     => Option.of(null)\n     *\n     * Also see [[None.mapNullable]], [[None.flatMap]]\n     */\n    map<U>(fn: (v:T)=>U): Option<U> {\n        return <None<U>>none;\n    }\n\n    /**\n     * Return a new option where the element (if present) was transformed\n     * by the mapper function you give. If the mapped value is `null` or\n     * `undefined`, then a Some will turn into a None.\n     * If the option was None it'll stay None.\n     *\n     *     Option.of(5).mapNullable(x => x*2)\n     *     => Option.of(10)\n     *\n     *     Option.of(5).mapNullable(x => null)\n     *     => Option.none()\n     *\n     * Also see [[None.map]], [[None.flatMap]]\n     */\n    mapNullable<U>(fn: (v:T)=>U|null|undefined): Option<U> {\n        return <None<U>>none;\n    }\n\n    /**\n     * If this is a Some, calls the function you give on\n     * the item in the option and return its result.\n     * If the option is a None, return none.\n     * This is the monadic bind.\n     */\n    flatMap<U>(mapper:(v:T)=>Option<U>): Option<U> {\n        return <None<U>>none;\n    }\n\n    /**\n     * If this is None, will return None. If it's a Some,\n     * and the contents match your predicate, return the option.\n     * If the contents don't match the predicate, return None.\n     */\n    filter<U extends T>(fn:(v:T)=>v is U): Option<U>;\n    filter(fn: (v:T)=>boolean): Option<T>;\n    filter(fn: (v:T)=>boolean): Option<T> {\n        return <None<T>>none;\n    }\n\n    /**\n     * Execute a side-effecting function if the option\n     * is a Some; returns the option.\n     */\n    ifSome(fn:(v:T)=>void): Option<T> {\n        return this;\n    }\n\n    /**\n     * Execute a side-effecting function if the option\n     * is a Some; returns the option.\n     */\n    ifNone(fn:()=>void): Option<T> {\n        fn();\n        return this;\n    }\n\n    /**\n     * Handle both branches of the option and return a value\n     * (can also be used for side-effects).\n     * This is the catamorphism for option.\n     *\n     *     Option.of(5).match({\n     *         Some: x  => \"got \" + x,\n     *         None: () => \"got nothing!\"\n     *     });\n     *     => \"got 5\"\n     */\n    match<U>(cases: {Some: (v:T)=>U, None: ()=>U}): U {\n        return cases.None();\n    }\n\n    /**\n     * Transform this value to another value type.\n     * Enables fluent-style programming by chaining calls.\n     */\n    transform<U>(converter:(x:Option<T>)=>U): U {\n        return converter(this);\n    }\n\n    /**\n     * Convert to a vector. If it's a None, it's the empty\n     * vector, if it's a Some, it's a one-element vector with\n     * the contents of the option.\n     */\n    toVector(): Vector<T> {\n        return Vector.empty<T>();\n    }\n\n    /**\n     * Convert to an either. You must provide a left value\n     * in case this is a None.\n     */\n    toEither<L>(left: L): Either<L,T> {\n        return Either.left<L,T>(left);\n    }\n\n    /**\n     * If this is a Some, return this object.\n     * If this is a None, return the result of the function.\n     */\n    orCall(fn: () => Option<T>): Option<T> {\n      return fn();\n    }\n\n    hasTrueEquality<T>(): boolean {\n        return optionHasTrueEquality(this);\n    }\n\n    /**\n     * Two objects are equal if they represent the same value,\n     * regardless of whether they are the same object physically\n     * in memory.\n     */\n    equals(other: Option<T&WithEquality>): boolean {\n        return other === <None<T>>none;\n    }\n\n    /**\n     * Get a number for that object. Two different values\n     * may get the same number, but one value must always get\n     * the same number. The formula can impact performance.\n     */\n    hashCode(): number {\n        return 1;\n    }\n\n    /**\n     * Get a human-friendly string representation of that value.\n     */\n    toString(): string {\n        return \"None()\";\n    }\n\n    /**\n     * Used by the node REPL to display values.\n     */\n    [inspect](): string {\n        return this.toString();\n    }\n}\n\n/**\n * @hidden\n */\nexport const none = new None<any>();\n"
  },
  {
    "path": "src/Predicate.ts",
    "content": "/**\n * A predicate is a function taking one parameter and returning a boolean.\n * In other words the predicate checks whether some proposition holds for the parameter.\n *\n * The Predicate interface offers normal function-calling, to make sure that the\n * predicate holds (just call predicate(x)), but also some helper methods to\n * deal with logical operations between propositions.\n *\n * You can build predicates using [[PredicateStatic]] through the\n * 'Predicate' global constant.\n *\n * Examples:\n *\n *     const check = Predicate.of((x: number) => x > 10).and(x => x < 20);\n *     check(12); // => true\n *     check(21);\n *     => false\n *\n *     Vector.of(1,2,3,4,5).filter(\n *         Predicate.isIn([2,3]).negate())\n *     => Vector.of(1, 4, 5)\n */\nimport { WithEquality, areEqual } from \"./Comparison\";\nimport { Vector } from \"./Vector\";\n\n/**\n * A predicate is a function taking one parameter and returning a boolean.\n * In other words the predicate checks whether some proposition holds for the parameter.\n *\n * The Predicate interface offers normal function-calling, to make sure that the\n * predicate holds (just call predicate(x)), but also some helper methods to\n * deal with logical operations between propositions.\n *\n * You can build predicates using [[PredicateStatic]] through the\n * 'Predicate' global constant.\n */\nexport interface Predicate<T> {\n\n    /**\n     * Does the predicate hold for the value you give?\n     * Returns true or false\n     */\n    (x:T): boolean;\n\n    /**\n     * Combines two predicates with the 'and' logical operation.\n     * For instance:\n     *\n     *     Predicate.of((x: number) => x > 10).and(x => x < 20)\n     */\n    and(fn:(x:T)=>boolean): Predicate<T>;\n\n    /**\n     * Combines two predicates with the 'or' logical operation.\n     * For instance:\n     *\n     *     Predicate.of((x: number) => x < 5).or(x => x > 10)\n     */\n    or(fn:(x:T)=>boolean): Predicate<T>;\n\n    /**\n     * Unary operation to negate the predicate.\n     */\n    negate(): Predicate<T>;\n}\n\n/**\n * The Predicates class offers some helper functions to deal\n * with [[Predicate]] including the ability to build [[Predicate]]\n * from functions using [[PredicateStatic.of]], some builtin predicates\n * like [[PredicateStatic.isIn]], and the ability to combine to combine\n * Predicates like with [[PredicateStatic.allOf]].\n */\nexport class PredicateStatic {\n\n    /**\n     * Take a predicate function and of it to become a [[Predicate]]\n     * (enabling you to call [[Predicate.and]], and other logic operations on it)\n     */\n    of<T>(fn: (x:T)=>boolean): Predicate<T> {\n        const r = <Predicate<T>>fn;\n        r.and = (other:(x:T)=>boolean) => Predicate.of((x:T) => r(x) && other(x));\n        r.or = (other:(x:T)=>boolean) => Predicate.of((x:T) => r(x) || other(x));\n        r.negate = () => Predicate.of((x:T) => !fn(x));\n        return r;\n    }\n\n    /**\n     * Return a [[Predicate]] checking whether a value is equal to the\n     * value you give as parameter.\n     */\n    equals<T>(other: T&WithEquality): Predicate<T&WithEquality> {\n        return Predicate.of(x => areEqual(other, x));\n    }\n\n    /**\n     * Return a [[Predicate]] checking whether a value is contained in the\n     * list of values you give as parameter.\n     */\n    isIn<T>(others: Iterable<T&WithEquality>): Predicate<T&WithEquality> {\n        return Predicate.of<T&WithEquality>(x => Vector.ofIterable(others).contains(x));\n    }\n\n    /**\n     * Return a [[Predicate]] checking whether all of the predicate functions given hold\n     */\n    allOf<T>(...predicates: Array<(x:T)=>boolean>): Predicate<T> {\n        return Predicate.of<T>(x => Vector.ofIterable(predicates).allMatch(p=>p(x)));\n    }\n\n    /**\n     * Return a [[Predicate]] checking whether any of the predicate functions given hold\n     */\n    anyOf<T>(...predicates: Array<(x:T)=>boolean>): Predicate<T> {\n        return Predicate.of<T>(x => Vector.ofIterable(predicates).anyMatch(p=>p(x)));\n    }\n\n    /**\n     * Return a [[Predicate]] checking whether none of the predicate functions given hold\n     */\n    noneOf<T>(...predicates: Array<(x:T)=>boolean>): Predicate<T> {\n        return Predicate.of<T>(x => !Vector.ofIterable(predicates).anyMatch(p=>p(x)));\n    }\n}\n\n/**\n * The Predicate constant allows to call the [[Predicate]] \"static\" methods.\n */\nexport const Predicate = new PredicateStatic();\n"
  },
  {
    "path": "src/Seq.ts",
    "content": "import { WithEquality, Ordering, ToOrderable } from \"./Comparison\";\nimport { HashMap } from \"./HashMap\";\nimport { HashSet } from \"./HashSet\";\nimport { Option } from \"./Option\";\nimport { Collection } from \"./Collection\";\nimport { Stream } from \"./Stream\";\n\n/**\n * IterableArray can take a type and apply iterable to its\n * \"components\". That is useful for instance for [[Vector.zip]]\n *\n * `IterableArray<[string,number,string]>`\n * => `[Iterable<string>, Iterable<number>, Iterable<string>]`\n */\nexport type IterableArray<T> = { [K in keyof T] : Iterable<T[K]> };\n\n/**\n * A generic interface for list-like implementations.\n * @param T the item type\n */\nexport interface Seq<T> extends Collection<T> {\n\n    /**\n     * Append an element at the end of the collection.\n     */\n    append(elt: T): Seq<T>;\n\n    /**\n     * Append multiple elements at the end of the collection.\n     * Note that arrays are also iterables.\n     */\n    appendAll(elts: Iterable<T>): Seq<T>;\n\n    /**\n     * Remove multiple elements from a collection\n     *\n     *     Vector.of(1,2,3,4,3,2,1).removeAll([2,4])\n     *     => Vector.of(1,3,3,1)\n     */\n    removeAll(elts: Iterable<T&WithEquality>): Seq<T>;\n\n    /**\n     * Removes the first element matching the predicate\n     * (use [[Seq.filter]] to remove all elements matching a predicate)\n     */\n    removeFirst(predicate: (v:T)=>boolean): Seq<T>;\n\n    /**\n     * Call a function for element in the collection.\n     * Return the unchanged collection.\n     */\n    forEach(fn: (v:T)=>void): Seq<T>;\n\n    /**\n     * Get the first value of the collection, if any.\n     * returns Option.Some if the collection is not empty,\n     * Option.None if it's empty.\n     */\n    head(): Option<T>;\n\n    /**\n     * Get the last value of the collection, if any.\n     * returns Option.Some if the collection is not empty,\n     * Option.None if it's empty.\n     */\n    last(): Option<T>;\n\n    /**\n     * Get all the elements in the collection but the first one.\n     * Option.None if it's empty.\n     */\n    tail(): Option<Seq<T>>;\n\n    /**\n     * Return a new collection where each element was transformed\n     * by the mapper function you give.\n     */\n    map<U>(mapper:(v:T)=>U): Seq<U>;\n\n    /**\n     * Apply the mapper function on every element of this collection.\n     * The mapper function returns an Option; if the Option is a Some,\n     * the value it contains is added to the result Collection, if it's\n     * a None, the value is discarded.\n     *\n     *     Vector.of(1,2,6).mapOption(x => x%2===0 ?\n     *         Option.of(x+1) : Option.none<number>())\n     *     => Vector.of(3, 7)\n     */\n    mapOption<U>(mapper:(v:T)=>Option<U>): Seq<U>;\n\n    /**\n     * Search for an item matching the predicate you pass,\n     * return Option.Some of that element if found,\n     * Option.None otherwise.\n     */\n    find(predicate:(v:T)=>boolean): Option<T>;\n\n    /**\n     * Calls the function you give for each item in the collection,\n     * your function returns a collection, all the collections are\n     * concatenated.\n     * This is the monadic bind.\n     */\n    flatMap<U>(mapper:(v:T)=>Seq<U>): Seq<U>;\n\n    /**\n     * Randomly reorder the elements of the collection.\n     */\n    shuffle(): Seq<T>;\n\n    /**\n     * Returns a new collection with elements\n     * sorted according to the comparator you give.\n     *\n     *     const activityOrder = [\"Writer\", \"Actor\", \"Director\"];\n     *     Vector.of({name:\"George\", activity: \"Director\"}, {name:\"Robert\", activity: \"Actor\"})\n     *         .sortBy((p1,p2) => activityOrder.indexOf(p1.activity) - activityOrder.indexOf(p2.activity));\n     *     => Vector.of({\"name\":\"Robert\",\"activity\":\"Actor\"}, {\"name\":\"George\",\"activity\":\"Director\"})\n     *\n     * also see [[Seq.sortOn]]\n     */\n    sortBy(compare: (v1:T,v2:T)=>Ordering): Seq<T>;\n\n    /**\n     * Give a function associating a number or a string with\n     * elements from the collection, and the elements\n     * are sorted according to that value.\n     *\n     *     Vector.of({a:3,b:\"b\"}, {a:1,b:\"test\"}, {a:2,b:\"a\"}).sortOn(elt=>elt.a)\n     *     => Vector.of({a:1,b:\"test\"}, {a:2,b:\"a\"}, {a:3,b:\"b\"})\n     *\n     * You can also sort by multiple criteria, and request 'descending'\n     * sorting:\n     *\n     *     Vector.of({a:1,b:\"b\"}, {a:1,b:\"test\"}, {a:2,b:\"a\"}).sortOn(elt=>elt.a, {desc:elt=>elt.b})\n     *     => Vector.of({a:1,b:\"test\"}, {a:1,b:\"b\"}, {a:2,b:\"a\"})\n     *\n     * also see [[Seq.sortBy]]\n     */\n    sortOn(...getKeys: Array<ToOrderable<T>|{desc:ToOrderable<T>}>): Seq<T>;\n\n    /**\n     * Prepend an element at the beginning of the collection.\n     */\n    prepend(elt: T): Seq<T>;\n\n    /**\n     * Prepend multiple elements at the beginning of the collection.\n     */\n    prependAll(elts: Iterable<T>): Seq<T>;\n\n    /**\n     * Joins elements of the collection by a separator.\n     * Example:\n     *\n     *     Vector.of(1,2,3).mkString(\", \")\n     *     => \"1, 2, 3\"\n     */\n    mkString(separator: string): string;\n\n    /**\n     * Combine this collection with the collection you give in\n     * parameter to produce a new collection which combines both,\n     * in pairs. For instance:\n     *\n     *     Vector.of(1,2,3).zip([\"a\",\"b\",\"c\"])\n     *     => Vector.of([1,\"a\"], [2,\"b\"], [3,\"c\"])\n     *\n     * The result collection will have the length of the shorter\n     * of both collections. Extra elements will be discarded.\n     *\n     * Also see [[Vector.zip]], [[LinkedListStatic.zip]] and [[StreamStatic.zip]]\n     * (static versions which can more than two iterables)\n     */\n    zip<U>(other: Iterable<U>): Seq<[T,U]>;\n\n    /**\n     * Combine this collection with the index of the elements\n     * in it. Handy if you need the index when you map on\n     * the collection for instance:\n     *\n     *     Vector.of(\"a\",\"b\").zipWithIndex().map(([v,idx]) => v+idx);\n     *     => Vector.of(\"a0\", \"b1\")\n     */\n    zipWithIndex(): Seq<[T,number]>;\n\n    /**\n     * Retrieve the element at index idx.\n     * Returns an option because the collection may\n     * contain less elements than the index.\n     */\n    get(idx: number): Option<T>;\n\n    /**\n     * Returns a new collection with the first\n     * n elements discarded.\n     * If the collection has less than n elements,\n     * returns the empty collection.\n     */\n    drop(n:number): Seq<T>;\n\n    /**\n     * Returns a new collection, discarding the first elements\n     * until one element fails the predicate. All elements\n     * after that point are retained.\n     */\n    dropWhile(predicate:(x:T)=>boolean): Seq<T>;\n\n    /**\n     * Returns a new collection with the last\n     * n elements discarded.\n     * If the collection has less than n elements,\n     * returns the empty collection.\n     */\n    dropRight(n:number): Seq<T>;\n\n    /**\n     * Returns a new collection, discarding the last elements\n     * until one element fails the predicate. All elements\n     * before that point are retained.\n     */\n    dropRightWhile(predicate:(x:T)=>boolean): Seq<T>;\n\n    /**\n     * Returns a new collection, discarding the elements\n     * after the first element which fails the predicate.\n     */\n    takeWhile(predicate:(x:T)=>boolean): Seq<T>;\n\n    /**\n     * Returns a new collection, discarding the elements\n     * after the first element which fails the predicate,\n     * but starting from the end of the collection.\n     *\n     *     Vector.of(1,2,3,4).takeRightWhile(x => x > 2)\n     *     => Vector.of(3,4)\n     */\n    takeRightWhile(predicate:(x:T)=>boolean): Seq<T>;\n\n    /**\n     * Return a new collection containing the first n\n     * elements from this collection\n     *\n     *     Vector.of(1,2,3,4).take(2)\n     *     => Vector.of(1,2)\n     */\n    take(n:number): Seq<T>;\n\n    /**\n     * Remove duplicate items; elements are mapped to keys, those\n     * get compared.\n     *\n     *     Vector.of(1,1,2,3,2,3,1).distinctBy(x => x);\n     *     => Vector.of(1,2,3)\n     */\n    distinctBy<U>(keyExtractor: (x:T)=>U&WithEquality): Seq<T>;\n\n    /**\n     * Reverse the collection. For instance:\n     *\n     *     Vector.of(1,2,3).reverse();\n     *     => Vector.of(3,2,1)\n     */\n    reverse(): Seq<T>;\n\n    /**\n     * Takes a predicate; returns a pair of collections.\n     * The first one is the longest prefix of this collection\n     * which satisfies the predicate, and the second collection\n     * is the remainder of the collection.\n     *\n     *    Vector.of(1,2,3,4,5,6).span(x => x <3)\n     *    => [Vector.of(1,2), Vector.of(3,4,5,6)]\n     */\n    span(predicate:(x:T)=>boolean): [Seq<T>,Seq<T>];\n\n    /**\n     * Split the collection at a specific index.\n     *\n     *     Vector.of(1,2,3,4,5).splitAt(3)\n     *     => [Vector.of(1,2,3), Vector.of(4,5)]\n     */\n    splitAt(index:number): [Seq<T>,Seq<T>];\n\n    /**\n     * Slides a window of a specific size over the sequence.\n     * Returns a lazy stream so memory use is not prohibitive.\n     *\n     *     Vector.of(1,2,3,4,5,6,7,8).sliding(3)\n     *     => Stream.of(Vector.of(1,2,3), Vector.of(4,5,6), Vector.of(7,8))\n     */\n    sliding(count:number): Stream<Seq<T>>;\n\n    /**\n     * Apply the function you give to all elements of the sequence\n     * in turn, keeping the intermediate results and returning them\n     * along with the final result in a list.\n     * The last element of the result is the final cumulative result.\n     *\n     *     Vector.of(1,2,3).scanLeft(0, (cur,soFar)=>soFar+cur)\n     *     => Vector.of(0,1,3,6)\n     */\n    scanLeft<U>(init:U, fn:(soFar:U,cur:T)=>U): Seq<U>;\n\n    /**\n     * Apply the function you give to all elements of the sequence\n     * in turn, keeping the intermediate results and returning them\n     * along with the final result in a list.\n     * The first element of the result is the final cumulative result.\n     *\n     *     Vector.of(1,2,3).scanRight(0, (cur,soFar)=>soFar+cur)\n     *     => Vector.of(6,5,3,0)\n     */\n    scanRight<U>(init:U, fn:(cur:T,soFar:U)=>U): Seq<U>;\n\n    /**\n     * Convert this collection to a map. You give a function which\n     * for each element in the collection returns a pair. The\n     * key of the pair will be used as a key in the map, the value,\n     * as a value in the map. If several values get the same key,\n     * entries will be lost.\n     *\n     *     Vector.of(1,2,3).toMap(x=>[x.toString(), x])\n     *     => HashMap.of([\"1\",1], [\"2\",2], [\"3\",3])\n     */\n    toMap<K,V>(converter:(x:T)=>[K & WithEquality,V]): HashMap<K,V>;\n\n    /**\n     * Convert this collection to a set. Since the elements of the\n     * Seq may not support equality, you must pass a function returning\n     * a value supporting equality.\n     *\n     *     Vector.of(1,2,3,3,4).toSet(x=>x)\n     *     => HashSet.of(1,2,3,4)\n     */\n    toSet<K>(converter:(x:T)=>K&WithEquality): HashSet<K>;\n\n    /**\n     * Transform this value to another value type.\n     * Enables fluent-style programming by chaining calls.\n     */\n    transform<U>(converter:(x:Seq<T>)=>U): U;\n}\n"
  },
  {
    "path": "src/SeqHelpers.ts",
    "content": "import { Option } from \"./Option\";\nimport { WithEquality, hasTrueEquality,\n         Ordering, ToOrderable } from \"./Comparison\";\nimport { HashMap } from \"./HashMap\";\nimport { Seq } from \"./Seq\";\nimport { Collection } from \"./Collection\";\nimport { Stream, ConsStream } from \"./Stream\";\nimport { Lazy } from \"./Lazy\";\nimport { HashSet } from \"./HashSet\";\n\n/**\n * @hidden\n */\nexport function shuffle(array: any[]) {\n    // https://stackoverflow.com/a/2450976/516188\n    var currentIndex = array.length, temporaryValue, randomIndex;\n\n    // While there remain elements to shuffle...\n    while (0 !== currentIndex) {\n\n        // Pick a remaining element...\n        randomIndex = Math.floor(Math.random() * currentIndex);\n        currentIndex -= 1;\n\n        // And swap it with the current element.\n        temporaryValue = array[currentIndex];\n        array[currentIndex] = array[randomIndex];\n        array[randomIndex] = temporaryValue;\n    }\n\n    return array;\n}\n\n/**\n * @hidden\n */\nexport function arrangeBy<T,K>(collection: Collection<T>, getKey: (v:T)=>K&WithEquality): Option<HashMap<K,T>> {\n    return Option.of(collection.groupBy(getKey).mapValues(v => v.single()))\n        .filter(map => !map.anyMatch((k,v) => v.isNone()))\n        .map(map => map.mapValues(v => v.getOrThrow()));\n}\n\n/**\n * @hidden\n */\nexport function seqHasTrueEquality<T>(seq: Seq<T>): boolean {\n    return seq.find(x => x!=null).hasTrueEquality();\n}\n\n/**\n * @hidden\n */\nexport function zipWithIndex<T>(seq: Seq<T>): Seq<[T,number]> {\n    return seq.zip<number>(Stream.iterate(0,i=>i+1));\n}\n\n/**\n * @hidden\n */\nexport function sortOn<T>(seq: Seq<T>, getKeys: Array<ToOrderable<T>|{desc:ToOrderable<T>}>): Seq<T> {\n    return seq.sortBy((x,y) => {\n        for (const getKey of getKeys) {\n            if ((<any>getKey).desc) {\n                const a = (<ToOrderable<T>>(<any>getKey).desc)(x);\n                const b = (<ToOrderable<T>>(<any>getKey).desc)(y);\n                if (a === b) {\n                    continue;\n                }\n                return a<b?Ordering.GT:Ordering.LT;\n            } else {\n                const a = (<ToOrderable<T>>getKey)(x);\n                const b = (<ToOrderable<T>>getKey)(y);\n                if (a === b) {\n                    continue;\n                }\n                return a>b?Ordering.GT:Ordering.LT;\n            }\n        }\n        return Ordering.EQ;\n    });\n}\n\n/**\n * @hidden\n */\nexport function distinctBy<T,U>(seq: Collection<T>, keyExtractor: (x:T)=>U&WithEquality): Collection<T> {\n    let knownKeys = HashSet.empty<U>();\n    return seq.filter(x => {\n        const key = keyExtractor(x);\n        const r = knownKeys.contains(key);\n        if (!r) {\n            knownKeys = knownKeys.add(key);\n        }\n        return !r;\n    });\n}\n\n/**\n * Utility function to help converting a value to string\n * util.inspect seems to depend on node.\n * @hidden\n */\nexport function toStringHelper(\n    obj: any|null,\n    options: {quoteStrings:boolean} = {quoteStrings: true}): string\n{\n    if (Array.isArray(obj)) {\n        return \"[\" + obj.map(o => toStringHelper(o, options)) + \"]\"\n    }\n    if (typeof obj === \"string\") {\n        return options.quoteStrings ? `'${obj}'` : obj;\n    }\n    if (obj && (obj.toString !== Object.prototype.toString)) {\n        return obj.toString();\n    }\n    // We used to use JSON.stringify here, but that will\n    // throw an exception if there are cycles, which we\n    // absolutely don't want!\n    // https://stackoverflow.com/a/48254637/516188\n    const customStringify = function (v:any) {\n        const cache = new Set();\n        return JSON.stringify(v, function (key, value) {\n            if (typeof value === 'object' && value !== null) {\n                if (cache.has(value)) {\n                    // Circular reference found, discard key\n                    return;\n                }\n                // Store value in our set\n                cache.add(value);\n            }\n            return value;\n        });\n    };\n    return customStringify(obj);\n}\n\n/**\n * @hidden\n */\nexport function minBy<T>(coll: Collection<T>, compare: (v1:T,v2:T)=>Ordering): Option<T> {\n    return coll.reduce((v1,v2)=>compare(v1,v2)<0 ? v2 : v1);\n}\n\n/**\n * @hidden\n */\nexport function minOn<T>(coll: Collection<T>, getSortable: ToOrderable<T>): Option<T> {\n    if (coll.isEmpty()) {\n        return Option.none<T>();\n    }\n    let iter = coll[Symbol.iterator]();\n    let step = iter.next();\n    let val = getSortable(step.value);\n    let result = step.value;\n    while (!(step = iter.next()).done) {\n        const curVal = getSortable(step.value);\n        if (curVal < val) {\n            val = curVal;\n            result = step.value;\n        }\n    }\n    return Option.of(result);\n}\n\n/**\n * @hidden\n */\nexport function maxBy<T>(coll: Collection<T>, compare: (v1:T,v2:T)=>Ordering): Option<T> {\n    return coll.reduce((v1,v2)=>compare(v1,v2)>0 ? v2 : v1);\n}\n\n/**\n * @hidden\n */\nexport function maxOn<T>(coll: Collection<T>, getSortable: ToOrderable<T>): Option<T> {\n    if (coll.isEmpty()) {\n        return Option.none<T>();\n    }\n    let iter = coll[Symbol.iterator]();\n    let step = iter.next();\n    let val = getSortable(step.value);\n    let result = step.value;\n    while (!(step = iter.next()).done) {\n        const curVal = getSortable(step.value);\n        if (curVal > val) {\n            val = curVal;\n            result = step.value;\n        }\n    }\n    return Option.of(result);\n}\n\n/**\n * @hidden\n */\nexport function sumOn<T>(coll: Collection<T>, getNumber: (v:T)=>number): number {\n    return coll.foldLeft(0, (soFar,cur)=>soFar+getNumber(cur));\n}\n\n/**\n * @hidden\n */\nexport function reduce<T>(coll: Collection<T>, combine: (v1:T,v2:T)=>T): Option<T> {\n    if (coll.isEmpty()) {\n        return Option.none<T>();\n    }\n    let iter = coll[Symbol.iterator]();\n    let step = iter.next();\n    let result = step.value;\n    while (!(step = iter.next()).done) {\n        result = combine(result, step.value);\n    }\n    return Option.of(result);\n}\n\n/**\n * @hidden\n */\nexport function sliding<T>(seq: Seq<T>, count:number): Stream<Seq<T>> {\n    // in a way should get better performance with Seq.splitAt instead\n    // of Seq.take+Seq.drop, but we should be lazy and not hold another\n    // version of the sequence in memory (though for linked list it's free,\n    // it's not the case for Vector)\n    return seq.isEmpty() ?\n        Stream.empty<Seq<T>>() :\n        new ConsStream(seq.take(count), Lazy.of(() => sliding(seq.drop(count), count)));\n}\n\n/**\n * @hidden\n */\nexport function removeAll<T>(seq: Seq<T>, elts:Iterable<T&WithEquality>): Seq<T> {\n    const toRemove = HashSet.ofIterable(elts);\n    // I know T must have equality since the parameter has it and is the same type.\n    return <Seq<T>><any>(<Seq<T&WithEquality>><any>seq).filter(x => !toRemove.contains(x));\n}\n"
  },
  {
    "path": "src/Stream.ts",
    "content": "/**\n * A lazy, potentially infinite, sequence of values.\n *\n * The code is organized through the class [[EmptyStream]] (empty list\n * or tail), the class [[ConsStream]] (list value and lazy pointer to next),\n * and the type alias [[Stream]] (empty or cons).\n *\n * Finally, \"static\" functions on Option are arranged in the class\n * [[StreamStatic]] and are accessed through the global constant Stream.\n *\n * Use take() for instance to reduce an infinite stream to a finite one.\n *\n * Examples:\n *\n *     Stream.iterate(1, x => x*2).take(4);\n *     => Stream.of(1,2,4,8)\n *\n *     Stream.continually(Math.random).take(2);\n *     => Stream.of(0.49884723907769635, 0.3226548779864311)\n */\nimport { Option, Some } from \"./Option\";\nimport { Vector } from \"./Vector\";\nimport { WithEquality, getHashCode,\n         areEqual, Ordering, ToOrderable } from \"./Comparison\";\nimport { contractTrueEquality } from \"./Contract\";\nimport { inspect } from \"./Value\";\nimport { HashMap } from \"./HashMap\";\nimport { HashSet } from \"./HashSet\";\nimport { Seq, IterableArray } from \"./Seq\";\nimport { Lazy } from \"./Lazy\";\nimport { LinkedList } from \"./LinkedList\";\nimport * as SeqHelpers from \"./SeqHelpers\";\n\n/**\n * A Stream is either [[EmptyStream]] or [[ConsStream]]\n * \"static methods\" available through [[StreamStatic]]\n * @param T the item type\n */\nexport type Stream<T> = EmptyStream<T> | ConsStream<T>;\n\n/**\n * Holds the \"static methods\" for [[Stream]]\n */\nexport class StreamStatic {\n    /**\n     * The empty stream\n     */\n    empty<T>(): Stream<T> {\n        return <EmptyStream<T>>emptyStream;\n    }\n\n    /**\n     * Create a Stream with the elements you give.\n     */\n    of<T>(elt:T, ...elts:T[]): ConsStream<T>;\n    of<T>(...elts:T[]): Stream<T>;\n    of<T>(...elts:T[]): Stream<T> {\n        return Stream.ofIterable(elts);\n    }\n\n    /**\n     * Build a stream from any iterable, which means also\n     * an array for instance.\n     * @param T the item type\n     */\n    ofIterable<T>(elts: Iterable<T>): Stream<T> {\n        // need to eagerly copy the iterable. the reason\n        // is, if we would build the stream based on the iterator\n        // in the iterable, Stream.tail() would do it.next().\n        // but it.next() modifies the iterator (mutability),\n        // and you would end up with getting two different tails\n        // for the same stream if you call .tail() twice in a row\n        if (Array.isArray(elts)) {\n            return Stream.ofArray(elts);\n        }\n        return Stream.ofArray(Array.from(elts));\n    }\n\n    /**\n     * Curried type guard for Stream.\n     * Sometimes needed also due to https://github.com/Microsoft/TypeScript/issues/20218\n     *\n     *     Vector.of(Stream.of(1), Stream.empty<number>())\n     *         .filter(Stream.isEmpty)\n     *     => Vector.of(Stream.empty<number>())\n     */\n    isEmpty<T>(s: Stream<T>): s is EmptyStream<T> {\n        return s.isEmpty();\n    }\n\n    /**\n     * Curried type guard for Stream.\n     * Sometimes needed also due to https://github.com/Microsoft/TypeScript/issues/20218\n     *\n     *     Vector.of(Stream.of(1), Stream.empty<number>())\n     *         .filter(Stream.isNotEmpty)\n     *         .map(s => s.head().get()+1)\n     *     => Vector.of(2)\n     */\n    isNotEmpty<T>(s: Stream<T>): s is ConsStream<T> {\n        return !s.isEmpty();\n    }\n\n    /**\n     * @hidden\n     */\n    private ofArray<T>(elts: Array<T>): Stream<T> {\n        if (elts.length === 0) {\n            return <EmptyStream<T>>emptyStream;\n        }\n        const head = elts[0];\n        return new ConsStream(head, Lazy.of(() => Stream.ofArray(elts.slice(1))));\n    }\n\n    /**\n     * Build an infinite stream from a seed and a transformation function.\n     *\n     *     Stream.iterate(1, x => x*2).take(4);\n     *     => Stream.of(1,2,4,8)\n     */\n    iterate<T>(seed:T, fn: (v:T)=>T): ConsStream<T> {\n        return new ConsStream(seed, Lazy.of(()=>Stream.iterate(fn(seed), fn)));\n    }\n\n    /**\n     * Build an infinite stream by calling repeatedly a function.\n     *\n     *     Stream.continually(() => 1).take(4);\n     *     => Stream.of(1,1,1,1)\n     *\n     *     Stream.continually(Math.random).take(2);\n     *     => Stream.of(0.49884723907769635, 0.3226548779864311)\n     */\n    continually<T>(fn: ()=>T): ConsStream<T> {\n        return new ConsStream(fn(), Lazy.of(() => Stream.continually(fn)));\n    }\n\n    /**\n     * Dual to the foldRight function. Build a collection from a seed.\n     * Takes a starting element and a function.\n     * It applies the function on the starting element; if the\n     * function returns None, it stops building the list, if it\n     * returns Some of a pair, it adds the first element to the result\n     * and takes the second element as a seed to keep going.\n     *\n     *     Stream.unfoldRight(\n     *          10, x=>Option.of(x)\n     *              .filter(x => x!==0)\n     *              .map<[number,number]>(x => [x,x-1]));\n     *     => Stream.of(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)\n     */\n    unfoldRight<T,U>(seed: T, fn: (x:T)=>Option<[U,T]>): Stream<U> {\n        let nextVal = fn(seed);\n        if (nextVal.isNone()) {\n            return <EmptyStream<U>>emptyStream;\n        }\n        return new ConsStream(\n            nextVal.get()[0],\n            Lazy.of(()=>Stream.unfoldRight(nextVal.getOrThrow()[1], fn)));\n    }\n\n    /**\n     * Combine any number of iterables you give in as\n     * parameters to produce a new collection which combines all,\n     * in tuples. For instance:\n     *\n     *     Stream.zip(Stream.of(1,2,3), [\"a\",\"b\",\"c\"], LinkedList.of(8,9,10))\n     *     => Stream.of([1,\"a\",8], [2,\"b\",9], [3,\"c\",10])\n     *\n     * The result collection will have the length of the shorter\n     * of the input iterables. Extra elements will be discarded.\n     *\n     * Also see the non-static version [[ConsStream.zip]], which only combines two\n     * collections.\n     * @param A A is the type of the tuple that'll be generated\n     *          (`[number,string,number]` for the code sample)\n     */\n    zip<A extends any[]>(...iterables: IterableArray<A>): Stream<A> {\n        const iterators: Iterator<A>[] = iterables.map(i => i[Symbol.iterator]());\n        let items = iterators.map(i => i.next());\n\n        if (items.some(item => item.done)) {\n            return <EmptyStream<A>>emptyStream;\n        }\n\n        return new ConsStream(items.map(item => item.value) as A,\n                              Lazy.of(() => Stream.zip<A>(...\n                                  <any>iterators.map(i=>({ [Symbol.iterator]: ()=>i})))));\n    }\n\n}\n\n/**\n * The Stream constant allows to call the Stream \"static\" methods\n */\nexport const Stream = new StreamStatic();\n\n/**\n * EmptyStream is the empty stream; every non-empty\n * stream also has a pointer to an empty stream\n * after its last element.\n * \"static methods\" available through [[StreamStatic]]\n * @param T the item type\n */\nexport class EmptyStream<T> implements Seq<T> {\n\n    /**\n     * @hidden\n     */\n    readonly className: \"EmptyStream\" = <any>undefined;  // https://stackoverflow.com/a/47841595/516188\n\n    /**\n     * Implementation of the Iterator interface.\n     */\n    [Symbol.iterator](): Iterator<T> {\n        return {\n            next(): IteratorResult<T> {\n                return {\n                    done: true,\n                    value: <any>undefined\n                };\n            }\n        }\n    }\n\n    /**\n     * View this Some a as Stream. Useful to help typescript type\n     * inference sometimes.\n     */\n    asStream(): Stream<T> {\n        return this;\n    }\n\n    /**\n     * @hidden\n     */\n    hasTrueEquality(): boolean {\n        return SeqHelpers.seqHasTrueEquality<T>(this);\n    }\n\n    /**\n     * Get the length of the collection.\n     */\n    length(): number {\n        return 0;\n    }\n\n    /**\n     * If the collection contains a single element,\n     * return Some of its value, otherwise return None.\n     */\n    single(): Option<T> {\n        return Option.none<T>();\n    }\n\n    /**\n     * true if the collection is empty, false otherwise.\n     */\n    isEmpty(): this is EmptyStream<T> {\n        return true;\n    }\n\n    /**\n     * Get the first value of the collection, if any.\n     * returns Option.Some if the collection is not empty,\n     * Option.None if it's empty.\n     */\n    head(): Option<T> {\n        return Option.none<T>();\n    }\n\n    /**\n     * Get all the elements in the collection but the first one.\n     * If the collection is empty, return None.\n     */\n    tail(): Option<Stream<T>> {\n        return Option.none<Stream<T>>();\n    }\n\n    /**\n     * Get the last value of the collection, if any.\n     * returns Option.Some if the collection is not empty,\n     * Option.None if it's empty.\n     */\n    last(): Option<T> {\n        return Option.none<T>();\n    }\n\n    /**\n     * Retrieve the element at index idx.\n     * Returns an option because the collection may\n     * contain less elements than the index.\n     *\n     * Careful this is going to have poor performance\n     * on Stream, which is not a good data structure\n     * for random access!\n     */\n    get(idx: number): Option<T> {\n        return Option.none<T>();\n    }\n\n    /**\n     * Search for an item matching the predicate you pass,\n     * return Option.Some of that element if found,\n     * Option.None otherwise.\n     */\n    find(predicate:(v:T)=>boolean): Option<T> {\n        return Option.none<T>();\n    }\n\n    /**\n     * Returns true if the item is in the collection,\n     * false otherwise.\n     */\n    contains(v:T&WithEquality): boolean {\n        return false;\n    }\n\n    /**\n     * Return a new stream keeping only the first n elements\n     * from this stream.\n     */\n    take(n: number): Stream<T> {\n        return this;\n    }\n\n    /**\n     * Returns a new collection, discarding the elements\n     * after the first element which fails the predicate.\n     */\n    takeWhile(predicate: (x:T)=>boolean): Stream<T> {\n        return this;\n    }\n\n    /**\n     * Returns a new collection, discarding the elements\n     * after the first element which fails the predicate,\n     * but starting from the end of the collection.\n     *\n     *     Stream.of(1,2,3,4).takeRightWhile(x => x > 2)\n     *     => Stream.of(3,4)\n     */\n    takeRightWhile(predicate:(x:T)=>boolean): Stream<T> {\n        return this;\n    }\n\n    /**\n     * Returns a new collection with the first\n     * n elements discarded.\n     * If the collection has less than n elements,\n     * returns the empty collection.\n     */\n    drop(n:number): Stream<T> {\n        return this;\n    }\n\n    /**\n     * Returns a new collection, discarding the first elements\n     * until one element fails the predicate. All elements\n     * after that point are retained.\n     */\n    dropWhile(predicate:(x:T)=>boolean): Stream<T> {\n        return this;\n    }\n\n    /**\n     * Returns a new collection with the last\n     * n elements discarded.\n     * If the collection has less than n elements,\n     * returns the empty collection.\n     */\n    dropRight(n:number): Stream<T> {\n        return this;\n    }\n\n    /**\n     * Returns a new collection, discarding the last elements\n     * until one element fails the predicate. All elements\n     * before that point are retained.\n     */\n    dropRightWhile(predicate:(x:T)=>boolean): Stream<T> {\n        return this;\n    }\n\n    /**\n     * Reduces the collection to a single value using the\n     * associative binary function you give. Since the function\n     * is associative, order of application doesn't matter.\n     *\n     * Example:\n     *\n     *     Stream.of(1,2,3).fold(0, (a,b) => a + b);\n     *     => 6\n     */\n    fold(zero:T, fn:(v1:T,v2:T)=>T): T {\n        return zero;\n    }\n\n    /**\n     * Reduces the collection to a single value.\n     * Left-associative.\n     *\n     * Example:\n     *\n     *     Vector.of(\"a\", \"b\", \"c\").foldLeft(\"!\", (xs,x) => x+xs);\n     *     => \"cba!\"\n     *\n     * @param zero The initial value\n     * @param fn A function taking the previous value and\n     *           the current collection item, and returning\n     *           an updated value.\n     */\n    foldLeft<U>(zero: U, fn:(soFar:U,cur:T)=>U): U {\n        return zero;\n    }\n\n    /**\n     * Reduces the collection to a single value.\n     * Right-associative.\n     *\n     * Example:\n     *\n     *     Vector.of(\"a\", \"b\", \"c\").foldRight(\"!\", (x,xs) => xs+x);\n     *     => \"!cba\"\n     *\n     * @param zero The initial value\n     * @param fn A function taking the current collection item and\n     *           the previous value , and returning\n     *           an updated value.\n     */\n    foldRight<U>(zero: U, fn:(cur:T, soFar:U)=>U): U {\n        return zero;\n    }\n\n    /**\n     * Combine this collection with the collection you give in\n     * parameter to produce a new collection which combines both,\n     * in pairs. For instance:\n     *\n     *     Stream.of(1,2,3).zip([\"a\",\"b\",\"c\"])\n     *     => Stream.of([1,\"a\"], [2,\"b\"], [3,\"c\"])\n     *\n     * The result collection will have the length of the shorter\n     * of both collections. Extra elements will be discarded.\n     *\n     * Also see [[StreamStatic.zip]] (static version which can more than two\n     * iterables)\n     */\n    zip<U>(other: Iterable<U>): Stream<[T,U]> {\n        return <EmptyStream<[T,U]>>emptyStream;\n    }\n\n    /**\n     * Combine this collection with the index of the elements\n     * in it. Handy if you need the index when you map on\n     * the collection for instance:\n     *\n     *     Stream.of(\"a\",\"b\").zipWithIndex().map(([v,idx]) => v+idx);\n     *     => Stream.of(\"a0\", \"b1\")\n     */\n    zipWithIndex(): Stream<[T,number]> {\n        return <Stream<[T,number]>>SeqHelpers.zipWithIndex<T>(this);\n    }\n\n    /**\n     * Reverse the collection. For instance:\n     *\n     *     Stream.of(1,2,3).reverse();\n     *     => Stream.of(3,2,1)\n     */\n    reverse(): Stream<T> {\n        return this;\n    }\n\n    /**\n     * Takes a predicate; returns a pair of collections.\n     * The first one is the longest prefix of this collection\n     * which satisfies the predicate, and the second collection\n     * is the remainder of the collection.\n     *\n     *    Stream.of(1,2,3,4,5,6).span(x => x <3)\n     *    => [Stream.of(1,2), Stream.of(3,4,5,6)]\n     */\n    span(predicate:(x:T)=>boolean): [Stream<T>,Stream<T>] {\n        return [this, this];\n    }\n\n    /**\n     * Split the collection at a specific index.\n     *\n     *     Stream.of(1,2,3,4,5).splitAt(3)\n     *     => [Stream.of(1,2,3), Stream.of(4,5)]\n     */\n    splitAt(index:number): [Stream<T>,Stream<T>] {\n        return [this, this];\n    }\n\n    /**\n     * Returns a pair of two collections; the first one\n     * will only contain the items from this collection for\n     * which the predicate you give returns true, the second\n     * will only contain the items from this collection where\n     * the predicate returns false.\n     *\n     *     Stream.of(1,2,3,4).partition(x => x%2===0)\n     *     => [Stream.of(2,4),Stream.of(1,3)]\n     */\n    partition<U extends T>(predicate:(v:T)=>v is U): [Stream<U>,Stream<Exclude<T,U>>];\n    partition(predicate:(x:T)=>boolean): [Stream<T>,Stream<T>];\n    partition<U extends T>(predicate:(v:T)=>boolean): [Stream<U>,Stream<any>] {\n        return [Stream.empty<U>(), Stream.empty<T>()];\n    }\n\n    /**\n     * Group elements in the collection using a classifier function.\n     * Elements are then organized in a map. The key is the value of\n     * the classifier, and in value we get the list of elements\n     * matching that value.\n     *\n     * also see [[ConsStream.arrangeBy]]\n     */\n    groupBy<C>(classifier: (v:T)=>C & WithEquality): HashMap<C,Stream<T>> {\n        return HashMap.empty<C,Stream<T>>();\n    }\n\n    /**\n     * Matches each element with a unique key that you extract from it.\n     * If the same key is present twice, the function will return None.\n     *\n     * also see [[ConsStream.groupBy]]\n     */\n    arrangeBy<K>(getKey: (v:T)=>K&WithEquality): Option<HashMap<K,T>> {\n        return SeqHelpers.arrangeBy<T,K>(this, getKey);\n    }\n\n    /**\n     * Randomly reorder the elements of the collection.\n     */\n    shuffle(): Stream<T> {\n        return Stream.ofIterable(SeqHelpers.shuffle(this.toArray()));\n    }\n\n    /**\n     * Append an element at the end of this Stream.\n     */\n    append(v:T): Stream<T> {\n        return Stream.of(v);\n    }\n\n    /*\n     * Append multiple elements at the end of this Stream.\n     */\n    appendAll(elts:Iterable<T>): Stream<T> {\n        return Stream.ofIterable(elts);\n    }\n\n    /**\n     * Remove multiple elements from a stream\n     *\n     *     Stream.of(1,2,3,4,3,2,1).removeAll([2,4])\n     *     => Stream.of(1,3,3,1)\n     */\n    removeAll(elts:Iterable<T&WithEquality>): Stream<T> {\n        return this;\n    }\n\n    /**\n     * Removes the first element matching the predicate\n     * (use [[ConsStream.filter]] to remove all elements matching a predicate)\n     */\n    removeFirst(predicate: (x:T)=>boolean): Stream<T> {\n        return this;\n    }\n\n    /*\n     * Append another Stream at the end of this Stream.\n     *\n     * There is no function taking a javascript iterator,\n     * because iterators are stateful and Streams lazy.\n     * If we would create two Streams working on the same iterator,\n     * the streams would interact with one another.\n     * It also breaks the cycle() function.\n     */\n    appendStream(elts:Stream<T>): Stream<T> {\n        return elts;\n    }\n\n    /**\n     * Prepend an element at the beginning of the collection.\n     */\n    prepend(elt: T): Stream<T> {\n        return Stream.of(elt);\n    }\n\n    /**\n     * Prepend multiple elements at the beginning of the collection.\n     */\n    prependAll(elt: Iterable<T>): Stream<T> {\n        return Stream.ofIterable(elt);\n    }\n\n    /**\n     * Repeat infinitely this Stream.\n     * For instance:\n     *\n     *     Stream.of(1,2,3).cycle().take(8)\n     *     => Stream.of(1,2,3,1,2,3,1,2)\n     */\n    cycle(): Stream<T> {\n        return <EmptyStream<T>>emptyStream;\n    }\n\n    /**\n     * Return a new collection where each element was transformed\n     * by the mapper function you give.\n     */\n    map<U>(mapper:(v:T)=>U): Stream<U> {\n        return <EmptyStream<U>>emptyStream;\n    }\n\n    /**\n     * Apply the mapper function on every element of this collection.\n     * The mapper function returns an Option; if the Option is a Some,\n     * the value it contains is added to the result Collection, if it's\n     * a None, the value is discarded.\n     *\n     *     Stream.of(1,2,6).mapOption(x => x%2===0 ?\n     *         Option.of(x+1) : Option.none<number>())\n     *     => Stream.of(3, 7)\n     */\n    mapOption<U>(mapper:(v:T)=>Option<U>): Stream<U> {\n        return <EmptyStream<U>>emptyStream;\n    }\n\n    /**\n     * Calls the function you give for each item in the collection,\n     * your function returns a collection, all the collections are\n     * concatenated.\n     * This is the monadic bind.\n     */\n    flatMap<U>(mapper:(v:T)=>Stream<U>): Stream<U> {\n        return <EmptyStream<U>>emptyStream;\n    }\n\n    /**\n     * Returns true if the predicate returns true for all the\n     * elements in the collection.\n     */\n    allMatch<U extends T>(predicate:(v:T)=>v is U): this is Stream<U>;\n    allMatch(predicate:(v:T)=>boolean): boolean;\n    allMatch(predicate:(v:T)=>boolean): boolean {\n        return true;\n    }\n\n    /**\n     * Returns true if there the predicate returns true for any\n     * element in the collection.\n     */\n    anyMatch(predicate:(v:T)=>boolean): boolean {\n        return false;\n    }\n\n    /**\n     * Call a predicate for each element in the collection,\n     * build a new collection holding only the elements\n     * for which the predicate returned true.\n     */\n    filter<U extends T>(predicate:(v:T)=>v is U): Stream<U>;\n    filter(predicate:(v:T)=>boolean): Stream<T>;\n    filter(predicate:(v:T)=>boolean): Stream<T> {\n        return this;\n    }\n\n    /**\n     * Returns a new collection with elements\n     * sorted according to the comparator you give.\n     *\n     *     const activityOrder = [\"Writer\", \"Actor\", \"Director\"];\n     *     Stream.of({name:\"George\", activity: \"Director\"}, {name:\"Robert\", activity: \"Actor\"})\n     *         .sortBy((p1,p2) => activityOrder.indexOf(p1.activity) - activityOrder.indexOf(p2.activity));\n     *     => Stream.of({\"name\":\"Robert\",\"activity\":\"Actor\"}, {\"name\":\"George\",\"activity\":\"Director\"})\n     *\n     * also see [[ConsStream.sortOn]]\n     */\n    sortBy(compare: (v1:T,v2:T)=>Ordering): Stream<T> {\n        return this;\n    }\n\n    /**\n     * Give a function associating a number or a string with\n     * elements from the collection, and the elements\n     * are sorted according to that value.\n     *\n     *     Stream.of({a:3,b:\"b\"},{a:1,b:\"test\"},{a:2,b:\"a\"}).sortOn(elt=>elt.a)\n     *     => Stream.of({a:1,b:\"test\"},{a:2,b:\"a\"},{a:3,b:\"b\"})\n     *\n     * You can also sort by multiple criteria, and request 'descending'\n     * sorting:\n     *\n     *     Stream.of({a:1,b:\"b\"},{a:1,b:\"test\"},{a:2,b:\"a\"}).sortOn(elt=>elt.a,{desc:elt=>elt.b})\n     *     => Stream.of({a:1,b:\"test\"},{a:1,b:\"b\"},{a:2,b:\"a\"})\n     *\n     * also see [[ConsStream.sortBy]]\n     */\n    sortOn(...getKeys: Array<ToOrderable<T>|{desc:ToOrderable<T>}>): Stream<T> {\n        return this;\n    }\n\n    /**\n     * Remove duplicate items; elements are mapped to keys, those\n     * get compared.\n     *\n     *     Stream.of(1,1,2,3,2,3,1).distinctBy(x => x);\n     *     => Stream.of(1,2,3)\n     */\n    distinctBy<U>(keyExtractor: (x:T)=>U&WithEquality): Stream<T> {\n        return this;\n    }\n\n    /**\n     * Call a function for element in the collection.\n     */\n    forEach(fn: (v:T)=>void): Stream<T> {\n        return this;\n    }\n\n    /**\n     * Reduces the collection to a single value by repeatedly\n     * calling the combine function.\n     * No starting value. The order in which the elements are\n     * passed to the combining function is undetermined.\n     */\n    reduce(combine: (v1:T,v2:T)=>T): Option<T> {\n        return SeqHelpers.reduce(this, combine);\n    }\n\n    /**\n     * Compare values in the collection and return the smallest element.\n     * Returns Option.none if the collection is empty.\n     *\n     * also see [[ConsStream.minOn]]\n     */\n    minBy(compare: (v1:T,v2:T)=>Ordering): Option<T> {\n        return Option.none<T>();\n    }\n\n    /**\n     * Call the function you give for each value in the collection\n     * and return the element for which the result was the smallest.\n     * Returns Option.none if the collection is empty.\n     *\n     *     Stream.of({name:\"Joe\", age:12}, {name:\"Paula\", age:6}).minOn(x=>x.age)\n     *     => Option.of({name:\"Paula\", age:6})\n     *\n     * also see [[ConsStream.minBy]]\n     */\n    minOn(getOrderable: ToOrderable<T>): Option<T> {\n        return Option.none<T>();\n    }\n\n    /**\n     * Compare values in the collection and return the largest element.\n     * Returns Option.none if the collection is empty.\n     *\n     * also see [[ConsStream.maxOn]]\n     */\n    maxBy(compare: (v1:T,v2:T)=>Ordering): Option<T> {\n        return Option.none<T>();\n    }\n\n    /**\n     * Call the function you give for each value in the collection\n     * and return the element for which the result was the largest.\n     * Returns Option.none if the collection is empty.\n     *\n     *     Stream.of({name:\"Joe\", age:12}, {name:\"Paula\", age:6}).maxOn(x=>x.age)\n     *     => Option.of({name:\"Joe\", age:12})\n     *\n     * also see [[ConsStream.maxBy]]\n     */\n    maxOn(getOrderable: ToOrderable<T>): Option<T> {\n        return Option.none<T>();\n    }\n\n    /**\n     * Call the function you give for each element in the collection\n     * and sum all the numbers, return that sum.\n     * Will return 0 if the collection is empty.\n     *\n     *     Stream.of(1,2,3).sumOn(x=>x)\n     *     => 6\n     */\n    sumOn(getNumber: (v:T)=>number): number {\n        return 0;\n    }\n\n    /**\n     * Slides a window of a specific size over the sequence.\n     * Returns a lazy stream so memory use is not prohibitive.\n     *\n     *     Stream.of(1,2,3,4,5,6,7,8).sliding(3)\n     *     => Stream.of(Stream.of(1,2,3), Stream.of(4,5,6), Stream.of(7,8))\n     */\n    sliding(count:number): Stream<Stream<T>> {\n        return <Stream<Stream<T>>>SeqHelpers.sliding(this, count);\n    }\n\n    /**\n     * Apply the function you give to all elements of the sequence\n     * in turn, keeping the intermediate results and returning them\n     * along with the final result in a list.\n     *\n     *     Stream.of(1,2,3).scanLeft(0, (soFar,cur)=>soFar+cur)\n     *     => Stream.of(0,1,3,6)\n     */\n    scanLeft<U>(init:U, fn:(soFar:U,cur:T)=>U): Stream<U> {\n        return new ConsStream(init, Lazy.of(()=><EmptyStream<U>>emptyStream));\n    }\n\n    /**\n     * Apply the function you give to all elements of the sequence\n     * in turn, keeping the intermediate results and returning them\n     * along with the final result in a list.\n     * The first element of the result is the final cumulative result.\n     *\n     *     Stream.of(1,2,3).scanRight(0, (cur,soFar)=>soFar+cur)\n     *     => Stream.of(6,5,3,0)\n     */\n    scanRight<U>(init:U, fn:(cur:T,soFar:U)=>U): Stream<U> {\n        return new ConsStream(init, Lazy.of(()=><EmptyStream<U>>emptyStream));\n    }\n\n    /**\n     * Joins elements of the collection by a separator.\n     * Example:\n     *\n     *     Vector.of(1,2,3).mkString(\", \")\n     *     => \"1, 2, 3\"\n     */\n    mkString(separator: string): string {\n        return \"\";\n    }\n\n    /**\n     * Convert to array.\n     * Don't do it on an infinite stream!\n     */\n    toArray(): T[] {\n        return [];\n    }\n\n    /**\n     * Convert to vector.\n     * Don't do it on an infinite stream!\n     */\n    toVector(): Vector<T> {\n        return Vector.empty<T>();\n    }\n\n    /**\n     * Convert this collection to a map. You give a function which\n     * for each element in the collection returns a pair. The\n     * key of the pair will be used as a key in the map, the value,\n     * as a value in the map. If several values get the same key,\n     * entries will be lost.\n     *\n     *     Stream.of(1,2,3).toMap(x=>[x.toString(), x])\n     *     => HashMap.of([\"1\",1], [\"2\",2], [\"3\",3])\n     */\n    toMap<K,V>(converter:(x:T)=>[K & WithEquality,V]): HashMap<K,V> {\n        return HashMap.empty<K,V>();\n    }\n\n    /**\n     * Convert this collection to a set. Since the elements of the\n     * Seq may not support equality, you must pass a function returning\n     * a value supporting equality.\n     *\n     *     Stream.of(1,2,3,3,4).toSet(x=>x)\n     *     => HashSet.of(1,2,3,4)\n     */\n    toSet<K>(converter:(x:T)=>K&WithEquality): HashSet<K> {\n        return HashSet.empty<K>();\n    }\n\n    /**\n     * Convert this collection to a list.\n     */\n    toLinkedList(): LinkedList<T> {\n        return LinkedList.ofIterable(this);\n    }\n\n    /**\n     * Transform this value to another value type.\n     * Enables fluent-style programming by chaining calls.\n     */\n    transform<U>(converter:(x:Stream<T>)=>U): U {\n        return converter(this);\n    }\n\n    /**\n     * Two objects are equal if they represent the same value,\n     * regardless of whether they are the same object physically\n     * in memory.\n     */\n    equals(other: Stream<T&WithEquality>): boolean {\n        if (!other) {\n            return false;\n        }\n        return other.isEmpty();\n    }\n\n    /**\n     * Get a number for that object. Two different values\n     * may get the same number, but one value must always get\n     * the same number. The formula can impact performance.\n     */\n    hashCode(): number {\n        return 1;\n    }\n\n    [inspect](): string {\n        return this.toString();\n    }\n\n    /**\n     * Get a human-friendly string representation of that value.\n     *\n     * Also see [[ConsStream.mkString]]\n     */\n    toString(): string {\n        return \"[]\";\n    }\n}\n\n/**\n * ConsStream holds a value and a lazy pointer to a next element,\n * which could be [[ConsStream]] or [[EmptyStream]].\n * A ConsStream is basically a non-empty stream. It will\n * contain at least one element.\n * \"static methods\" available through [[StreamStatic]]\n * @param T the item type\n */\nexport class ConsStream<T> implements Seq<T> {\n\n    /**\n     * @hidden\n     */\n    readonly className: \"ConsStream\" = <any>undefined;  // https://stackoverflow.com/a/47841595/516188\n\n    /**\n     * @hidden\n     */\n    public constructor(protected value: T, protected _tail: Lazy<Stream<T>>) {}\n\n    /**\n     * Implementation of the Iterator interface.\n     */\n    [Symbol.iterator](): Iterator<T> {\n        let item: Stream<T> = this;\n        return {\n            next(): IteratorResult<T> {\n                if (item.isEmpty()) {\n                    return { done: true, value: <any>undefined };\n                }\n                const value = item.head().get();\n                item = item.tail().get();\n                return {done: false, value};\n            }\n        };\n    }\n\n    /**\n     * View this Some a as Stream. Useful to help typescript type\n     * inference sometimes.\n     */\n    asStream(): Stream<T> {\n        return this;\n    }\n\n    /**\n     * @hidden\n     */\n    hasTrueEquality(): boolean {\n        return SeqHelpers.seqHasTrueEquality<T>(this);\n    }\n\n    /**\n     * Get the length of the collection.\n     */\n    length(): number {\n        return this.foldLeft(0, (n, ignored) => n + 1);\n    }\n\n    /**\n     * If the collection contains a single element,\n     * return Some of its value, otherwise return None.\n     */\n    single(): Option<T> {\n        return this._tail.get().isEmpty() ?\n            Option.of(this.value) :\n            Option.none<T>();\n    }\n\n    /**\n     * true if the collection is empty, false otherwise.\n     */\n    isEmpty(): this is EmptyStream<T> {\n        return false;\n    }\n\n    /**\n     * Get the first value of the collection, if any.\n     * returns Option.Some if the collection is not empty,\n     * Option.None if it's empty.\n     */\n    head(): Some<T> {\n        return Option.some(this.value);\n    }\n\n    /**\n     * Get all the elements in the collection but the first one.\n     * If the collection is empty, return None.\n     */\n    tail(): Some<Stream<T>> {\n        return Option.some(this._tail.get());\n    }\n\n    /**\n     * Get the last value of the collection, if any.\n     * returns Option.Some if the collection is not empty,\n     * Option.None if it's empty.\n     */\n    last(): Some<T> {\n        let curItem: Stream<T> = this;\n        while (true) {\n            const item = (<ConsStream<T>>curItem).value;\n            curItem = (<ConsStream<T>>curItem)._tail.get();\n            if (curItem.isEmpty()) {\n                return Option.some(item);\n            }\n        }\n    }\n\n    /**\n     * Retrieve the element at index idx.\n     * Returns an option because the collection may\n     * contain less elements than the index.\n     *\n     * Careful this is going to have poor performance\n     * on Stream, which is not a good data structure\n     * for random access!\n     */\n    get(idx: number): Option<T> {\n        let curItem: Stream<T> = this;\n        let i=0;\n        while (!curItem.isEmpty()) {\n            if (i === idx) {\n                const item = curItem.value;\n                return Option.of(item);\n            }\n            curItem = curItem._tail.get();\n            ++i;\n        }\n        return Option.none<T>();\n    }\n\n    /**\n     * Search for an item matching the predicate you pass,\n     * return Option.Some of that element if found,\n     * Option.None otherwise.\n     */\n    find(predicate:(v:T)=>boolean): Option<T> {\n        let curItem: Stream<T> = this;\n        while (!curItem.isEmpty()) {\n            const item = curItem.value;\n            if (predicate(item)) {\n                return Option.of(item);\n            }\n            curItem = curItem._tail.get();\n        }\n        return Option.none<T>();\n    }\n\n    /**\n     * Returns true if the item is in the collection,\n     * false otherwise.\n     */\n    contains(v:T&WithEquality): boolean {\n        return this.find(x => areEqual(x,v)).isSome();\n    }\n\n    /**\n     * Return a new stream keeping only the first n elements\n     * from this stream.\n     */\n    take(n: number): Stream<T> {\n        if (n < 1) {\n            return <EmptyStream<T>>emptyStream;\n        }\n        return new ConsStream(this.value,\n                              Lazy.of(() => this._tail.get().take(n-1)));\n    }\n\n    /**\n     * Returns a new collection, discarding the elements\n     * after the first element which fails the predicate.\n     */\n    takeWhile(predicate: (x:T)=>boolean): Stream<T> {\n        if (!predicate(this.value)) {\n            return <EmptyStream<T>>emptyStream;\n        }\n        return new ConsStream(this.value,\n                              Lazy.of(() => this._tail.get().takeWhile(predicate)));\n    }\n\n    /**\n     * Returns a new collection, discarding the elements\n     * after the first element which fails the predicate,\n     * but starting from the end of the collection.\n     *\n     *     Stream.of(1,2,3,4).takeRightWhile(x => x > 2)\n     *     => Stream.of(3,4)\n     */\n    takeRightWhile(predicate:(x:T)=>boolean): Stream<T> {\n        return this.reverse().takeWhile(predicate).reverse();\n    }\n\n    /**\n     * Returns a new collection with the first\n     * n elements discarded.\n     * If the collection has less than n elements,\n     * returns the empty collection.\n     */\n    drop(n:number): Stream<T> {\n        let i = n;\n        let curItem: Stream<T> = this;\n        while (i-- > 0 && !curItem.isEmpty()) {\n            curItem = curItem._tail.get();\n        }\n        return curItem;\n    }\n\n    /**\n     * Returns a new collection, discarding the first elements\n     * until one element fails the predicate. All elements\n     * after that point are retained.\n     */\n    dropWhile(predicate:(x:T)=>boolean): Stream<T> {\n        let curItem: Stream<T> = this;\n        while (!curItem.isEmpty() && predicate(curItem.value)) {\n            curItem = curItem._tail.get();\n        }\n        return curItem;\n    }\n\n    /**\n     * Returns a new collection with the last\n     * n elements discarded.\n     * If the collection has less than n elements,\n     * returns the empty collection.\n     */\n    dropRight(n:number): Stream<T> {\n        // going twice through the list...\n        const length = this.length();\n        return this.take(length-n);\n    }\n\n    /**\n     * Returns a new collection, discarding the last elements\n     * until one element fails the predicate. All elements\n     * before that point are retained.\n     */\n    dropRightWhile(predicate:(x:T)=>boolean): Stream<T> {\n        return this.reverse().dropWhile(predicate).reverse();\n    }\n\n    /**\n     * Reduces the collection to a single value using the\n     * associative binary function you give. Since the function\n     * is associative, order of application doesn't matter.\n     *\n     * Example:\n     *\n     *     Stream.of(1,2,3).fold(0, (a,b) => a + b);\n     *     => 6\n     */\n    fold(zero:T, fn:(v1:T,v2:T)=>T): T {\n        return this.foldLeft(zero, fn);\n    }\n\n    /**\n     * Reduces the collection to a single value.\n     * Left-associative.\n     *\n     * Example:\n     *\n     *     Vector.of(\"a\", \"b\", \"c\").foldLeft(\"!\", (xs,x) => x+xs);\n     *     => \"cba!\"\n     *\n     * @param zero The initial value\n     * @param fn A function taking the previous value and\n     *           the current collection item, and returning\n     *           an updated value.\n     */\n    foldLeft<U>(zero: U, fn:(soFar:U,cur:T)=>U): U {\n        let r = zero;\n        let curItem: Stream<T> = this;\n        while (!curItem.isEmpty()) {\n            r = fn(r, curItem.value);\n            curItem = curItem._tail.get();\n        }\n        return r;\n    }\n\n    /**\n     * Reduces the collection to a single value.\n     * Right-associative.\n     *\n     * Example:\n     *\n     *     Vector.of(\"a\", \"b\", \"c\").foldRight(\"!\", (x,xs) => xs+x);\n     *     => \"!cba\"\n     *\n     * @param zero The initial value\n     * @param fn A function taking the current collection item and\n     *           the previous value , and returning\n     *           an updated value.\n     */\n    foldRight<U>(zero: U, fn:(cur:T, soFar:U)=>U): U {\n        return this.reverse().foldLeft(zero, (xs,x)=>fn(x,xs));\n    }\n\n    /**\n     * Combine this collection with the collection you give in\n     * parameter to produce a new collection which combines both,\n     * in pairs. For instance:\n     *\n     *     Stream.of(1,2,3).zip([\"a\",\"b\",\"c\"])\n     *     => Stream.of([1,\"a\"], [2,\"b\"], [3,\"c\"])\n     *\n     * The result collection will have the length of the shorter\n     * of both collections. Extra elements will be discarded.\n     *\n     * Also see [[StreamStatic.zip]] (static version which can more than two\n     * iterables)\n     */\n    zip<U>(other: Iterable<U>): Stream<[T,U]> {\n        const otherIterator = other[Symbol.iterator]();\n        let otherCurItem = otherIterator.next();\n\n        if (this.isEmpty() || otherCurItem.done) {\n            return <EmptyStream<[T,U]>>emptyStream;\n        }\n\n        return new ConsStream([this.value, otherCurItem.value] as [T,U],\n                              Lazy.of(() => this._tail.get().zip(\n                                  { [Symbol.iterator]: ()=>otherIterator})));\n    }\n\n    /**\n     * Combine this collection with the index of the elements\n     * in it. Handy if you need the index when you map on\n     * the collection for instance:\n     *\n     *     Stream.of(\"a\",\"b\").zipWithIndex().map(([v,idx]) => v+idx);\n     *     => Stream.of(\"a0\", \"b1\")\n     */\n    zipWithIndex(): Stream<[T,number]> {\n        return <Stream<[T,number]>>SeqHelpers.zipWithIndex<T>(this);\n    }\n\n    /**\n     * Reverse the collection. For instance:\n     *\n     *     Stream.of(1,2,3).reverse();\n     *     => Stream.of(3,2,1)\n     */\n    reverse(): Stream<T> {\n        return this.foldLeft(<Stream<T>><EmptyStream<T>>emptyStream, (xs,x) => xs.prepend(x));\n    }\n\n    /**\n     * Takes a predicate; returns a pair of collections.\n     * The first one is the longest prefix of this collection\n     * which satisfies the predicate, and the second collection\n     * is the remainder of the collection.\n     *\n     *    Stream.of(1,2,3,4,5,6).span(x => x <3)\n     *    => [Stream.of(1,2), Stream.of(3,4,5,6)]\n     */\n    span(predicate:(x:T)=>boolean): [Stream<T>,Stream<T>] {\n        return [this.takeWhile(predicate), this.dropWhile(predicate)];\n    }\n\n    /**\n     * Split the collection at a specific index.\n     *\n     *     Stream.of(1,2,3,4,5).splitAt(3)\n     *     => [Stream.of(1,2,3), Stream.of(4,5)]\n     */\n    splitAt(index:number): [Stream<T>,Stream<T>] {\n        return [this.take(index), this.drop(index)];\n    }\n\n    /**\n     * Returns a pair of two collections; the first one\n     * will only contain the items from this collection for\n     * which the predicate you give returns true, the second\n     * will only contain the items from this collection where\n     * the predicate returns false.\n     *\n     *     Stream.of(1,2,3,4).partition(x => x%2===0)\n     *     => [Stream.of(2,4),Stream.of(1,3)]\n     */\n    partition<U extends T>(predicate:(v:T)=>v is U): [Stream<U>,Stream<Exclude<T,U>>];\n    partition(predicate:(x:T)=>boolean): [Stream<T>,Stream<T>];\n    partition(predicate:(v:T)=>boolean): [Stream<T>,Stream<T>] {\n        // goes twice over the list, but since we want a lazy behavior...\n        return [this.filter(predicate), this.filter(x => !predicate(x))];\n    }\n\n    /**\n     * Group elements in the collection using a classifier function.\n     * Elements are then organized in a map. The key is the value of\n     * the classifier, and in value we get the list of elements\n     * matching that value.\n     *\n     * also see [[ConsStream.arrangeBy]]\n     */\n    groupBy<C>(classifier: (v:T)=>C & WithEquality): HashMap<C,Stream<T>> {\n        return this.foldLeft(\n            HashMap.empty<C,Stream<T>>(),\n            (acc: HashMap<C,Stream<T>>, v:T) =>\n                acc.putWithMerge(\n                    classifier(v), Stream.of(v),\n                    (v1:Stream<T>,v2:Stream<T>)=>v1.appendStream(v2)));\n    }\n\n    /**\n     * Matches each element with a unique key that you extract from it.\n     * If the same key is present twice, the function will return None.\n     *\n     * also see [[ConsStream.groupBy]]\n     */\n    arrangeBy<K>(getKey: (v:T)=>K&WithEquality): Option<HashMap<K,T>> {\n        return SeqHelpers.arrangeBy<T,K>(this, getKey);\n    }\n\n    /**\n     * Randomly reorder the elements of the collection.\n     */\n    shuffle(): Stream<T> {\n        return Stream.ofIterable(SeqHelpers.shuffle(this.toArray()));\n    }\n\n    /**\n     * Append an element at the end of this Stream.\n     */\n    append(v:T): Stream<T> {\n        const tail = this._tail.get();\n        return new ConsStream(\n            this.value,\n            Lazy.of(()=>tail.append(v)));\n    }\n\n    /*\n     * Append multiple elements at the end of this Stream.\n     */\n    appendAll(elts:Iterable<T>): Stream<T> {\n        return this.appendStream(Stream.ofIterable(elts));\n    }\n\n    /**\n     * Remove multiple elements from a stream\n     *\n     *     Stream.of(1,2,3,4,3,2,1).removeAll([2,4])\n     *     => Stream.of(1,3,3,1)\n     */\n    removeAll(elts:Iterable<T&WithEquality>): Stream<T> {\n        return <Stream<T>><any>SeqHelpers.removeAll(this, elts);\n    }\n\n    /**\n     * Removes the first element matching the predicate\n     * (use [[ConsStream.filter]] to remove all elements matching a predicate)\n     */\n    removeFirst(predicate: (x:T)=>boolean): Stream<T> {\n        const tail = this._tail.get();\n        return predicate(this.value) ?\n            tail :\n            new ConsStream(this.value,\n                           Lazy.of(()=>tail.removeFirst(predicate)));\n    }\n\n    /*\n     * Append another Stream at the end of this Stream.\n     *\n     * There is no function taking a javascript iterator,\n     * because iterators are stateful and Streams lazy.\n     * If we would create two Streams working on the same iterator,\n     * the streams would interact with one another.\n     * It also breaks the cycle() function.\n     */\n    appendStream(elts:Stream<T>): Stream<T> {\n        const tail = this._tail.get();\n        return new ConsStream(\n            this.value,\n            Lazy.of(() => tail.appendStream(elts)));\n    }\n\n    /**\n     * Prepend an element at the beginning of the collection.\n     */\n    prepend(elt: T): Stream<T> {\n        return new ConsStream(\n            elt,\n            Lazy.of(()=>this));\n    }\n\n    /**\n     * Prepend multiple elements at the beginning of the collection.\n     */\n    prependAll(elts: Iterable<T>): Stream<T> {\n        return Stream.ofIterable(elts).appendAll(this);\n    }\n\n    /**\n     * Repeat infinitely this Stream.\n     * For instance:\n     *\n     *     Stream.of(1,2,3).cycle().take(8)\n     *     => Stream.of(1,2,3,1,2,3,1,2)\n     */\n    cycle(): Stream<T> {\n        return this._cycle(this);\n    }\n\n    private _cycle(toRepeat: Stream<T>): Stream<T> {\n        const tail = this._tail.get();\n        return new ConsStream(\n            this.value,\n            Lazy.of(() => tail.isEmpty() ? toRepeat.cycle() : tail._cycle(toRepeat)));\n    }\n\n    /**\n     * Return a new collection where each element was transformed\n     * by the mapper function you give.\n     */\n    map<U>(mapper:(v:T)=>U): Stream<U> {\n        return new ConsStream(mapper(this.value),\n                              Lazy.of(() => this._tail.get().map(mapper)));\n    }\n\n    /**\n     * Apply the mapper function on every element of this collection.\n     * The mapper function returns an Option; if the Option is a Some,\n     * the value it contains is added to the result Collection, if it's\n     * a None, the value is discarded.\n     *\n     *     Stream.of(1,2,6).mapOption(x => x%2===0 ?\n     *         Option.of(x+1) : Option.none<number>())\n     *     => Stream.of(3, 7)\n     */\n    mapOption<U>(mapper:(v:T)=>Option<U>): Stream<U> {\n        const mapped = mapper(this.value);\n        return mapped.isSome() ?\n            new ConsStream(mapped.get(),\n                           Lazy.of(() => this._tail.get().mapOption(mapper))) :\n            this._tail.get().mapOption(mapper);\n    }\n\n    /**\n     * Calls the function you give for each item in the collection,\n     * your function returns a collection, all the collections are\n     * concatenated.\n     * This is the monadic bind.\n     */\n    flatMap<U>(mapper:(v:T)=>Stream<U>): Stream<U> {\n        return mapper(this.value).appendStream(\n            this._tail.get().flatMap(mapper));\n    }\n\n    /**\n     * Returns true if the predicate returns true for all the\n     * elements in the collection.\n     */\n    allMatch<U extends T>(predicate:(v:T)=>v is U): this is Stream<U>;\n    allMatch(predicate:(v:T)=>boolean): boolean;\n    allMatch(predicate:(v:T)=>boolean): boolean {\n        return this.find(x => !predicate(x)).isNone();\n    }\n\n    /**\n     * Returns true if there the predicate returns true for any\n     * element in the collection.\n     */\n    anyMatch(predicate:(v:T)=>boolean): boolean {\n        return this.find(predicate).isSome();\n    }\n\n    /**\n     * Call a predicate for each element in the collection,\n     * build a new collection holding only the elements\n     * for which the predicate returned true.\n     */\n    filter<U extends T>(predicate:(v:T)=>v is U): Stream<U>;\n    filter(predicate:(v:T)=>boolean): Stream<T>;\n    filter(predicate:(v:T)=>boolean): Stream<T> {\n        return predicate(this.value) ?\n            new ConsStream(this.value,\n                           Lazy.of(() => this._tail.get().filter(predicate))) :\n            this._tail.get().filter(predicate);\n    }\n\n    /**\n     * Returns a new collection with elements\n     * sorted according to the comparator you give.\n     *\n     *     const activityOrder = [\"Writer\", \"Actor\", \"Director\"];\n     *     Stream.of({name:\"George\", activity: \"Director\"}, {name:\"Robert\", activity: \"Actor\"})\n     *         .sortBy((p1,p2) => activityOrder.indexOf(p1.activity) - activityOrder.indexOf(p2.activity));\n     *     => Stream.of({\"name\":\"Robert\",\"activity\":\"Actor\"}, {\"name\":\"George\",\"activity\":\"Director\"})\n     *\n     * also see [[ConsStream.sortOn]]\n     */\n    sortBy(compare: (v1:T,v2:T)=>Ordering): Stream<T> {\n        return Stream.ofIterable<T>(this.toArray().sort(compare));\n    }\n\n    /**\n     * Give a function associating a number or a string with\n     * elements from the collection, and the elements\n     * are sorted according to that value.\n     *\n     *     Stream.of({a:3,b:\"b\"},{a:1,b:\"test\"},{a:2,b:\"a\"}).sortOn(elt=>elt.a)\n     *     => Stream.of({a:1,b:\"test\"},{a:2,b:\"a\"},{a:3,b:\"b\"})\n     *\n     * You can also sort by multiple criteria, and request 'descending'\n     * sorting:\n     *\n     *     Stream.of({a:1,b:\"b\"},{a:1,b:\"test\"},{a:2,b:\"a\"}).sortOn(elt=>elt.a,{desc:elt=>elt.b})\n     *     => Stream.of({a:1,b:\"test\"},{a:1,b:\"b\"},{a:2,b:\"a\"})\n     *\n     * also see [[ConsStream.sortBy]]\n     */\n    sortOn(...getKeys: Array<ToOrderable<T>|{desc:ToOrderable<T>}>): Stream<T> {\n        return <Stream<T>>SeqHelpers.sortOn<T>(this, getKeys);\n    }\n\n    /**\n     * Remove duplicate items; elements are mapped to keys, those\n     * get compared.\n     *\n     *     Stream.of(1,1,2,3,2,3,1).distinctBy(x => x);\n     *     => Stream.of(1,2,3)\n     */\n    distinctBy<U>(keyExtractor: (x:T)=>U&WithEquality): Stream<T> {\n        return <Stream<T>>SeqHelpers.distinctBy(this, keyExtractor);\n    }\n\n    /**\n     * Call a function for element in the collection.\n     */\n    forEach(fn: (v:T)=>void): Stream<T> {\n        let curItem: Stream<T> = this;\n        while (!curItem.isEmpty()) {\n            fn(curItem.value);\n            curItem = curItem._tail.get();\n        }\n        return this;\n    }\n\n    /**\n     * Reduces the collection to a single value by repeatedly\n     * calling the combine function.\n     * No starting value. The order in which the elements are\n     * passed to the combining function is undetermined.\n     */\n    reduce(combine: (v1:T,v2:T)=>T): Option<T> {\n        return SeqHelpers.reduce(this, combine);\n    }\n\n    /**\n     * Compare values in the collection and return the smallest element.\n     * Returns Option.none if the collection is empty.\n     *\n     * also see [[ConsStream.minOn]]\n     */\n    minBy(compare: (v1:T,v2:T)=>Ordering): Option<T> {\n        return SeqHelpers.minBy(this, compare);\n    }\n\n    /**\n     * Call the function you give for each value in the collection\n     * and return the element for which the result was the smallest.\n     * Returns Option.none if the collection is empty.\n     *\n     *     Stream.of({name:\"Joe\", age:12}, {name:\"Paula\", age:6}).minOn(x=>x.age)\n     *     => Option.of({name:\"Paula\", age:6})\n     *\n     * also see [[ConsStream.minBy]]\n     */\n    minOn(getOrderable: ToOrderable<T>): Option<T> {\n        return SeqHelpers.minOn(this, getOrderable);\n    }\n\n    /**\n     * Compare values in the collection and return the largest element.\n     * Returns Option.none if the collection is empty.\n     *\n     * also see [[ConsStream.maxOn]]\n     */\n    maxBy(compare: (v1:T,v2:T)=>Ordering): Option<T> {\n        return SeqHelpers.maxBy(this, compare);\n    }\n\n    /**\n     * Call the function you give for each value in the collection\n     * and return the element for which the result was the largest.\n     * Returns Option.none if the collection is empty.\n     *\n     *     Stream.of({name:\"Joe\", age:12}, {name:\"Paula\", age:6}).maxOn(x=>x.age)\n     *     => Option.of({name:\"Joe\", age:12})\n     *\n     * also see [[ConsStream.maxBy]]\n     */\n    maxOn(getOrderable: ToOrderable<T>): Option<T> {\n        return SeqHelpers.maxOn(this, getOrderable);\n    }\n\n    /**\n     * Call the function you give for each element in the collection\n     * and sum all the numbers, return that sum.\n     * Will return 0 if the collection is empty.\n     *\n     *     Stream.of(1,2,3).sumOn(x=>x)\n     *     => 6\n     */\n    sumOn(getNumber: (v:T)=>number): number {\n        return SeqHelpers.sumOn(this, getNumber);\n    }\n\n    /**\n     * Slides a window of a specific size over the sequence.\n     * Returns a lazy stream so memory use is not prohibitive.\n     *\n     *     Stream.of(1,2,3,4,5,6,7,8).sliding(3)\n     *     => Stream.of(Stream.of(1,2,3), Stream.of(4,5,6), Stream.of(7,8))\n     */\n    sliding(count:number): Stream<Stream<T>> {\n        return <Stream<Stream<T>>>SeqHelpers.sliding(this, count);\n    }\n\n    /**\n     * Apply the function you give to all elements of the sequence\n     * in turn, keeping the intermediate results and returning them\n     * along with the final result in a list.\n     *\n     *     Stream.of(1,2,3).scanLeft(0, (soFar,cur)=>soFar+cur)\n     *     => Stream.of(0,1,3,6)\n     */\n    scanLeft<U>(init:U, fn:(soFar:U,cur:T)=>U): Stream<U> {\n        return new ConsStream(\n            init,\n            Lazy.of(()=>this._tail.get().scanLeft(fn(init, this.value), fn)));\n    }\n\n    /**\n     * Apply the function you give to all elements of the sequence\n     * in turn, keeping the intermediate results and returning them\n     * along with the final result in a list.\n     * The first element of the result is the final cumulative result.\n     *\n     *     Stream.of(1,2,3).scanRight(0, (cur,soFar)=>soFar+cur)\n     *     => Stream.of(6,5,3,0)\n     */\n    scanRight<U>(init:U, fn:(cur:T,soFar:U)=>U): Stream<U> {\n        // can't be lazy\n        const fn2 = (x:U,y:T)=>fn(y,x);\n        return this.reverse().scanLeft(init, fn2).reverse();\n    }\n\n    /**\n     * Joins elements of the collection by a separator.\n     * Example:\n     *\n     *     Vector.of(1,2,3).mkString(\", \")\n     *     => \"1, 2, 3\"\n     */\n    mkString(separator: string): string {\n        let r = \"\";\n        let curItem: Stream<T> = this;\n        let isNotFirst = false;\n        while (!curItem.isEmpty()) {\n            if (isNotFirst) {\n                r += separator;\n            }\n            r += SeqHelpers.toStringHelper(curItem.value, {quoteStrings:false});\n            curItem = curItem._tail.get();\n            isNotFirst = true;\n        }\n        return r;\n    }\n\n    /**\n     * Convert to array.\n     * Don't do it on an infinite stream!\n     */\n    toArray(): T[] {\n        let r:T[] = [];\n        let curItem: Stream<T> = this;\n        while (!curItem.isEmpty()) {\n            r.push(curItem.value);\n            curItem = curItem._tail.get();\n        }\n        return r;\n    }\n\n    /**\n     * Convert to vector.\n     * Don't do it on an infinite stream!\n     */\n    toVector(): Vector<T> {\n        return Vector.ofIterable<T>(this.toArray());\n    }\n\n    /**\n     * Convert this collection to a map. You give a function which\n     * for each element in the collection returns a pair. The\n     * key of the pair will be used as a key in the map, the value,\n     * as a value in the map. If several values get the same key,\n     * entries will be lost.\n     *\n     *     Stream.of(1,2,3).toMap(x=>[x.toString(), x])\n     *     => HashMap.of([\"1\",1], [\"2\",2], [\"3\",3])\n     */\n    toMap<K,V>(converter:(x:T)=>[K & WithEquality,V]): HashMap<K,V> {\n        return this.foldLeft(HashMap.empty<K,V>(), (acc,cur) => {\n            const converted = converter(cur);\n            return acc.put(converted[0], converted[1]);\n        });\n    }\n\n    /**\n     * Convert this collection to a set. Since the elements of the\n     * Seq may not support equality, you must pass a function returning\n     * a value supporting equality.\n     *\n     *     Stream.of(1,2,3,3,4).toSet(x=>x)\n     *     => HashSet.of(1,2,3,4)\n     */\n    toSet<K>(converter:(x:T)=>K&WithEquality): HashSet<K> {\n        return this.foldLeft(HashSet.empty<K>(), (acc,cur) => {\n            return acc.add(converter(cur));\n        });\n    }\n\n    /**\n     * Convert this collection to a list.\n     */\n    toLinkedList(): LinkedList<T> {\n        return LinkedList.ofIterable(this);\n    }\n\n    /**\n     * Transform this value to another value type.\n     * Enables fluent-style programming by chaining calls.\n     */\n    transform<U>(converter:(x:Stream<T>)=>U): U {\n        return converter(this);\n    }\n\n    /**\n     * Two objects are equal if they represent the same value,\n     * regardless of whether they are the same object physically\n     * in memory.\n     */\n    equals(other: Stream<T&WithEquality>): boolean {\n        if (<any>other === this) {\n            return true;\n        }\n        if (!other || !other.tail) {\n            return false;\n        }\n        contractTrueEquality(\"Stream.equals\", this, other);\n        let myVal: Stream<T> = this;\n        let hisVal = other;\n        while (true) {\n            if (myVal.isEmpty() !== hisVal.isEmpty()) {\n                return false;\n            }\n            if (myVal.isEmpty()) {\n                // they are both empty, end of the stream\n                return true;\n            }\n            const myHead = myVal.value;\n            const hisHead = (<ConsStream<T>>hisVal).value;\n\n            if ((myHead === undefined) !== (hisHead === undefined)) {\n                return false;\n            }\n            if (myHead === undefined || hisHead === undefined) {\n                // they are both undefined, the || is for TS's flow analysis\n                // so he realizes none of them is undefined after this.\n                continue;\n            }\n            if (!areEqual(myHead, hisHead)) {\n                return false;\n            }\n            myVal = myVal._tail.get();\n            hisVal = (<ConsStream<T&WithEquality>>hisVal)._tail.get();\n        }\n    }\n\n    /**\n     * Get a number for that object. Two different values\n     * may get the same number, but one value must always get\n     * the same number. The formula can impact performance.\n     */\n    hashCode(): number {\n        let hash = 1;\n        let curItem: Stream<T> = this;\n        while (!curItem.isEmpty()) {\n            hash = 31 * hash + getHashCode(curItem.value);\n            curItem = curItem._tail.get();\n        }\n        return hash;\n    }\n\n    [inspect](): string {\n        return this.toString();\n    }\n\n    /**\n     * Get a human-friendly string representation of that value.\n     *\n     * Also see [[ConsStream.mkString]]\n     */\n    toString(): string {\n        let curItem: Stream<T> = this;\n        let result = \"Stream(\";\n\n        while (!curItem.isEmpty()) {\n            result += SeqHelpers.toStringHelper(curItem.value);\n            const tail: Lazy<Stream<T>> = curItem._tail;\n            if (!tail.isEvaluated()) {\n                result += \", ?\";\n                break;\n            }\n            curItem = tail.get();\n            if (!curItem.isEmpty()) {\n                result += \", \";\n            }\n        }\n\n        return result + \")\";\n    }\n}\n\nconst emptyStream = new EmptyStream<any>();\n"
  },
  {
    "path": "src/Tuple2.ts",
    "content": "import { Value, inspect } from \"./Value\";\nimport { Option } from \"./Option\";\nimport { Vector } from \"./Vector\";\nimport { LinkedList, ConsLinkedList } from \"./LinkedList\";\nimport { WithEquality, areEqual, getHashCode } from \"./Comparison\";\nimport { toStringHelper } from \"./SeqHelpers\";\nimport { contractTrueEquality } from \"./Contract\";\n\n/**\n * Contains a pair of two values, which may or may not have the same type.\n * Compared to the builtin typescript [T,U] type, we get equality semantics\n * and helper functions (like mapping and so on).\n * @param T the first item type\n * @param U the second item type\n */\nexport class Tuple2<T,U> implements Value {\n\n    private constructor(private _fst: T,\n                        private _snd: U) {}\n\n    /**\n     * Build a pair of value from both values.\n     */\n    static of<T,U>(fst: T, snd: U) {\n        return new Tuple2(fst,snd);\n    }\n\n    /**\n     * Build a tuple2 from javascript array. Compared to [[Tuple2.ofPair]],\n     * it checks the length of the array and will return [[None]] in case\n     * the length isn't two. However the types of the elements aren't checked.\n     */\n    static ofArray<T,U>(pair: Array<T|U>): Option<Tuple2<T,U>> {\n        if (pair && pair.length === 2) {\n            return Option.of(new Tuple2<T,U>(<T>pair[0], <U>pair[1]));\n        }\n        return Option.none<Tuple2<T,U>>();\n    }\n\n    /**\n     * Build a tuple2 from javascript pair.\n     * Also see [[Tuple2.ofArray]]\n     */\n    static ofPair<T,U>(pair: [T, U]): Tuple2<T,U> {\n        return new Tuple2(pair[0], pair[1]);\n    }\n\n    /**\n     * @hidden\n     */\n    hasTrueEquality(): boolean {\n        return Option.of(this.fst()).hasTrueEquality() &&\n            Option.of(this.snd()).hasTrueEquality();\n    }\n\n    /**\n     * Extract the first value from the pair\n     */\n    fst(): T {\n        return this._fst;\n    }\n\n    /**\n     * Extract the second value from the pair\n     */\n    snd(): U {\n        return this._snd;\n    }\n\n    /**\n     * Maps the first component of this tuple to a new value.\n     */\n    map1<V>(fn: (v:T)=>V): Tuple2<V,U> {\n        return new Tuple2(fn(this._fst), this._snd);\n    }\n\n    /**\n     * Maps the second component of this tuple to a new value.\n     */\n    map2<V>(fn: (v:U)=>V): Tuple2<T,V> {\n        return new Tuple2(this._fst, fn(this._snd));\n    }\n\n    /**\n     * Make a new tuple by mapping both values inside this one.\n     */\n    map<T1,U1>(fn: (a:T,b:U)=> Tuple2<T1,U1>): Tuple2<T1,U1> {\n        return fn(this._fst, this._snd);\n    }\n\n    /**\n     * Transform this value to another value type.\n     * Enables fluent-style programming by chaining calls.\n     */\n    transform<V>(converter:(x:Tuple2<T,U>)=>V): V {\n        return converter(this);\n    }\n\n    /**\n     * Two objects are equal if they represent the same value,\n     * regardless of whether they are the same object physically\n     * in memory.\n     */\n    equals(other: Tuple2<T&WithEquality,U&WithEquality>): boolean {\n        if (<any>other === this) {\n            return true;\n        }\n        if (!other || other._fst === undefined) {\n            return false;\n        }\n        contractTrueEquality(\"Tuple2.equals\", this, other);\n        return areEqual(this._fst, other._fst) &&\n            areEqual(this._snd, other._snd);\n    }\n\n    /**\n     * Get a number for that object. Two different values\n     * may get the same number, but one value must always get\n     * the same number. The formula can impact performance.\n     */\n    hashCode(): number {\n        return getHashCode(this._fst)*53 + getHashCode(this._snd);\n    }\n\n    /**\n     * Convert the tuple to a javascript pair.\n     * Compared to [[Tuple2.toArray]], it behaves the\n     * same at runtime, the only difference is the\n     * typescript type definition.\n     */\n    toPair(): [T,U] {\n        return [this._fst, this._snd];\n    }\n\n    /**\n     * Convert the tuple to a javascript array.\n     * Compared to [[Tuple2.toPair]], it behaves the\n     * same at runtime, the only difference is the\n     * typescript type definition.\n     */\n    toArray(): Array<T|U> {\n        return [this._fst, this._snd];\n    }\n\n    /**\n     * Convert the tuple to a vector.\n     */\n    toVector(): Vector<T|U> {\n        return Vector.of<T|U>(this._fst, this._snd);\n    }\n\n    /**\n     * Convert the tuple to a linked list.\n     */\n    toLinkedList(): ConsLinkedList<T|U> {\n        return LinkedList.of<T|U>(this._fst, this._snd);\n    }\n\n    /**\n     * Get a human-friendly string representation of that value.\n     */\n    toString(): string {\n        return `Tuple2(${toStringHelper(this._fst)}, ${toStringHelper(this._snd)})`;\n    }\n\n    /**\n     * Used by the node REPL to display values.\n     * Most of the time should be the same as toString()\n     */\n    [inspect](): string {\n        return this.toString();\n    }\n}\n"
  },
  {
    "path": "src/Value.ts",
    "content": "import { WithEquality } from \"./Comparison\";\n\nimport * as util from 'util';\n\n/**\n * @hidden\n */\nexport const inspect = Symbol.for(\"nodejs.util.inspect.custom\");\n\nexport interface Value {\n\n    /**\n     * Two objects are equal if they represent the same value,\n     * regardless of whether they are the same object physically\n     * in memory.\n     */\n    equals(other: any&WithEquality /*TODO*/): boolean; // I experimented with 'this' for the other type but had issues with interfaces\n\n    /**\n     * Get a number for that object. Two different values\n     * may get the same number, but one value must always get\n     * the same number. The formula can impact performance.\n     */\n    hashCode(): number;\n\n    /**\n     * Get a human-friendly string representation of that value.\n     */\n    toString(): string;\n\n    /**\n     * Used by the node REPL to display values.\n     * Most of the time should be the same as toString()\n     */\n    [inspect](): string;\n}\n"
  },
  {
    "path": "src/Vector.ts",
    "content": "import { inspect } from './Value';\nimport { Option } from \"./Option\";\nimport { HashMap } from \"./HashMap\";\nimport { HashSet } from \"./HashSet\";\nimport { Stream } from \"./Stream\";\nimport { Seq, IterableArray } from \"./Seq\";\nimport { WithEquality, areEqual, getHashCode,\n         Ordering, ToOrderable } from \"./Comparison\";\nimport * as SeqHelpers from \"./SeqHelpers\";\nimport * as L from \"list\";\n\n/**\n * A general-purpose list class with all-around good performance.\n * quasi-O(1) (actually O(log32(n))) access, append, replace.\n * It's backed by a bit-mapped vector trie.\n * @param T the item type\n */\nexport class Vector<T> implements Seq<T> {\n\n    /**\n     * @hidden\n     */\n    // _contents will be undefined only if length===0\n    protected constructor(private _list: L.List<T>) {}\n\n    /**\n     * The empty vector.\n     * @param T the item type\n     */\n    static empty<T>(): Vector<T> {\n        return new Vector(L.empty());\n    }\n\n    /**\n     * Build a vector from a series of items (any number, as parameters)\n     * @param T the item type\n     */\n    static of<T>(...data: T[]): Vector<T> {\n        return Vector.ofIterable(data);\n    }\n\n    /**\n     * Build a vector from any iterable, which means also\n     * an array for instance.\n     * @param T the item type\n     */\n    static ofIterable<T>(elts: Iterable<T>): Vector<T> {\n        return new Vector(L.from(elts));\n    }\n\n    /**\n     * Curried predicate to find out whether the vector is empty.\n     *\n     *     LinkedList.of(Vector.of(1), Vector.empty<number>())\n     *         .filter(Vector.isEmpty)\n     *     => LinkedList.of(Vector.empty<number>())\n     */\n    static isEmpty<T>(v: Vector<T>): boolean {\n        return v.isEmpty();\n    }\n\n    /**\n     * Curried predicate to find out whether the vector is empty.\n     *\n     *     LinkedList.of(Vector.of(1), Vector.empty<number>())\n     *         .filter(Vector.isNotEmpty)\n     *     => LinkedList.of(Vector.of(1))\n     */\n    static isNotEmpty<T>(v: Vector<T>): boolean {\n        return !v.isEmpty();\n    }\n\n    /**\n     * Get the length of the collection.\n     */\n    length(): number {\n        return L.length(this._list);\n    }\n\n    /**\n     * true if the collection is empty, false otherwise.\n     */\n    isEmpty(): boolean {\n        return L.length(this._list) === 0;\n    }\n\n    /**\n     * Dual to the foldRight function. Build a collection from a seed.\n     * Takes a starting element and a function.\n     * It applies the function on the starting element; if the\n     * function returns None, it stops building the list, if it\n     * returns Some of a pair, it adds the first element to the result\n     * and takes the second element as a seed to keep going.\n     *\n     *     Vector.unfoldRight(\n     *          10, x=>Option.of(x)\n     *              .filter(x => x!==0)\n     *              .map<[number,number]>(x => [x,x-1]))\n     *     => Vector.of(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)\n     */\n    static unfoldRight<T,U>(seed: T, fn: (x:T)=>Option<[U,T]>): Vector<U> {\n        let nextVal = fn(seed);\n        let r = L.empty();\n        while (nextVal.isSome()) {\n            r = L.append(nextVal.get()[0], r);\n            nextVal = fn(nextVal.get()[1]);\n        }\n        return new Vector(r);\n    }\n\n    /**\n     * Retrieve the element at index idx.\n     * Returns an option because the collection may\n     * contain less elements than the index.\n     */\n    get(index: number): Option<T> {\n        return Option.of(L.nth(index, this._list));\n    }\n\n    /**\n     * If the collection contains a single element,\n     * return Some of its value, otherwise return None.\n     */\n    single(): Option<T> {\n        return L.length(this._list) === 1 ?\n            this.head() :\n            Option.none<T>();\n    }\n\n    /**\n     * Replace the value of element at the index you give.\n     * Will throw if the index is out of bounds!\n     */\n    replace(index: number, val: T): Vector<T> {\n        if (index >= this.length() || index < 0) {\n            throw new Error('Vector.replace: index is out of range: ' + index);\n        }\n        return new Vector(L.update(index, val, this._list));\n    }\n\n    /**\n     * Replace the first occurence (if any) of the element you give by\n     * the new value you give.\n     *\n     *     Vector.of(1, 2, 3, 4, 2).replaceFirst(2, 5)\n     *     => Vector.of(1, 5, 3, 4, 2)\n     * \n     */\n    replaceFirst(element: T&WithEquality, newVal: T&WithEquality): Vector<T> {\n        // it's a little annoying that areEqual will check whether the element\n        // has an equals function for each element in the list, but then\n        // what if the list allows null or undefined and the newVal is null or\n        // undefined? With type erasure then I don't know what equality to use\n        // on the next elements\n        const index = L.findIndex(v => areEqual(v, element), this._list);\n        return (index >= 0)\n            ? new Vector(L.update(index, newVal, this._list))\n            : this;\n    }\n\n    /**\n     * Replace all occurences of the element you give by\n     * the new value you give.\n     *\n     *     Vector.of(1, 2, 3, 4, 2).replaceAll(2, 5)\n     *     => Vector.of(1, 5, 3, 4, 5)\n     *\n     */\n    replaceAll(element: T&WithEquality, newVal: T&WithEquality): Vector<T> {\n        // if we're going to update many elements, then append in a loop\n        // would give better perf (not copying multiple times the same slice).\n        // if we won't update that many, update in a loop would give better perf...\n        // assuming it's the latter case.\n        let idx = 0;\n        return this.foldLeft(\n            this as Vector<T>,\n            (sofar, cur) => {\n                const r = areEqual(cur, element)\n                    ? new Vector(L.update(idx, newVal, sofar._list))\n                    : sofar;\n                ++idx;\n                return r;\n            });\n    }\n\n    /**\n     * Append an element at the end of the collection.\n     */\n    append(val:T): Vector<T> {\n        return new Vector(L.append(val, this._list));\n    }\n\n    /**\n     * Append multiple elements at the end of the collection.\n     * Note that arrays are also iterables.\n     */\n    appendAll(elts: Iterable<T>): Vector<T> {\n        if ((<any>elts)._list && (<any>elts).replace) {\n            // elts is a vector too\n            return new Vector(L.concat(this._list, (<Vector<T>>elts)._list));\n        }\n        return new Vector(L.concat(this._list, L.from(elts)));\n    }\n\n    /**\n     * Remove multiple elements from a vector\n     *\n     *     Vector.of(1,2,3,4,3,2,1).removeAll([2,4])\n     *     => Vector.of(1,3,3,1)\n     */\n    removeAll(elts:Iterable<T&WithEquality>): Vector<T> {\n        return <Vector<T>><any>SeqHelpers.removeAll(this, elts);\n    }\n\n    /**\n     * Get the first value of the collection, if any.\n     * returns Option.Some if the collection is not empty,\n     * Option.None if it's empty.\n     */\n    head(): Option<T> {\n        return this.get(0);\n    }\n\n    /**\n     * Get the last value of the collection, if any.\n     * returns Option.Some if the collection is not empty,\n     * Option.None if it's empty.\n     */\n    last(): Option<T> {\n        return Option.of(L.last(this._list));\n    }\n\n    /**\n     * Return a new vector containing all the elements in this\n     * vector except the last one, or the empty vector if this\n     * is the empty vector.\n     *\n     *     Vector.of(1,2,3).init()\n     *     => Vector.of(1,2)\n     */\n    init(): Vector<T> {\n        return new Vector(L.pop(this._list));\n    }\n\n    /**\n     * Returns a new collection, discarding the first elements\n     * until one element fails the predicate. All elements\n     * after that point are retained.\n     */\n    dropWhile(predicate:(x:T)=>boolean): Vector<T> {\n        return new Vector(L.dropWhile(predicate, this._list));\n    }\n\n    /**\n     * Search for the first item matching the predicate you pass,\n     * return Option.Some of that element if found,\n     * Option.None otherwise.\n     */\n    find(predicate:(v:T)=>boolean): Option<T> {\n        return Option.of(L.find(predicate, this._list));\n    }\n\n    /**\n     * Search for the last item matching the predicate you pass,\n     * return Option.Some of that element if found,\n     * Option.None otherwise.\n     */\n    findLast(predicate:(v:T)=>boolean): Option<T> {\n        return Option.of(L.findLast(predicate, this._list));\n    }\n\n    /**\n     * Search for the first item matching the predicate you pass,\n     * returning its index in the form of Option.Some if found,\n     * Option.None otherwise.\n     */\n    findIndex(predicate:(v:T)=>boolean): Option<number> {\n        return Option.of(L.findIndex(predicate, this._list)).filter(i => i != -1);\n    }\n\n    /**\n     * Returns true if the predicate returns true for all the\n     * elements in the collection.\n     */\n    allMatch<U extends T>(predicate:(v:T)=>v is U): this is Vector<U>;\n    allMatch(predicate:(v:T)=>boolean): boolean;\n    allMatch(predicate:(v:T)=>boolean): boolean {\n        return L.every(predicate, this._list);\n    }\n\n    /**\n     * Returns true if there the predicate returns true for any\n     * element in the collection.\n     */\n    anyMatch(predicate:(v:T)=>boolean): boolean {\n        return L.some(predicate, this._list);\n    }\n\n    /**\n     * Returns a pair of two collections; the first one\n     * will only contain the items from this collection for\n     * which the predicate you give returns true, the second\n     * will only contain the items from this collection where\n     * the predicate returns false.\n     *\n     *     Vector.of(1,2,3,4).partition(x => x%2===0)\n     *     => [Vector.of(2,4),Vector.of(1,3)]\n     */\n    partition<U extends T>(predicate:(v:T)=>v is U): [Vector<U>,Vector<Exclude<T,U>>];\n    partition(predicate:(x:T)=>boolean): [Vector<T>,Vector<T>];\n    partition(predicate:(v:T)=>boolean): [Vector<T>,Vector<T>] {\n        return <[Vector<T>,Vector<T>]>L.partition(predicate, this._list)\n            .map(x => new Vector(x));\n    }\n\n    /**\n     * Returns true if the item is in the collection,\n     * false otherwise.\n     */\n    contains(v:T&WithEquality): boolean {\n        return this.find(x => areEqual(x,v)).isSome();\n    }\n\n    /**\n     * Group elements in the collection using a classifier function.\n     * Elements are then organized in a map. The key is the value of\n     * the classifier, and in value we get the list of elements\n     * matching that value.\n     *\n     * also see [[Vector.arrangeBy]]\n     */\n    groupBy<C>(classifier: (v:T)=>C & WithEquality): HashMap<C,Vector<T>> {\n        return this.foldLeft(\n            HashMap.empty<C,Vector<T>>(),\n            (acc: HashMap<C,Vector<T>>, v:T) =>\n                acc.putWithMerge(\n                    classifier(v), Vector.of(v), // !!! DOUBLE CHECK THIS\n                    (v1:Vector<T>,v2:Vector<T>) => v1.append(<T>L.nth(0, v2._list))));\n    }\n\n    /**\n     * Matches each element with a unique key that you extract from it.\n     * If the same key is present twice, the function will return None.\n     *\n     * also see [[Vector.groupBy]]\n     */\n    arrangeBy<K>(getKey: (v:T)=>K&WithEquality): Option<HashMap<K,T>> {\n        return SeqHelpers.arrangeBy<T,K>(this, getKey);\n    }\n\n    /**\n     * Remove duplicate items; elements are mapped to keys, those\n     * get compared.\n     *\n     *     Vector.of(1,1,2,3,2,3,1).distinctBy(x => x);\n     *     => Vector.of(1,2,3)\n     */\n    distinctBy<U>(keyExtractor: (x:T)=>U&WithEquality): Vector<T> {\n        return <Vector<T>>SeqHelpers.distinctBy(this, keyExtractor);\n    }\n\n    [Symbol.iterator](): Iterator<T> {\n        return this._list[Symbol.iterator]();\n    }\n\n    /**\n     * Call a function for element in the collection.\n     */\n    forEach(fun:(x:T)=>void):Vector<T> {\n        L.forEach(fun, this._list);\n        return this;\n    }\n\n    /**\n     * Return a new collection where each element was transformed\n     * by the mapper function you give.\n     */\n    map<U>(fun:(x:T)=>U): Vector<U> {\n        return new Vector(L.map(fun, this._list));\n    }\n\n    /**\n     * Call a predicate for each element in the collection,\n     * build a new collection holding only the elements\n     * for which the predicate returned true.\n     */\n    filter<U extends T>(fun:(v:T)=>v is U): Vector<U>;\n    filter(fun:(v:T)=>boolean): Vector<T>;\n    filter(fun:(v:T)=>boolean): Vector<T> {\n        return new Vector(L.filter(fun, this._list));\n    }\n\n    /**\n     * Apply the mapper function on every element of this collection.\n     * The mapper function returns an Option; if the Option is a Some,\n     * the value it contains is added to the result Collection, if it's\n     * a None, the value is discarded.\n     *\n     *     Vector.of(1,2,6).mapOption(x => x%2===0 ?\n     *         Option.of(x+1) : Option.none<number>())\n     *     => Vector.of(3, 7)\n     */\n    mapOption<U>(mapper:(v:T)=>Option<U>): Vector<U> {\n        let vec = L.empty();\n        for (let i = 0; i < this.length(); i++) {\n            const v = mapper(<T>L.nth(i, this._list));\n            if (v.isSome()) {\n                vec = L.append(v.get(), vec);\n            }\n        }\n        return new Vector(vec);\n    }\n\n    /**\n     * Calls the function you give for each item in the collection,\n     * your function returns a collection, all the collections are\n     * concatenated.\n     * This is the monadic bind.\n     */\n    flatMap<U>(mapper:(v:T)=>Vector<U>): Vector<U> {\n        return new Vector(L.chain(x => mapper(x)._list, this._list));\n    }\n\n    /**\n     * Reduces the collection to a single value using the\n     * associative binary function you give. Since the function\n     * is associative, order of application doesn't matter.\n     *\n     * Example:\n     *\n     *     Vector.of(1,2,3).fold(0, (a,b) => a + b);\n     *     => 6\n     */\n    fold(zero:T, fn:(v1:T,v2:T)=>T): T {\n        return this.foldLeft(zero, fn);\n    }\n\n    /**\n     * Reduces the collection to a single value.\n     * Left-associative.\n     *\n     * Example:\n     *\n     *     Vector.of(\"a\", \"b\", \"c\").foldLeft(\"!\", (xs,x) => x+xs);\n     *     => \"cba!\"\n     *\n     * @param zero The initial value\n     * @param fn A function taking the previous value and\n     *           the current collection item, and returning\n     *           an updated value.\n     */\n    foldLeft<U>(zero:U, fn:(soFar:U,cur:T)=>U):U {\n        return L.foldl(fn, zero, this._list);\n    }\n\n    /**\n     * Reduces the collection to a single value.\n     * Right-associative.\n     *\n     * Example:\n     *\n     *     Vector.of(\"a\", \"b\", \"c\").foldRight(\"!\", (x,xs) => xs+x);\n     *     => \"!cba\"\n     *\n     * @param zero The initial value\n     * @param fn A function taking the current collection item and\n     *           the previous value , and returning\n     *           an updated value.\n     */\n    foldRight<U>(zero: U, fn:(cur:T, soFar:U)=>U): U {\n        return L.foldr(fn, zero, this._list);\n    }\n\n\n    /**\n     * Returns the index of the first occurence of the value you give, if present\n     *\n     *     Vector.of(1, 2, 3, 4, 3).indexOf(3)\n     *     => Option.of(2)\n     */\n    indexOf(element: T & WithEquality): Option<number> {\n        return Option.of(L.findIndex(v => areEqual(v, element), this._list))\n            .filter(i => i >= 0);\n    }\n\n    /**\n     * Randomly reorder the elements of the collection.\n     */\n    shuffle(): Vector<T> {\n        return Vector.ofIterable(SeqHelpers.shuffle(this.toArray()));\n    }\n\n    /**\n     * Transform this value to another value type.\n     * Enables fluent-style programming by chaining calls.\n     */\n    transform<U>(converter:(x:Vector<T>)=>U): U {\n        return converter(this);\n    }\n\n    /**\n     * Two objects are equal if they represent the same value,\n     * regardless of whether they are the same object physically\n     * in memory.\n     */\n    equals(other:Vector<T&WithEquality>): boolean {\n        if (<any>other === this) {\n            return true;\n        }\n        if (!other || (!other._list) || (!L.isList(other._list))) {\n            return false;\n        }\n        if (this.length() !== other.length()) return false;\n        for (let i = 0; i < this.length(); i++) {\n            const myVal: T & WithEquality|null|undefined = <T&WithEquality>L.nth(i, this._list);\n            const hisVal: T & WithEquality|null|undefined = L.nth(i, other._list);\n            if ((myVal === undefined) !== (hisVal === undefined)) {\n                return false;\n            }\n            if (myVal === undefined || hisVal === undefined) {\n                // they are both undefined, the || is for TS's flow analysis\n                // so he realizes none of them is undefined after this.\n                continue;\n            }\n            if (!areEqual(myVal, hisVal)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Get a number for that object. Two different values\n     * may get the same number, but one value must always get\n     * the same number. The formula can impact performance.\n     */\n    hashCode(): number {\n        let hash = 1;\n        for (let i=0;i<this.length();i++) {\n            hash = 31 * hash + getHashCode(L.nth(i, this._list));\n        }\n        return hash;\n    }\n\n    /**\n     * Get a human-friendly string representation of that value.\n     *\n     * Also see [[Vector.mkString]]\n     */\n    toString(): string {\n        let r = \"Vector(\";\n        for (let i=0;i<this.length();i++) {\n            if (i>0) {\n                r += \", \";\n            }\n            r += SeqHelpers.toStringHelper(L.nth(i, this._list));\n        }\n        return r + \")\";\n    }\n\n    /**\n     * Used by the node REPL to display values.\n     * Most of the time should be the same as toString()\n     */\n    [inspect](): string {\n        return this.toString();\n    }\n\n    /**\n     * Joins elements of the collection by a separator.\n     * Example:\n     *\n     *     Vector.of(1,2,3).mkString(\", \")\n     *     => \"1, 2, 3\"\n     */\n    mkString(separator: string): string {\n        let r = \"\";\n        for (let i=0;i<this.length();i++) {\n            if (i>0) {\n                r += separator;\n            }\n            r += SeqHelpers.toStringHelper(<T>L.nth(i, this._list), {quoteStrings:false});\n        }\n        return r;\n    }\n\n    /**\n     * Returns a new collection with elements\n     * sorted according to the comparator you give.\n     *\n     * also see [[Vector.sortOn]]\n     */\n    sortBy(compare: (v1:T,v2:T)=>Ordering): Vector<T> {\n        return Vector.ofIterable<T>(this.toArray().sort(compare));\n    }\n\n    /**\n     * Give a function associating a number or a string with\n     * elements from the collection, and the elements\n     * are sorted according to that value.\n     *\n     *     Vector.of({a:3,b:\"b\"},{a:1,b:\"test\"},{a:2,b:\"a\"}).sortOn(elt=>elt.a)\n     *     => Vector.of({a:1,b:\"test\"},{a:2,b:\"a\"},{a:3,b:\"b\"})\n     *\n     * You can also sort by multiple criteria, and request 'descending'\n     * sorting:\n     *\n     *     Vector.of({a:1,b:\"b\"},{a:1,b:\"test\"},{a:2,b:\"a\"}).sortOn(elt=>elt.a,{desc:elt=>elt.b})\n     *     => Vector.of({a:1,b:\"test\"},{a:1,b:\"b\"},{a:2,b:\"a\"})\n     *\n     * also see [[Vector.sortBy]]\n     */\n    sortOn(...getKeys: Array<ToOrderable<T>|{desc:ToOrderable<T>}>): Vector<T> {\n        return <Vector<T>>SeqHelpers.sortOn<T>(this, getKeys);\n    }\n\n    /**\n     * Convert this collection to a map. You give a function which\n     * for each element in the collection returns a pair. The\n     * key of the pair will be used as a key in the map, the value,\n     * as a value in the map. If several values get the same key,\n     * entries will be lost.\n     *\n     *     Vector.of(1,2,3).toMap(x=>[x.toString(), x])\n     *     => HashMap.of([\"1\",1], [\"2\",2], [\"3\",3])\n     */\n    toMap<K,V>(converter:(x:T)=>[K & WithEquality,V]): HashMap<K,V> {\n        return this.foldLeft(HashMap.empty<K,V>(), (acc,cur) => {\n            const converted = converter(cur);\n            return acc.put(converted[0], converted[1]);\n        });\n    }\n\n    /**\n     * Convert this collection to a set. Since the elements of the\n     * Seq may not support equality, you must pass a function returning\n     * a value supporting equality.\n     *\n     *     Vector.of(1,2,3,3,4).toSet(x=>x)\n     *     => HashSet.of(1,2,3,4)\n     */\n    toSet<K>(converter:(x:T)=>K&WithEquality): HashSet<K> {\n        return this.foldLeft(HashSet.empty<K>(), (acc,cur) => {\n            return acc.add(converter(cur));\n        });\n    }\n\n    /**\n     * Convert to array.\n     */\n    toArray(): T[] {\n        return L.toArray(this._list);\n    };\n\n    /**\n     * @hidden\n     */\n    hasTrueEquality(): boolean {\n        return SeqHelpers.seqHasTrueEquality<T>(this);\n    }\n\n    /**\n     * Combine any number of iterables you give in as\n     * parameters to produce a new collection which combines all,\n     * in tuples. For instance:\n     *\n     *     Vector.zip(Vector.of(1,2,3), [\"a\",\"b\",\"c\"], LinkedList.of(8,9,10))\n     *     => Vector.of([1,\"a\",8], [2,\"b\",9], [3,\"c\",10])\n     *\n     * The result collection will have the length of the shorter\n     * of the input iterables. Extra elements will be discarded.\n     *\n     * Also see [the non-static version](#zip), which only combines two\n     * collections.\n     * @param A A is the type of the tuple that'll be generated\n     *          (`[number,string,number]` for the code sample)\n     */\n    static zip<A extends any[]>(...iterables: IterableArray<A>): Vector<A> {\n        let r = <L.List<A>>L.empty();\n        const iterators = iterables.map(i => i[Symbol.iterator]());\n        let items = iterators.map(i => i.next());\n\n        while (!items.some(item => item.done)) {\n            r = L.append<A>(<any>items.map(item => item.value), r);\n            items = iterators.map(i => i.next());\n        }\n        return new Vector(r);\n    }\n\n    /**\n     * Combine this collection with the collection you give in\n     * parameter to produce a new collection which combines both,\n     * in pairs. For instance:\n     *\n     *     Vector.of(1,2,3).zip([\"a\",\"b\",\"c\"])\n     *     => Vector.of([1,\"a\"], [2,\"b\"], [3,\"c\"])\n     *\n     * The result collection will have the length of the shorter\n     * of both collections. Extra elements will be discarded.\n     *\n     * Also see [[Vector.zip]] (static version which can more than two\n     * iterables)\n     */\n    zip<U>(other: Iterable<U>): Vector<[T,U]> {\n        let r = <L.List<[T,U]>>L.empty();\n        const thisIterator = this[Symbol.iterator]();\n        const otherIterator = other[Symbol.iterator]();\n        let thisCurItem = thisIterator.next();\n        let otherCurItem = otherIterator.next();\n\n        while (!thisCurItem.done && !otherCurItem.done) {\n            r = L.append<[T,U]>([thisCurItem.value, otherCurItem.value], r);\n            thisCurItem = thisIterator.next();\n            otherCurItem = otherIterator.next();\n        }\n        return new Vector(r);\n    }\n\n    /**\n     * Reverse the collection. For instance:\n     *\n     *     Vector.of(1,2,3).reverse();\n     *     => Vector.of(3,2,1)\n     */\n    reverse(): Vector<T> {\n        return new Vector(L.reverse(this._list));\n    }\n\n    /**\n     * Combine this collection with the index of the elements\n     * in it. Handy if you need the index when you map on\n     * the collection for instance:\n     *\n     *     Vector.of(\"a\",\"b\").zipWithIndex().map(([v,idx]) => v+idx)\n     *     => Vector.of(\"a0\", \"b1\")\n     */\n    zipWithIndex(): Vector<[T,number]> {\n        return <Vector<[T,number]>>SeqHelpers.zipWithIndex<T>(this);\n    }\n\n    /**\n     * Returns a new collection, discarding the elements\n     * after the first element which fails the predicate.\n     */\n    takeWhile(predicate:(x:T)=>boolean): Vector<T> {\n        return new Vector(L.takeWhile(predicate, this._list));\n    }\n\n    /**\n     * Returns a new collection, discarding the elements\n     * after the first element which fails the predicate,\n     * but starting from the end of the collection.\n     *\n     *     Vector.of(1,2,3,4).takeRightWhile(x => x > 2)\n     *     => Vector.of(3,4)\n     */\n    takeRightWhile(predicate:(x:T)=>boolean): Vector<T> {\n        return new Vector(L.takeLastWhile(predicate, this._list));\n    }\n\n    /**\n     * Split the collection at a specific index.\n     *\n     *     Vector.of(1,2,3,4,5).splitAt(3)\n     *     => [Vector.of(1,2,3), Vector.of(4,5)]\n     */\n    splitAt(index:number): [Vector<T>,Vector<T>] {\n        if (index < 0) {\n            return [Vector.empty<T>(), this];\n        }\n        return <[Vector<T>,Vector<T>]>L.splitAt(index, this._list).map(x => new Vector(x));\n    }\n\n    /**\n     * Takes a predicate; returns a pair of collections.\n     * The first one is the longest prefix of this collection\n     * which satisfies the predicate, and the second collection\n     * is the remainder of the collection.\n     *\n     *    Vector.of(1,2,3,4,5,6).span(x => x <3)\n     *    => [Vector.of(1,2), Vector.of(3,4,5,6)]\n     */\n    span(predicate:(x:T)=>boolean): [Vector<T>,Vector<T>] {\n        // could be potentially faster using splitAt.\n        const first = this.takeWhile(predicate);\n        return [first, this.drop(first.length())];\n    }\n\n    /**\n     * Returns a new collection with the first\n     * n elements discarded.\n     * If the collection has less than n elements,\n     * returns the empty collection.\n     */\n    drop(n:number): Vector<T> {\n        return new Vector(L.drop(n, this._list));\n    }\n\n    /**\n     * Return a new collection containing the first n\n     * elements from this collection\n     *\n     *     Vector.of(1,2,3,4).take(2)\n     *     => Vector.of(1,2)\n     */\n    take(n:number): Vector<T> {\n        if (n<0) {\n            return Vector.empty<T>();\n        }\n        return new Vector(L.take(n, this._list));\n    }\n\n    /**\n     * Prepend an element at the beginning of the collection.\n     */\n    prepend(elt: T): Vector<T> {\n        return new Vector(L.prepend(elt, this._list));\n    }\n\n    /**\n     * Prepend multiple elements at the beginning of the collection.\n     */\n    prependAll(elts: Iterable<T>): Vector<T> {\n        return Vector.ofIterable(elts).appendAll(this);\n    }\n\n    /**\n     * Removes the first element matching the predicate\n     * (use [[Seq.filter]] to remove all elements matching a predicate)\n     */\n    removeFirst(predicate: (v:T)=>boolean): Vector<T> {\n        const v1 = this.takeWhile(x => !predicate(x));\n        return v1.appendAll(this.drop(v1.length()+1));\n    }\n\n    /**\n     * Returns a new collection with the last\n     * n elements discarded.\n     * If the collection has less than n elements,\n     * returns the empty collection.\n     */\n    dropRight(n:number): Vector<T> {\n        if (n>=this.length()) {\n            return Vector.empty<T>();\n        }\n        return new Vector(L.dropLast(n, this._list));\n    }\n\n    /**\n     * Returns a new collection, discarding the last elements\n     * until one element fails the predicate. All elements\n     * before that point are retained.\n     */\n    dropRightWhile(predicate:(x:T)=>boolean): Vector<T> {\n        let i=this.length()-1;\n        for (;i>=0;i--) {\n            if (!predicate(<T>L.nth(i, this._list))) {\n                return this.take(i+1);\n            }\n        }\n        return Vector.empty<T>();\n    }\n\n    /**\n     * Get all the elements in the collection but the first one.\n     * If the collection is empty, return None.\n     */\n    tail(): Option<Vector<T>> {\n        if (this.isEmpty()) {\n            return Option.none<Vector<T>>();\n        }\n        return Option.of(new Vector(L.tail(this._list)));\n    }\n\n    /**\n     * Reduces the collection to a single value by repeatedly\n     * calling the combine function.\n     * No starting value. The order in which the elements are\n     * passed to the combining function is undetermined.\n     */\n    reduce(combine: (v1:T,v2:T)=>T): Option<T> {\n        return SeqHelpers.reduce(this, combine);\n    }\n\n    /**\n     * Compare values in the collection and return the smallest element.\n     * Returns Option.none if the collection is empty.\n     *\n     * also see [[Vector.minOn]]\n     */\n    minBy(compare: (v1:T,v2:T)=>Ordering): Option<T> {\n        return SeqHelpers.minBy(this, compare);\n    }\n\n    /**\n     * Call the function you give for each value in the collection\n     * and return the element for which the result was the smallest.\n     * Returns Option.none if the collection is empty.\n     *\n     *     Vector.of({name:\"Joe\", age:12}, {name:\"Paula\", age:6}).minOn(x=>x.age)\n     *     => Option.of({name:\"Paula\", age:6})\n     *\n     * also see [[Vector.minBy]]\n     */\n    minOn(getOrderable: ToOrderable<T>): Option<T> {\n        return SeqHelpers.minOn(this, getOrderable);\n    }\n\n    /**\n     * Compare values in the collection and return the largest element.\n     * Returns Option.none if the collection is empty.\n     *\n     * also see [[Vector.maxOn]]\n     */\n    maxBy(compare: (v1:T,v2:T)=>Ordering): Option<T> {\n        return SeqHelpers.maxBy(this, compare);\n    }\n\n    /**\n     * Call the function you give for each value in the collection\n     * and return the element for which the result was the largest.\n     * Returns Option.none if the collection is empty.\n     *\n     *     Vector.of({name:\"Joe\", age:12}, {name:\"Paula\", age:6}).maxOn(x=>x.age)\n     *     => Option.of({name:\"Joe\", age:12})\n     *\n     * also see [[Vector.maxBy]]\n     */\n    maxOn(getOrderable: ToOrderable<T>): Option<T> {\n        return SeqHelpers.maxOn(this, getOrderable);\n    }\n\n    /**\n     * Call the function you give for each element in the collection\n     * and sum all the numbers, return that sum.\n     * Will return 0 if the collection is empty.\n     *\n     *     Vector.of(1,2,3).sumOn(x=>x)\n     *     => 6\n     */\n    sumOn(getNumber: (v:T)=>number): number {\n        return SeqHelpers.sumOn(this, getNumber);\n    }\n\n    /**\n     * Slides a window of a specific size over the sequence.\n     * Returns a lazy stream so memory use is not prohibitive.\n     *\n     *     Vector.of(1,2,3,4,5,6,7,8).sliding(3)\n     *     => Stream.of(Vector.of(1,2,3), Vector.of(4,5,6), Vector.of(7,8))\n     */\n    sliding(count:number): Stream<Vector<T>> {\n        return <Stream<Vector<T>>>SeqHelpers.sliding(this, count);\n    }\n\n    /**\n     * Apply the function you give to all elements of the sequence\n     * in turn, keeping the intermediate results and returning them\n     * along with the final result in a list.\n     * The last element of the result is the final cumulative result.\n     *\n     *     Vector.of(1,2,3).scanLeft(0, (soFar,cur)=>soFar+cur)\n     *     => Vector.of(0,1,3,6)\n     */\n    scanLeft<U>(init:U, fn:(soFar:U,cur:T)=>U): Vector<U> {\n        return new Vector(L.scan(fn, init, this._list));\n    }\n\n    /**\n     * Apply the function you give to all elements of the sequence\n     * in turn, keeping the intermediate results and returning them\n     * along with the final result in a list.\n     * The first element of the result is the final cumulative result.\n     *\n     *     Vector.of(1,2,3).scanRight(0, (cur,soFar)=>soFar+cur)\n     *     => Vector.of(6,5,3,0)\n     */\n    scanRight<U>(init:U, fn:(cur:T,soFar:U)=>U): Vector<U> {\n        const r:U[] = [];\n        r.unshift(init);\n        let cur = init;\n        for (let i = this.length()-1; i>=0; i--) {\n            cur = fn(<T>L.nth(i, this._list), cur);\n            r.unshift(cur);\n        }\n        return Vector.ofIterable(r);\n    }\n}\n"
  },
  {
    "path": "src/index.ts",
    "content": "// Not re-exporting the abstract types such as Seq, Collection and so on,\n// on purpose. Right now they are more an help to design the library, not meant\n// for the user.\n// Seq<T>.equals is a lot less type-precise than Vector<T>.equals, so I'd rather\n// the users use concrete types.\nexport * from \"./Option\";\nexport * from \"./Either\";\nexport * from \"./Lazy\";\nexport * from \"./Vector\";\nexport * from \"./LinkedList\";\nexport * from \"./HashMap\";\nexport * from \"./HashSet\";\nexport * from \"./Tuple2\";\nexport * from \"./Value\";\nexport * from \"./Comparison\";\nexport * from \"./Stream\";\nexport * from \"./Contract\";\nexport * from \"./Predicate\";\nexport * from \"./Function\";\nexport * from \"./Future\";\n"
  },
  {
    "path": "tests/Collection.ts",
    "content": "import { Collection } from \"../src/Collection\";\nimport { HashMap } from \"../src/HashMap\";\nimport { WithEquality } from \"../src/Comparison\";\nimport { Option } from \"../src/Option\";\nimport * as assert from 'assert'\n\n/**\n * @hidden\n */\nexport function runTests(seqName: string,\n                         of: <T>(...i:Array<T&WithEquality>)=>Collection<T>,\n                         empty: <T>()=>Collection<T>) {\n    describe(seqName + \" manipulation\", () => {\n        it(\"arrangeBy works, positive case\", () => assert.ok(\n            HashMap.of<string,string>([\"a\", \"aadvark\"], [\"b\", \"baseball\"]).equals(\n                of(\"aadvark\", \"baseball\").arrangeBy(x => x[0]).getOrThrow())));\n        it(\"arrangeBy works, negative case\", () => assert.ok(\n                of(\"aadvark\", \"aaseball\").arrangeBy(x => x[0]).isNone()));\n        it(\"arrangeBy works, empty seq\", () => assert.ok(\n            HashMap.empty<string,string>().equals(\n                empty<string>().arrangeBy(x => x[0]).getOrThrow())));\n        it(\"groupBy works\", () => assert.ok(\n            HashMap.empty<number,Collection<number>>().put(0, of(2,4)).put(1, of(1,3))\n                .equals(of(1,2,3,4).groupBy(x => x%2))));\n        it(\"reduce works\", () => assert.equal(\n            6, of(1,2,3).reduce((a,b)=>a+b).getOrThrow()));\n        it(\"reduce works on an empty collection\", () => assert.ok(\n            Option.none<number>().equals(empty<number>().reduce((a,b)=>a+b))));\n        it(\"minOn works\", () => assert.equal(\n            2, of(2,3,4).minOn(x=>x).getOrThrow()));\n        it(\"minOn works on the empty collection\", () => assert.ok(\n            empty<number>().minOn(x=>x).isNone()));\n        it(\"minBy works\", () => assert.equal(\n            4, of(2,3,4).minBy((x,y)=>x-y).getOrThrow()));\n        it(\"minBy works on the empty collection\", () => assert.ok(\n            empty<number>().minBy((x,y)=>x-y).isNone()));\n        it(\"maxOn works\", () => assert.equal(\n            4, of(2,3,4).maxOn(x=>x).getOrThrow()));\n        it(\"maxOn works on the empty collection\", () => assert.ok(\n            empty<number>().maxOn(x=>x).isNone()));\n        it(\"maxBy works\", () => assert.equal(\n            2, of(2,3,4).maxBy((x,y)=>x-y).getOrThrow()));\n        it(\"maxBy works on the empty collection\", () => assert.ok(\n            empty<number>().maxBy((x,y)=>x-y).isNone()));\n        it(\"sumOn works\", () => assert.equal(\n            6, of(1,2,3).sumOn(x=>x)));\n        it(\"sumOn works on the empty collection\", () => assert.equal(\n            0, empty<number>().sumOn(x=>x)));\n    });\n}\n"
  },
  {
    "path": "tests/Comments.ts",
    "content": "import { readFileSync, writeFileSync, readdirSync } from \"fs\";\nimport { Vector } from \"../src/Vector\";\nimport { Option } from \"../src/Option\";\nimport { Function2 } from \"../src/Function\";\nimport * as ts from 'typescript';\n\n/**\n * In this little script we extract source code from the apidoc comments\n * all over the source of prelude-ts, generate for each source file which\n * has apidoc comments containing source code samples a special apidoc-*.ts\n * test file.\n *\n * The apidoc comments must have the source indented by 4 characters, and\n * apidoc comments can specify an expected result for an expression using\n * \"=>\".\n */\n\nfunction getCodeSamples(commentText: string): Vector<string> {\n    const closedOpen = Vector\n        .ofIterable(commentText.split(\"\\n\"))\n        .map(str => str.trim())\n        .takeWhile(str => str.indexOf(\"@param\") < 0) // don't consider anything after @param\n        .foldLeft({closed: Vector.empty<string>(), open: Option.none<string>()}, (sofar,cur) => {\n            // we want to merge consecutive lines of code. a single comment may\n            // contain multiple blocks of code, separated by normal text\n            // => group the blocks of code together, skip the rest.\n            const isCode = cur.startsWith(\"*    \");\n            if (!isCode && sofar.open.isSome()) {\n                // this line is not code but we have an open piece of code\n                // => close the open piece of code\n                return {closed: sofar.closed.append(sofar.open.get()), open: Option.none<string>()};\n            }\n            if (!isCode) {\n                // this line is not code, no open piece of code\n                // => nothing to do\n                return sofar;\n            }\n            const lineCode = cur.replace(/^\\*    /, \"\");\n            if (sofar.open.isSome()) {\n                // this is code, and we have an open piece\n                // => append to it\n                return { closed: sofar.closed, open: Option.of(sofar.open.get()+\"\\n\"+lineCode)}\n            }\n            // this is code, no open piece => create a new piece\n            return { closed: sofar.closed, open: Option.of(lineCode)}\n        });\n    return closedOpen.closed.appendAll(closedOpen.open.toVector());\n}\n\ntype SampleInfo = {\n    identifier: string;\n    code: string,\n    expectedResult?: string\n};\n\nfunction getCommentsInlineCode(scanner: ts.Scanner): Vector<SampleInfo> {\n    let token = scanner.scan();\n    let codeSamples = Vector.empty<SampleInfo>();\n    let curCodeSample = Vector.empty<string>();\n    while (token !== ts.SyntaxKind.EndOfFileToken) {\n        if (!curCodeSample.isEmpty() &&\n            token === ts.SyntaxKind.Identifier) {\n            codeSamples = codeSamples.appendAll(\n                curCodeSample.map(Function2.of(getCodeSampleInfo).apply1(scanner.getTokenText())));\n            curCodeSample = Vector.empty<string>();\n        }\n        if ((token === ts.SyntaxKind.SingleLineCommentTrivia) ||\n            (token === ts.SyntaxKind.MultiLineCommentTrivia) ||\n            (token === ts.SyntaxKind.JSDocComment)) {\n            curCodeSample = getCodeSamples(scanner.getTokenText());\n        }\n        token = scanner.scan();\n    }\n    return codeSamples;\n}\n\nfunction getCodeSampleInfo(identifier: string, codeSample: string): SampleInfo {\n    const lines = Vector.ofIterable(codeSample.split(\"\\n\"));\n    if (!lines.last().getOrThrow().trim().startsWith(\"=>\")) {\n        return {\n            identifier,\n            code: codeSample\n        };\n    }\n    return {\n        identifier,\n        code: lines.init().mkString(\"\\n\"),\n        expectedResult: lines.last().getOrThrow().replace(/^\\s*=>\\s*/, \"\")\n    };\n}\n\nfunction storeInVariable(code: string) {\n    if (code.replace(/[^;]/g, \"\").length <= 1) {\n        // only one \";\" or less => single line.\n        return \"const xvar = \" + code;\n    }\n    // assuming several lines\n    // we rely on indentation to find out where to insert\n    // the const xvar = ...\n    //\n    // for instance...\n    //\n    // first LOC\n    // xcx\n    // blabla( <-- insert here: last line with same indentation as first LOC\n    //    ...\n    //    ...);\n    // =>\n    const lines = Vector.ofIterable(code.split(\"\\n\"));\n    const getIndent = (str:string)=> str.replace(/[^\\s].*$/, \"\").length;\n    const codeIndent = getIndent(lines.head().getOrThrow());\n    const constExprLines = lines\n        .reverse()\n        .takeWhile(l => getIndent(l) > codeIndent)\n        .length()+1\n\n    const [before,after] = lines.splitAt(lines.length()-constExprLines);\n    return before\n        .append(\" const xvar = \")\n        .appendAll(after)\n        .mkString(\"\\n\");\n}\n\nfunction generateTestContents(fname: string, sampleInfo: SampleInfo) {\n    const wrap = (x:string) => `describe(\"${fname} docstrings\", () => { ${x} });`;\n    if (sampleInfo.expectedResult && sampleInfo.expectedResult.startsWith(\"throws\")) {\n        return wrap(`\n            it(\"${sampleInfo.identifier}\", () => {\n                assert.throws(() => {\n                    ${sampleInfo.code}\n                });\n            });\n`\n        );\n    } else if (sampleInfo.expectedResult) {\n        return wrap(`\n            it(\"${sampleInfo.identifier}\", () => {\n                resetMathRandom();\n                ${storeInVariable(sampleInfo.code)};\n                assert.ok(myEq(${sampleInfo.expectedResult}, xvar),\n                    ${sampleInfo.expectedResult} + \" !== \" + xvar);\n                Math.random = origMathRandom;\n            });\n`);\n    } else {\n        return wrap(`\n            // no result to compare the output to, just make sure this compiles\n            ${sampleInfo.code}\n`);\n    }\n}\n\nfunction generateTestFileContents(fname: string, samplesInfo: Vector<SampleInfo>) {\n    return `\n        import { Vector } from \"../src/Vector\";\n        import { Future } from \"../src/Future\";\n        import { LinkedList, ConsLinkedList, EmptyLinkedList } from \"../src/LinkedList\";\n        import { HashSet } from \"../src/HashSet\";\n        import { HashMap } from \"../src/HashMap\";\n        import { Stream, EmptyStream, ConsStream } from \"../src/Stream\";\n        import { Function0, Function1, Function2,\n                 Function3, Function4, Function5 } from \"../src/Function\";\n        import { Predicate } from \"../src/Predicate\";\n        import { Either, Left, Right } from \"../src/Either\";\n        import { Option, Some, None } from \"../src/Option\";\n        import { instanceOf, typeOf } from \"../src/Comparison\";\n        import * as assert from 'assert';\n        import * as fs from 'fs';\n\n        function myEq(a:any, b:any): boolean {\n             if (a === null && b === null) {\n                 return true;\n             }\n             if ((a === null) !== (b === null)) {\n                 return false;\n             }\n             if (a === undefined && b === undefined) {\n                 return true;\n             }\n             if ((a === undefined) !== (b === undefined)) {\n                 return false;\n             }\n             if ((<any>a).isSome && (<any>b).isSome &&\n                     (<any>a).isSome() && (<any>b).isSome()) {\n                 // workaround for Option<array> equality\n                 // useful in HashMap tests\n                 return myEq(a.getOrThrow(), b.getOrThrow());\n             }\n             if (a.toArray) {\n                 // workaround for the zip test Vector.of([1,\"a\"]) equality\n                 // real Vector returns false, compilation error otherwise\n                 return myEq(a.toArray(), b.toArray());\n             }\n             if (a.equals) {\n                 return a.equals(b);\n             }\n             if (Array.isArray(a)) {\n                  if (a.length !== b.length) {\n                       return false;\n                  }\n                  for (let i=0;i<a.length;i++) {\n                      if (!myEq(a[i], b[i])) {\n                          return false;\n                      }\n                  }\n                  return true;\n             }\n             return JSON.stringify(a) === JSON.stringify(b);\n        }\n\n        // adding date support to myEq above isn't enough because I have Option<Date>\n        // in one of the tests...\n        (<any>Date.prototype).equals = function (other: Date) { return this.getTime() === other.getTime(); }\n\n        const randomValues = [0.49884723907769635, 0.3226548779864311];\n        let randomIndex = 0;\n        const origMathRandom = Math.random;\n        const mockMathRandom = () => randomValues[(randomIndex++) % randomValues.length];\n        function resetMathRandom() {\n             randomIndex = 0;\n             Math.random = mockMathRandom;\n        }\n\n        ${samplesInfo.map(Function2.of(generateTestContents).apply1(fname)).mkString(\"\\n\")}\n    `;\n}\n\nfunction generateTestCommentsFile(filepath: string, fname: string): void {\n    const fileContents = readFileSync(filepath).toString();\n    const scanner = ts.createScanner(\n        ts.ScriptTarget.ES2016, false,\n        ts.LanguageVariant.Standard, readFileSync(filepath).toString());\n    const codeSamples = getCommentsInlineCode(scanner);\n    if (codeSamples.isEmpty()) {\n        // nothing to do\n        return;\n    }\n    const outputContents = generateTestFileContents(fname, codeSamples);\n    writeFileSync(\"tests/apidoc-\" + fname, outputContents);\n}\n\n/**\n * @hidden\n */\nexport function generateTestComments(): void {\n    const files = readdirSync(\"./src\");\n    files\n        .filter(file => file.endsWith(\".ts\"))\n        .forEach(file => generateTestCommentsFile(\"src/\" + file, file));\n}\ngenerateTestComments();\n"
  },
  {
    "path": "tests/Comparison.ts",
    "content": "import { typeOf } from \"../src/Comparison\";\nimport { Vector } from \"../src/Vector\";\nimport * as assert from 'assert'\n\ndescribe(\"typeOf\", () => {\n    it (\"typeOf number\", () => {\n        // just checking that the type inference comes up with the proper type.\n        // only number has 'toExponential'\n        Vector.of<any>(1,\"a\",2,3,\"b\").filter(typeOf(\"number\"))\n            .head().getOrThrow().toExponential(2);\n    });\n    it (\"typeOf string\", () => {\n        // just checking that the type inference comes up with the proper type.\n        // only string has 'charAt'\n        Vector.of<any>(1,\"a\",2,3,\"b\").filter(typeOf(\"string\"))\n            .head().getOrThrow().charAt(2);\n    });\n});\n"
  },
  {
    "path": "tests/DocLinks.ts",
    "content": "import { readFileSync } from \"fs\";\nimport { Vector } from \"../src/Vector\";\nimport { Future } from \"../src/Future\";\nimport * as helpers from \"../scripts/make_doc_extra/helpers\";\nimport * as rp from 'request-promise-native';\n\nfunction checkUrlsInText(text:string, urlFilter: (url:string)=>boolean): Future<Vector<string>> {\n    const urls = Vector.ofIterable(\n        helpers.requireNotNull(text.match(/https?:.+?(?=[\\s\\)\"'])/g)))\n        .filter(urlFilter);\n    return Future.traverse(urls, url => {\n        console.log(`Checking ${url}...`);\n        return Future.of(rp(url).promise())\n    }, {maxConcurrent:3});\n}\n\ndescribe(\"documentation links work\", () => {\n    it(\"README.md\", async () => {\n        const contents = readFileSync(\"README.md\").toString();\n        await checkUrlsInText(contents, _=>true);\n    });\n    it(\"User Guide\", async () => {\n        const userGuide = await rp(\"https://github.com/emmanueltouzery/prelude.ts/wiki/Prelude.ts-user-guide\");\n        await checkUrlsInText(userGuide, url => url.indexOf(\"emmanuel\") >= 0 && !url.endsWith(\".git\"));\n    });\n    it(\"Equality Guide\", async () => {\n        const userGuide = await rp(\"https://github.com/emmanueltouzery/prelude.ts/wiki/Equality\");\n        await checkUrlsInText(userGuide, url => url.indexOf(\"emmanuel\") >= 0 && !url.endsWith(\".git\"));\n    });\n});\n"
  },
  {
    "path": "tests/Either.ts",
    "content": "import { Either } from \"../src/Either\";\nimport { Vector } from \"../src/Vector\";\nimport { Seq } from \"../src/Seq\";\nimport { assertFailCompile } from \"./TestHelpers\";\nimport * as assert from 'assert'\n\ndescribe(\"either comparison\", () => {\n    it(\"should mark equal eithers as equal\", () =>\n       assert.ok(Either.right(5).equals(Either.right<number,number>(5))))\n    it(\"should mark different eithers as not equal\", () =>\n       assert.ok(!Either.right(5).equals(Either.right<number,number>(6))))\n    it(\"should mark left as equals to left\", () =>\n       assert.ok(Either.left(\"x\").equals(Either.left<string,string>(\"x\"))));\n    it(\"should mark left and right as not equal\", () =>\n       assert.ok(!Either.right(5).equals(Either.left<number,number>(5))));\n    it(\"should mark left and right as not equal\", () =>\n       assert.ok(!Either.left(5).equals(Either.right<number,number>(5))));\n    it(\"should return true on contains\", () =>\n       assert.ok(Either.right(5).contains(5)));\n    it(\"should return false on contains on left\", () =>\n       assert.ok(!Either.left(5).contains(5)));\n    it(\"should return false on contains\", () =>\n       assert.ok(!Either.right(6).contains(5)));\n    it(\"doesn't throw when given another type on equals\", () => assert.equal(\n        false, Either.right(1).equals(<any>[1,2])));\n    it(\"doesn't throw when given null on equals\", () => assert.equal(\n        false, Either.right(1).equals(<any>null)));\n    it(\"empty doesn't throw when given another type on equals\", () => assert.equal(\n        false, Either.left(1).equals(<any>[1,2])));\n    it(\"empty doesn't throw when given null on equals\", () => assert.equal(\n        false, Either.left(1).equals(<any>null)));\n    it(\"should throw when comparing eithers without true equality\", () => assert.throws(\n        () => Either.right(Vector.of([1])).equals(\n            Either.right<string,Vector<number[]>>(Vector.of([1])))));\n    it(\"should fail compilation on an obviously bad equality test\", () =>\n       assertFailCompile(\n           \"Either.right([1]).equals(Either.right([1]))\", \"is not assignable to parameter\"));\n    it(\"should fail compilation on an obviously bad contains test\", () =>\n       assertFailCompile(\n           \"Either.right([1]).contains([1])\",\n           \"is not assignable to parameter\"));\n});\n\ndescribe(\"either transformation\", () => {\n    it(\"should transform with map\", () => {\n        assert.ok(Either.right(5).equals(Either.right<number,number>(4).map(x=>x+1)));\n    });\n    it(\"should handle null as Right\", () =>\n       assert.ok(Either.right(5).map<number|null>(x => null).equals(\n           Either.right<string,number|null>(null))));\n    it(\"should transform a Right to string properly\", () =>\n       assert.equal(\"Right(5)\", Either.right(5).toString()));\n    it(\"should transform a Left to string properly\", () =>\n       assert.equal(\"Left(5)\", Either.left(5).toString()));\n    it(\"should transform with flatMap x->y\", () => {\n        assert.ok(Either.right(5).equals(\n            Either.right<number,number>(4)\n                .flatMap(x=>Either.right<number,number>(x+1))));\n    });\n    it(\"should transform with flatMap x->left\", () => {\n        assert.ok(Either.left<number,number>(5).equals(\n            Either.right<number,number>(4).flatMap(x=>Either.left<number,number>(5))));\n    });\n    it(\"should transform with flatMap left->left\", () => {\n        assert.ok(Either.left(4).equals(\n            Either.left<number,number>(4).flatMap(x=>Either.right<number,number>(x+1))));\n    });\n    it(\"should apply bimap on the left value\", () =>\n       assert.ok(Either.left<number,number>(4).equals(\n           Either.left<number,number>(3).bimap(x=>x+1,x=>x-1))));\n    it(\"should apply bimap on the right value\", () =>\n       assert.ok(Either.right<number,number>(2).equals(\n           Either.right<number,number>(3).bimap(x=>x+1,x=>x-1))));\n    it(\"should apply match to a right\", () =>\n       assert.equal(5, Either.right<number,number>(4).match({\n           Right: x=>x+1,\n           Left:  x=>-1\n       })));\n    it(\"should apply match to a left\", () =>\n       assert.equal(4, Either.left<number,number>(5).match({\n           Right: x=>1,\n           Left:  x=>x-1\n       })));\n    it(\"should liftA2\", () => assert.ok(Either.right<string,number>(11).equals(\n        Either.liftA2((x:number,y:number) => x+y, {} as string)\n        (Either.right<string,number>(5), Either.right<string,number>(6)))));\n    it(\"should abort liftA2 on left\", () => assert.ok(Either.left(\"bad\").equals(\n        Either.liftA2((x:number,y:number) => x+y, {} as string)(\n            Either.right<string,number>(5), Either.left<string,number>(\"bad\")))));\n    it(\"should liftAp\", () => {\n        const fn = (x:{a:number,b:number,c:number}) => x.a+x.b+x.c;\n        const lifted = Either.liftAp(fn, {} as number);\n        assert.ok(Either.right(14).equals(\n            lifted({a:Either.right<number,number>(5), b:Either.right<number,number>(6), c:Either.right<number,number>(3)})));\n    });\n    it(\"should abort liftAp on left\", () => assert.ok(Either.left(2).equals(\n        Either.liftAp<number,{a:number,b:number},number>(x => x.a+x.b)\n        ({a:Either.right<number,number>(5), b:Either.left<number,number>(2)}))));\n    it(\"should lift 5-parameter functions\", () => {\n        assert.ok(Either.lift(\n            (x:number,y:number,z:number,a:number,b:number)=>x+1)(1,2,3,4,5).equals(Either.right(2)));\n        assert.throws(()=>Either.lift(\n            (x:number,y:number,z:number,a:number,b:number)=>undefined)(1,2,3,4,5));\n        assert.ok(Either.lift(\n            (x:number,y:number,z:number,a:number,b:number)=>{throw \"x\"})(1,2,3,4,5).isLeft());\n    });\n    it(\"left should provide transform\", () => assert.equal(\n        6, Either.left<number,number>(5).transform(x => 6)));\n    it(\"right should provide transform\", () => assert.equal(\n        6, Either.right<number,number>(5).transform(x => 6)));\n    it(\"should return the unchanged either if it was a left on filter\", () => assert.ok(\n        Either.left(\"bad\").equals(\n            Either.left<string,number>(\"bad\").filter(x => x<0, v => \"\"))));\n    it(\"should return the unchanged either if it was a right and predicate passes on filter\", () => assert.ok(\n        Either.right<string, number>(5).equals(\n            Either.right<string, number>(5).filter(x => x>0, v => \"\"))));\n    it(\"should return the unchanged successful either on recoverWith\", () => assert.ok(\n        Either.right<number, number>(6).equals(\n            Either.right<number, number>(6).recoverWith(v => Either.right<number, number>(v+1)))\n    ));\n    it(\"should return the new either on a failed Either with recoverWith\", () => assert.ok(\n        Either.right<number, number>(7).equals(\n            Either.left<number, number>(6).recoverWith(v => Either.right<number, number>(v+1)))\n    ));\n    it(\"should return the new failed either on a failed Either with recoverWith\", () => assert.ok(\n        Either.left<number, number>(7).equals(\n            Either.left<number, number>(6).recoverWith(v => Either.left<number, number>(v+1)))\n    ));\n});\n\ndescribe(\"Either helpers\", () => {\n    it(\"should do sequence when all are right\", () =>\n       assert.ok(\n           Either.right(<Seq<number>>Vector.of(1,2,3)).equals(\n               Either.sequence(Vector.of(Either.right<number,number>(1),\n                                         Either.right<number,number>(2),\n                                         Either.right<number,number>(3))))));\n    it(\"should fail sequence when some are left\", () =>\n       assert.ok(\n           Either.left(2).equals(\n               Either.sequence(Vector.of(Either.right<number,number>(1),\n                                         Either.left<number,number>(2),\n                                         Either.left<number,number>(3))))));\n});\n\ndescribe(\"either retrieval\", () => {\n    it(\"should return the value on Right.getOrElse\", () =>\n       assert.equal(5, Either.right(5).getOrElse(6)));\n    it(\"should return the alternative on Left.getOrElse\", () =>\n       assert.equal(6, Either.left<number,number>(5).getOrElse(6)));\n    it(\"should return the value on Right.toVector\", () =>\n       assert.deepEqual([5], Either.right(5).toVector().toArray()));\n    it(\"should return empty on Left.toVector\", () =>\n       assert.deepEqual([], Either.left<number,number>(5).toVector().toArray()));\n    it(\"should not throw on Right.getOrThrow\", () =>\n       assert.equal(5, Either.right(5).getOrThrow()));\n    it(\"should throw on Left.getOrThrow\", () =>\n       assert.throws(() => Either.left<number,number>(5).getOrThrow()));\n    it(\"should throw on Left.getOrThrow with custom msg\", () =>\n       assert.throws(() => Either.left<number,number>(5).getOrThrow(\"my custom msg\"),\n                     (err:any) => err.message === 'my custom msg'));\n    it(\"should offer get() if i checked for isRight\", () => {\n        const either = <Either<string,number>>Either.right(5);\n        if (either.isRight()) {\n            // what we are checking here is whether this does build\n            // .get() is available only on Right\n            assert.equal(5, either.get());\n        }\n    });\n    it(\"should offer get() if i checked against isLeft\", () => {\n        const either = <Either<string,number>>Either.right(5);\n        if (!either.isLeft()) {\n            // what we are checking here is whether this does build\n            // .get() is available only on Right\n            assert.equal(5, either.get());\n        }\n    });\n    it(\"should offer getLeft() if i checked for isLeft\", () => {\n        const either = <Either<string,number>>Either.left(\"5\");\n        if (either.isLeft()) {\n            // what we are checking here is whether this does build\n            // .get() is available only on Left\n            assert.equal(\"5\", either.getLeft());\n        }\n    });\n    it(\"should offer getLeft() if i checked against isRight\", () => {\n        const either = <Either<string,number>>Either.left(\"5\");\n        if (!either.isRight()) {\n            // what we are checking here is whether this does build\n            // .get() is available only on Left\n            assert.equal(\"5\", either.getLeft());\n        }\n    });\n});\n"
  },
  {
    "path": "tests/Function.ts",
    "content": "import { Function0, Function1, Function2, Function3, Function4, Function5 } from '../src/Function';\nimport { Option } from \"../src/Option\";\nimport * as assert from 'assert'\n\ndescribe(\"function composition\", () => {\n    it (\"Function0 tests\", () => {\n        const two = Function0.of(()=>2);\n        assert.equal(4, two.andThen((x:number)=>x*2)());\n        assert.equal(5, Function0.constant(5)());\n    });\n    it (\"Function1 tests\", () => {\n        const add1 = Function1.of((x:number)=>x+1);\n        assert.equal(9, add1.compose((x:number)=>x*2)(4));\n        assert.equal(10, add1.andThen((x:number)=>x*2)(4));\n        assert.equal(5, Function1.id()(5));\n        assert.equal(5, Function1.constant(5)(12));\n    });\n    it (\"Function2 tests\", () => {\n        const sumPlus1 = Function2.of((x:number,y:number)=>x+y+1);\n        assert.equal(16, sumPlus1.andThen((x:number)=>x*2)(4,3));\n        assert.equal(8, sumPlus1.curried()(4)(3));\n        assert.equal(8, sumPlus1.tupled()([4,3]));\n        assert.equal(8, sumPlus1.flipped()(4,3));\n        assert.equal(5, Function2.constant(5)(12,32));\n        assert.equal(8, sumPlus1.apply1(4)(3));\n    });\n    it (\"Function3 tests\", () => {\n        const sumPlus1 = Function3.of((x:number,y:number,z:number)=>x+y+z+1);\n        assert.equal(20, sumPlus1.andThen((x:number)=>x*2)(4,3,2));\n        assert.equal(10, sumPlus1.curried()(4)(3)(2));\n        assert.equal(10, sumPlus1.tupled()([4,3,2]));\n        assert.equal(10, sumPlus1.flipped()(4,3,2));\n        assert.equal(5, Function3.constant(5)(12,32,45));\n        assert.equal(10, sumPlus1.apply1(4)(3,2));\n        assert.equal(10, sumPlus1.apply2(4,3)(2));\n    });\n    it (\"Function4 tests\", () => {\n        const sumPlus1 = Function4.of((x:number,y:number,z:number,a:number)=>x+y+z+a+1);\n        assert.equal(22, sumPlus1.andThen((x:number)=>x*2)(4,3,2,1));\n        assert.equal(11, sumPlus1.curried()(4)(3)(2)(1));\n        assert.equal(11, sumPlus1.tupled()([4,3,2,1]));\n        assert.equal(11, sumPlus1.flipped()(4,3,2,1));\n        assert.equal(5, Function4.constant(5)(12,32,45,34));\n        assert.equal(11, sumPlus1.apply1(4)(3,2,1));\n        assert.equal(11, sumPlus1.apply2(4,3)(2,1));\n        assert.equal(11, sumPlus1.apply3(4,3,2)(1));\n    });\n    it (\"Function5 tests\", () => {\n        const sumPlus1 = Function5.of((x:number,y:number,z:number,a:number,b:number)=>x+y+z+a+b+1);\n        assert.equal(22, sumPlus1.andThen((x:number)=>x*2)(4,3,2,1,0));\n        assert.equal(11, sumPlus1.curried()(4)(3)(2)(1)(0));\n        assert.equal(11, sumPlus1.tupled()([4,3,2,1,0]));\n        assert.equal(11, sumPlus1.flipped()(4,3,2,1,0));\n        assert.equal(5, Function5.constant(5)(12,32,45,34,23));\n        assert.equal(11, sumPlus1.apply1(4)(3,2,1,0));\n        assert.equal(11, sumPlus1.apply2(4,3)(2,1,0));\n        assert.equal(11, sumPlus1.apply3(4,3,2)(1,0));\n        assert.equal(11, sumPlus1.apply4(4,3,2,1)(0));\n    });\n});\n"
  },
  {
    "path": "tests/Future.ts",
    "content": "import { Future } from \"../src/Future\";\nimport { Vector } from \"../src/Vector\";\nimport { Option } from \"../src/Option\";\nimport { Either } from \"../src/Either\";\nimport * as fs from 'fs';\nimport * as assert from 'assert';\n\nasync function ensureFailedWithValue<T>(val: any, promise:Promise<T>) {\n    let v;\n    try {\n        v = await promise;\n        assert.ok(false);\n    } catch (err) {\n        assert.deepEqual(val, err);\n    }\n}\n\ndescribe(\"Future.of\", () => {\n    it(\"properly wraps successful promises with of\", async () => {\n        assert.deepEqual(5, await Future.of(new Promise((a,r) => a(5))));\n    });\n    it(\"properly wraps failed promises with of\", async () => {\n        // shows the need for future.catch!?\n        // await Future.of(new Promise((a,r) => r(5)))\n        return ensureFailedWithValue(5, Future.of(Promise.reject(5)).toPromise());\n    });\n});\ndescribe(\"Future.ofCallback\", () => {\n    it(\"properly operates with fs.readFile\", async () => {\n        const readme = await Future.ofCallback<string>(\n            cb => fs.readFile(__dirname + \"/../../README.md\", \"utf-8\", cb));\n        // the readme should be long at least 1000 bytes\n        assert.ok(readme.length > 1000);\n    });\n    it(\"properly operates with fs.readFile in case of errors\", async () => {\n        try {\n            const passwd = await Future.ofCallback<string>(\n                cb => fs.readFile(__dirname + \"/../../README.mddd\", \"utf-8\", cb));\n            assert.ok(false); // should not make it here\n        } catch (err) {\n            // file does not exist\n            assert.equal('ENOENT', err.code);\n        }\n    });\n});\ndescribe(\"Future basics\", () => {\n    it(\"works when triggered\", async () => {\n        let i=0;\n        await Future.ofPromiseCtor(done=>done(++i));\n        assert.deepEqual(1, i);\n    });\n    it(\"works when failed\", async () => {\n        let i=0;\n        try {\n            await Future.ofPromiseCtor((done,err)=>err(++i));\n        } catch (err) {\n            assert.deepEqual(1, err);\n            assert.deepEqual(1, i);\n        }\n    });\n    it(\"handles errors\", async () => {\n        let i = 0;\n        let msg:Error|null = null;\n        Future.ofPromiseCtor(done=>{throw \"oops\"})\n            .map(x => ++i)\n            .onFailure(err => msg = err)\n            .toPromise().then(\n                success => assert.ok(false),\n                failed => {\n                    assert.deepEqual(\"oops\", failed);\n                    assert.deepEqual(0, i);\n                    assert.deepEqual(\"oops\", msg);\n                });\n    });\n    it(\"handles a throw in map\", async () => {\n        // i'm not crazy about this behaviour (not really functor-law like)\n        // but it's JS we're dealing with in the end :-(\n        return ensureFailedWithValue(\n            \"oops\", Future.ok(5).map<number>(x => {throw \"oops\"}).toPromise());\n    });\n    it(\"handles a throw in flatMap\", async () => {\n        // i'm not crazy about this behaviour (not really functor-law like)\n        // but it's JS we're dealing with in the end :-(\n        return ensureFailedWithValue(\n            \"oops\", Future.ok(5).flatMap<number>(x => {throw \"oops\"}).toPromise());\n    });\n    it(\"called only once if triggered twice\", async () => {\n        let i=0;\n        const f = Future.ofPromiseCtor(done=>{++i; done(1);});\n        await f;\n        assert.deepEqual(1, i);\n        await f;\n        assert.deepEqual(1, i);\n    });\n});\ndescribe(\"Future.map*\", () => {\n    it(\"map triggers and works\", async () => {\n        let i=0;\n        const f = Future.ofPromiseCtor<number>(done=>done(++i)).map(x => x*2);\n        assert.deepEqual(1, i);\n        assert.deepEqual(2, await f);\n    });\n    it(\"map doesn't flatten promises\", async () => {\n        let i=0;\n        const f = Future.ofPromiseCtor<number>(done=>done(5))\n            .map(x => new Promise((r,f)=>r(x+1)));\n        assert.ok((<any>await f).then !== null); // should get a promise out\n    });\n    it(\"map doesn't flatten futures\", async () => {\n        let i=0;\n        const f = Future.ok(5).map(x => Future.ofPromiseCtor(done=>done(x+1)));\n        assert.ok((<any>await f).getPromise !== null); // should get a future out\n    });\n    it(\"mapFailure works\", async () => {\n        return ensureFailedWithValue(\n            \"SORRY\", Future.failed(\"sorry\").mapFailure(err => err.toUpperCase()).toPromise());\n    });\n    it(\"mapFailure is a nop on successful futures\", async () => {\n        assert.deepEqual(5, await Future.ok(5).mapFailure(_ => \"oops\"));\n    });\n    it(\"flatMap does flatten futures\", async () => {\n        const f = Future.ok(5).flatMap(x => Future.ofPromiseCtor(done=>done(x+1)));\n        assert.ok((<any>await f).getPromise === undefined); // shouldn't get a future out\n        assert.deepEqual(6, await f);\n    });\n});\ndescribe(\"Future.liftA*\", () => {\n    it(\"applies liftAp properly\", async () => {\n        const fn = (x:{a:number,b:number}) => ({a:x.a+1,b:x.b-2});\n        const computationPromise =\n            Future.liftAp(fn)({a:Future.ok(5), b:Future.ofPromiseCtor(done=>done(12))});\n        assert.deepEqual({a:6,b:10}, await computationPromise);\n    });\n    it(\"applies liftAp properly in case of failure\", async () => {\n        const fn = (x:{a:number,b:number}) => ({a:x.a+1,b:x.b-2});\n        const computationPromise =\n            Future.liftAp(fn)({a:Future.ok(5), b:Future.failed(\"sorry\")});\n        return ensureFailedWithValue(\"sorry\", computationPromise.toPromise());\n    });\n    it(\"applies liftA2 properly\", async () => {\n        const fn = (a:number,b:number) => ({a:a+1,b:b-2});\n        const computationPromise =\n            Future.liftA2(fn)(Future.ok(5), Future.ofPromiseCtor(done=>done(12)));\n        assert.deepEqual({a:6,b:10}, await computationPromise);\n    });\n    it(\"applies liftA2 properly in case of failure\", async () => {\n        const fn = (a:number,b:number) => ({a:a+1,b:b-2});\n        const computationPromise =\n            Future.liftA2(fn)(Future.ok(5), Future.failed(\"sorry\"));\n        return ensureFailedWithValue(\"sorry\", computationPromise.toPromise());\n    });\n});\ndescribe(\"Future.lift\", () => {\n    it(\"lifts a simple promise\", async () => {\n        const fn = (x:number) => Promise.resolve(x+1);\n        const fn2 = Future.lift(fn);\n        assert.equal(5, await fn2(4));\n    });\n    it(\"lifts a failing promise\", async () => {\n        const fn = (x:number) => Promise.reject(x+1);\n        const fn2 = Future.lift(fn);\n        try {\n            await fn2(4);\n            assert.ok(false);\n        } catch (ex) {\n            assert.equal(5, ex);\n        }\n\n    });\n});\ndescribe(\"Future.traverse\", () => {\n    it(\"traverses properly\", async () => {\n        assert.deepEqual([1,2,3], await Future.traverse([1,2,3], Future.ok).map(v => v.toArray()));\n    });\n    it(\"traverses properly in case of failure\", async () => {\n        return ensureFailedWithValue(\"3\", Future.traverse(\n            [1, 2, 3], x => Future.ofPromiseCtor(() => { if (x < 3) { x } else { throw x; } }))\n                                     .map(v => v.toArray()).toPromise());\n    });\n    it(\"handles failures properly also with maxConcurrent>1\", async () => {\n        return ensureFailedWithValue(\"3\", Future.traverse(\n            [1, 2, 3],\n            x => Future.ofPromiseCtor(() => { if (x < 3) { x } else { throw x; } }),\n            {maxConcurrent:3}\n        ).map(v => v.toArray()).toPromise());\n    });\n    it(\"honors maxConcurrent\", async () => {\n        const checkMaxConcurrent = async (input: number[], maxC: number) => {\n            type Operation = {type:string, input: number, time: number};\n            const operationsOrder:Operation[] = [];\n            const mkFuture =\n                (i:number):Future<number> =>\n                Future.ofPromiseCtor(done => {\n                    operationsOrder.push({type:\"start\", input: i, time: new Date().getTime()});\n                    setTimeout(v => {\n                        operationsOrder.push({type:\"finish\", input: i, time: new Date().getTime()});\n                        done(v);\n                    }, Math.random()*50,i*2)})\n            const r = await Future.traverse(input, mkFuture, {maxConcurrent:maxC});\n            assert.ok(Vector.ofIterable(input.map(x=>x*2)).equals(r));\n            const concurrent = Vector.ofIterable(operationsOrder)\n                .scanLeft(0, (soFar,cur) => soFar + (cur.type === 'start' ? 1 : -1));\n            // we should start at 0 ops, then start/stop for each item in the list.\n            assert.equal(input.length*2+1, concurrent.length());\n            const expectedConc = [];\n            // number of concurrent increases from 0\n            for (let i=0;i<=maxC;i++) {\n                expectedConc.push(i);\n            }\n            // constantly switching between maxC & maxC-1 as\n            // futures complete\n            let flip = true;\n            for (let i=maxC;i<input.length*2-maxC-1;i++) {\n                expectedConc.push(flip ? (maxC-1) : maxC);\n                flip = !flip;\n            }\n            // decrease back to 0\n            for (let i=maxC;i>=0;i--) {\n                expectedConc.push(i);\n            }\n            assert.deepEqual(expectedConc, concurrent.toArray());\n        };\n        checkMaxConcurrent([1,2,3,4,5,6,7,8,9,10,11,12,13], 3);\n        checkMaxConcurrent([1,2,3,4,5,6,7,8,9], 6);\n    });\n});\ndescribe(\"Future.sequence\", () => {\n    it(\"sequences properly\", async () => {\n        assert.deepEqual([1,2,3], await Future.sequence(\n            [Future.ok(1),Future.ok(2),Future.ok(3)]).map(v => v.toArray()));\n    });\n    it(\"sequences properly in case of failure\", async () => {\n        return ensureFailedWithValue(\"3\", Future.sequence(\n            [Future.ok(1), Future.ok(2), Future.failed(\"3\")])\n            .map(v => v.toArray()).toPromise());\n    });\n});\ndescribe(\"Future.firstCompletedOf\", () => {\n    // TODO in these tests check the elapsed time is short!\n    it(\"returns the one finishing the first\", async () => {\n        assert.deepEqual(1, await Future.firstCompletedOf(\n            [Future.ofPromiseCtor(done=>setTimeout(done,100,3)), Future.ok(1)]));\n    });\n    it(\"returns the one finishing even if it's a failure\", async () => {\n        return ensureFailedWithValue(\"3\", Future.firstCompletedOf(\n            [Future.ofPromiseCtor(done=>setTimeout(done, 100, 1)), Future.failed(\"3\")]).toPromise());\n    });\n});\ndescribe(\"Future.firstSuccessfulOf\", () => {\n    // TODO in these tests check the elapsed time is short!\n    it(\"returns the one finishing the first\", async () => {\n        assert.deepEqual(1, await Future.firstSuccessfulOf(\n            [Future.ofPromiseCtor(done=>setTimeout(done,100,3)), Future.ok(1)]));\n    });\n    it(\"returns the one finishing slower if the other one is a failure\", async () => {\n        const v = await Future.firstSuccessfulOf(\n            [Future.ofPromiseCtor(done=>setTimeout(done, 20, 1)), Future.failed(\"3\")]).toPromise();\n       assert.equal(1, v);\n    });\n});\ndescribe(\"Future.filter\", () => {\n    it(\"is a nop if no filter to do\", async () => {\n        assert.deepEqual(5, await Future.ok(5).filter(x => x >= 2, v => \"value was \" + v));\n    });\n    it(\"is a nop if the future was failed\", async () => {\n        return ensureFailedWithValue(\n            \"already bad\", Future.failed<number>(\"already bad\").filter(x => x >= 2, v => \"value was \" + v).toPromise());\n    });\n    it(\"does filter if it applies\", async () => {\n        return ensureFailedWithValue(\n            \"value was 1\", Future.ok(1).filter(x => x >= 2, v => \"value was \" + v).toPromise());\n    });\n});\ndescribe(\"Future.recoverWith\", () => {\n    it(\"is a nop if the first promise succeeds, even if it's slower\", async () => {\n        assert.deepEqual(1, await Future.ofPromiseCtor(done => setTimeout(done, 50, 1))\n                         .recoverWith(_=>Future.ok(2)));\n    });\n    it(\"falls back to the second promise in case the first one fails\", async () => {\n        assert.deepEqual(\"oops\", await Future.failed(\"oops\").recoverWith(Future.ok));\n    });\n    it(\"falls back to the second promise in case both fail\", async () => {\n        return ensureFailedWithValue(\n            \"still not\",\n            Future.failed(\"oops\")\n                .recoverWith(_ => Future.failed(\"still not\")).toPromise());\n    });\n});\ndescribe(\"Future.find\", () => {\n    it(\"returns the first future if it matches\", async () => {\n        const actual = await Future.find([Future.ok(2)], x => x>=0);\n        assert.ok(Option.of(2).equals(actual));\n    });\n    it(\"returns nothing if no future matches\", async () => {\n        const actual = await Future.find([Future.ok(-1)], x => x>=0);\n        assert.ok(Option.none().equals(actual));\n    });\n    it(\"returns nothing if all futures fail\", async () => {\n        const actual = await Future.find([Future.failed<number>(-1)], x => x>=0);\n        assert.ok(Option.none().equals(actual));\n    });\n    it(\"returns the first matching\", async () => {\n        const actual = await Future.find([\n            Future.ok(-1),\n            Future.failed<number>(5),\n            Future.ok(-3),\n            Future.ok(6),\n            Future.ok(7)], x => x>=0);\n        assert.ok(Option.of(6).equals(actual));\n    });\n    it(\"doesn't wait if there's a success\", async () => {\n        let waited = false;\n        const actual = await Future.find([\n            Future.ok(-1),\n            Future.failed<number>(5),\n            Future.ok(-3),\n            Future.ofPromiseCtor<number>(\n                done => setTimeout(() => {waited = true; done(6);}, 60)),\n            Future.ok(7)], x => x>=0);\n        assert.ok(Option.of(7).equals(actual));\n        assert.ok(!waited);\n    });\n});\ndescribe(\"Future.on*\", () => {\n    it(\"calls onSuccess when it should\", async () => {\n        let v = 0;\n        await Future.ok(5)\n            .onSuccess(x => v = x);\n        assert.deepEqual(5, v);\n    });\n    it(\"doesn't calls onSuccess when it shouldn't\", async () => {\n        let v = 0;\n        let failed = false;\n        try {\n            await Future.failed<number>(5)\n                .onSuccess(x => v = x);\n        } catch {\n            failed = true;\n        }\n        assert.ok(failed);\n        assert.deepEqual(0, v);\n    });\n    it(\"doesn't call onFailure when it shouldn't\", async () => {\n        let v = 0;\n        await Future.ok(5)\n            .onFailure(x => v = x);\n        assert.deepEqual(0, v);\n    });\n    it(\"calls onFailure when it should\", async () => {\n        let v = 0;\n        let failed = false;\n        try {\n            await Future.failed(5)\n                .onFailure(x => v = x);\n        } catch {\n            failed = true;\n        }\n        assert.ok(failed);\n        assert.deepEqual(5, v);\n    });\n    it(\"calls onComplete on success\", async () => {\n        let v:any = undefined;\n        await Future.ok(5)\n            .onComplete(x => v = x);\n        assert.ok(Either.right(5).equals(v));\n    });\n    it(\"calls onComplete on failure\", async () => {\n        let v:any = undefined;\n        try {\n            await Future.failed(5)\n                .onComplete(x => v = x);\n        } catch { }\n        assert.ok(Either.left(5).equals(v));\n    });\n});\n\ndescribe(\"Future do notation*\", () => {\n    it(\"do notation creates a successful future\", async () => {\n        const f1 = Future.ok(1)\n        const f2 = Future.ok(2)\n      \n        const f3 = Future.do(async () => {\n            const v1 = await f1\n            const v2 = await f2\n            return v1 + v2\n        })\n      \n        const v3 = await f3\n        assert.deepEqual(3, v3);\n    });\n\n    it(\"do notation creates a failed future\", async () => {\n        const f1 = Future.ok(1)\n        const f2 = Future.failed<number>(\"bad number\")\n        \n        const f3 = Future.do(async () => {\n            const v1 = await f1\n            const v2 = await f2\n            return v1 + v2\n        })\n\n        try {\n          const v3 = await f3\n          assert.fail(\"Error: Future must fail\")\n\n        } catch (error) {\n          assert.deepEqual(error, \"bad number\");\n        }\n    });\n});\n"
  },
  {
    "path": "tests/HashMap.ts",
    "content": "import { HashMap } from \"../src/HashMap\";\nimport { HashSet } from \"../src/HashSet\";\nimport { Vector } from \"../src/Vector\";\nimport { LinkedList } from \"../src/LinkedList\";\nimport { Option } from \"../src/Option\";\nimport { Stream } from \"../src/Stream\";\nimport { Tuple2 } from \"../src/Tuple2\";\nimport { fieldsHashCode, HasEquals, getHashCode } from \"../src/Comparison\";\nimport { MyClass} from \"./SampleData\";\nimport { assertFailCompile } from \"./TestHelpers\";\nimport * as assert from 'assert'\n\ntype MyEnum = \"a\" | \"b\" | \"c\";\n\ndescribe(\"hashmap construction basic sanity tests\", () => {\n    it(\"should overwrite values with the same key\", () => assert.ok(\n        HashMap.empty<number,string>().put(5, \"test\").put(5, \"test1\")\n            .equals(HashMap.empty<number,string>().put(5, \"test1\"))));\n    it(\"should overwrite values with the same key with custom types\", () => assert.ok(\n        HashMap.empty<MyClass,string>()\n            .put(new MyClass(\"a\", 1), \"test\")\n            .put(new MyClass(\"a\", 1), \"test1\")\n            .put(new MyClass(\"a\", 2), \"test1\").equals(\n                HashMap.empty<MyClass,string>()\n                    .put(new MyClass(\"a\", 1), \"test1\")\n                    .put(new MyClass(\"a\", 2), \"test1\"))));\n\n    it(\"should overwrite values with the same key with custom types when created with of()\", () => assert.ok(\n        HashMap.empty<MyClass,string>()\n            .put(new MyClass(\"a\", 1), \"test\")\n            .put(new MyClass(\"a\", 1), \"test1\")\n            .put(new MyClass(\"a\", 2), \"test1\").equals(\n                HashMap.of<MyClass,string>([new MyClass(\"a\", 1), \"test1\"])\n                    .put(new MyClass(\"a\", 2), \"test1\"))));\n\n    it(\"should overwrite values with the same key with custom types when created with ofIterable()\", () => assert.ok(\n        HashMap.ofIterable<MyClass,string>(<[MyClass,string][]>[\n            [new MyClass(\"a\", 1), \"test\"],\n            [new MyClass(\"a\", 2), \"test1\"]])\n            .put(new MyClass(\"a\", 1), \"test1\")\n            .equals(\n                HashMap.of<MyClass,string>([new MyClass(\"a\", 1), \"test1\"])\n                    .put(new MyClass(\"a\", 2), \"test1\"))));\n\n    it(\"should support map as a key itself\", () => assert.ok(\n        HashMap.empty<HashMap<string,number>, number>()\n            .put(HashMap.empty<string,number>().put(\"hello\", 1), 6)\n            .put(HashMap.empty<string,number>().put(\"hello\", 1), 7)\n            .put(HashMap.empty<string,number>().put(\"bye\", 1), 7)\n            .equals(\n                HashMap.empty<HashMap<string,number>, number>()\n                    .put(HashMap.empty<string,number>().put(\"hello\", 1), 7)\n                    .put(HashMap.empty<string,number>().put(\"bye\", 1), 7))));\n\n    it(\"should build with of\", () => assert.ok(\n        HashMap.empty<number,string>().put(1,\"a\").put(2,\"b\").equals(\n            HashMap.of([1,\"a\"],[2,\"b\"]))));\n    it(\"should build with ofIterable\", () => assert.ok(\n        HashMap.empty<number,string>().put(1,\"a\").put(2,\"b\").equals(\n            HashMap.ofIterable(Vector.of<[number,string]>([1,\"a\"],[2,\"b\"])))));\n    it(\"should put with merge\", () => assert.ok(\n        HashMap.empty<number,string>()\n            .put(5,\"test\").putWithMerge(5,\"a\",(a,b)=>a+b)\n            .equals(HashMap.empty<number,string>().put(5, \"testa\"))));\n    it(\"should enforce the callback parameter order on put with merge\", () => assert.ok(\n        HashMap.of<number,string>([1,\"2\"],[2,\"4\"])\n            .putWithMerge(2,\"a\",(a,b)=>a)\n            .equals(HashMap.of<number,string>([1,\"2\"],[2,\"4\"]))));\n    it(\"should mergeWith\", () => assert.ok(\n        HashMap.empty<number,string>().put(1,\"a\").put(2,\"bc\").put(3,\"d\")\n            .equals(HashMap.empty<number,string>().put(1,\"a\").put(2,\"b\")\n                    .mergeWith(HashMap.empty<number,string>().put(2,\"c\").put(3,\"d\"), (v1,v2)=>v1+v2))));\n    it(\"should enforce the callback parameter order on mergeWith\", () => assert.ok(\n        HashMap.of<number,number>([1,2],[2,4],[3,5]).equals(\n            HashMap.of<number,number>([1,2],[2,4]).mergeWith(\n                HashMap.of([1,3],[2,2],[3,5]), (x,y)=>x))));\n    it(\"should remove keys\", () => assert.ok(\n        HashMap.of<number,string>([2,\"b\"]).equals(\n            HashMap.of<number,string>([1,\"a\"],[2,\"b\"]).remove(1))));\n    it(\"should allow to remove an inexisting key\", () => assert.ok(\n        HashMap.of<number,string>([1,\"a\"],[2,\"b\"]).equals(\n            HashMap.of<number,string>([1,\"a\"],[2,\"b\"]).remove(3))));\n    it(\"should allow to remove from the empty map\", () => assert.ok(\n        HashMap.empty<number,string>().equals(\n            HashMap.of<number,string>().remove(1))));\n    it(\"should build from a string object dictionary\", () => assert.ok(\n        HashMap.of<string,number>([\"a\",1],[\"b\",2]).equals(\n            HashMap.ofObjectDictionary<number>({a:1,b:2}))));\n    it(\"should build from an int object dictionary\", () => assert.ok(\n        HashMap.of<string,string>([\"1\",\"a\"],[\"2\",\"b\"]).equals(\n            HashMap.ofObjectDictionary<string>({1:\"a\",2:\"b\"}))));\n    it(\"should strip dictionary values with undefined\", () => assert.ok(\n        HashMap.of<string,string>([\"1\",\"a\"]).equals(\n            HashMap.ofObjectDictionary<string>({1:\"a\",2:undefined}))));\n    it(\"should build from an enum object dictionary\", () => {\n        const s: {[TKey in MyEnum]:number} = {\"a\":1,\"b\":2,\"c\":3};\n        const got = HashMap.ofObjectDictionary<number>(s);\n        assert.ok(HashMap.of<string,number>([\"a\",1],[\"b\",2],[\"c\",3]).equals(got));\n    });\n    it(\"should build from a partial enum object dictionary\", () => {\n        const s: {[TKey in MyEnum]?:number} = {\"a\":1};\n        const got = HashMap.ofObjectDictionary<number>(s);\n        assert.ok(HashMap.of<string,number>([\"a\",1]).equals(got));\n    });\n    it(\"should support findAny on an empty HashMap\", () => {\n        assert.ok(HashMap.empty<number,string>().findAny(x => true).isNone());\n    })\n    it(\"should fail at runtime on key without equality\", () => assert.throws(() =>\n        HashMap.empty<any,string>().put({field1:'test', field2:-1}, \"value1\")));\n});\n\ndescribe(\"hashmap equality\", () => {\n    it(\"empty should be equal with empty\", () =>\n       assert.ok(HashMap.empty<number,string>().equals(HashMap.empty<number,string>())));\n    it(\"non empty should be not be equal with empty\", () =>\n       assert.ok(!HashMap.empty<number,string>().put(1,\"t\").equals(HashMap.empty<number,string>())));\n    it(\"empty should be not be equal with non empty\", () =>\n       assert.ok(!HashMap.empty<number,string>().equals(HashMap.empty<number,string>().put(1,\"t\"))));\n    it(\"doesn't throw when given another type on equals\", () => assert.equal(\n        false, HashMap.empty().put(1,2).equals(<any>[1,2])));\n    it(\"doesn't throw when given null on equals\", () => assert.equal(\n        false, HashMap.empty().put(1,2).equals(<any>null)));\n    it(\"empty doesn't throw when given another type on equals\", () => assert.equal(\n        false, HashMap.empty().equals(<any>[1,2])));\n    it(\"empty doesn't throw when given null on equals\", () => assert.equal(\n        false, HashMap.empty().equals(<any>null)));\n    it(\"should refuse keys which don't offer true equality (neither equals nor hashcode)\", () => assert.throws(\n        () => HashMap.of([<any>{name:\"\"}, 1])));\n    it(\"should refuse keys which don't offer true equality (no hashcode)\", () => assert.throws(\n        () => HashMap.of([<any>{name:\"\",equals:(x:any,y:any)=>true},1])));\n    it(\"should refuse keys which don't offer true equality (no equals)\", () => assert.throws(\n        () => HashMap.of([<any>{name:\"\",hashCode:()=>1},1])));\n    it(\"should refuse keys which don't offer true equality\", () => assert.throws(\n        () => HashMap.of([Vector.of([1]),\"value\"])));\n    it(\"should refuse keys which don't offer true equality (vector)\", () => assert.throws(\n        () => HashMap.empty().put(Vector.of(Vector.of([1])),\"value\")));\n    it(\"should refuse keys which don't offer true equality (stream)\", () => assert.throws(\n        () => HashMap.of([Stream.of([1]), \"value\"])));\n    it(\"should refuse keys which don't offer true equality (option)\", () => assert.throws(\n        // @ts-ignore\n        () => HashMap.of([Option.of([1]), \"value\"])));\n    it(\"should refuse keys which don't offer true equality (tuple2)\", () => assert.throws(\n        () => HashMap.of([Tuple2.of(1,Vector.of([1])), \"value\"])));\n    it(\"should refuse keys which don't offer true equality (hashmap)\", () => assert.throws(\n        () => HashMap.of([HashMap.of([\"a\",[1]]), \"value\"])));\n    it(\"should fail compilation on an obviously bad key type\", () =>\n       assertFailCompile(\n           \"HashMap.of([[1], 'test'])\", \"is not assignable to\"));\n    it(\"should not have trivial hashcode collisions #1\", () =>\n        assert.equal(false, HashMap.of([\"48\", 1], [\"49\", 2], [\"50\", 3], [\"51\", 4]).hashCode()\n            == HashMap.of([\"49\", 2], [\"50\", 3], [\"51\", 4]).hashCode()));\n    it(\"should not have trivial hashcode collisions #2\", () =>\n        assert.equal(false, HashMap.of([\"48\", 1], [\"49\", 2], [\"50\", 3], [\"51\", 4]).hashCode()\n            == HashMap.of([\"49345678\", 2], [\"50\", 3], [\"51\", 4]).hashCode()));\n    it(\"should calculate the same hashcode if the values are provided in a different order\", () => {\n        const a = HashMap.of([\"a\", 1], [\"b\", 0]);\n        const b = HashMap.of([\"b\", 0], [\"a\", 1]);\n\n        assert.equal(a.hashCode(), b.hashCode());\n    });\n    it(\"should not have hashcode collisions when duplicate values are swapped between keys\", () => {\n        const a = HashMap.of([\"a\", 1], [\"b\", 0]);\n        const b = HashMap.of([\"a\", 0], [\"b\", 1]);\n\n        assert.equal(false, a.hashCode() === b.hashCode());\n    });\n    it(\"should generate hashCodes for values implementing HasEquals\", () => {\n        class TestClass implements HasEquals {\n            constructor(\n                public value: string\n            ) {}\n\n            public equals(other: unknown): boolean {\n                return this.hashCode() === getHashCode(other);\n            }\n\n            public hashCode(): number {\n                return fieldsHashCode(this.value)\n            }\n        }\n\n        const a = HashMap.of([\"48\", new TestClass(\"foo\")]).hashCode();\n        const b = HashMap.of([\"48\", new TestClass(\"bar\")]).hashCode();\n\n        assert.equal(false, a == b);\n    });\n})\n\ndescribe(\"hashmap - toString should be nicely formatted\", () => {\n    it(\"should format strings and numbers\", () => assert.equal(\n       \"HashMap(key1: 6, key2: 7, key3: null)\",\n        \"\"+HashMap.empty<string,number|null>().put(\"key1\", 6).put(\"key2\", 7).put(\"key3\",null)));\n    it(\"should format custom classes\", () => assert.equal(\n       \"HashMap(key1: {field1: test, field2: -1})\",\n         \"\"+HashMap.empty<string,MyClass>().put(\"key1\", new MyClass('test', -1))));\n   it(\"should format cust class keys as well\", () => assert.equal(\n        \"HashMap({\\\"field1\\\":\\\"test\\\",\\\"field2\\\":-1}: 'value1')\",\n        \"\"+HashMap.empty<any,string>().put({\n            field1:'test',\n            field2:-1,\n            equals(this:any, b:any) { return this.field1===b.field1 && this.field2===b.field2 },\n            hashCode(this:any) { return fieldsHashCode(this.field1, this.field2);}\n        }, \"value1\")));\n});\n\ndescribe(\"hashmap extract values\", () => {\n    it(\"should retrieve values\", () => assert.ok(\n        HashMap.empty<string,number>().put(\"key1\", 6).get(\"key1\").contains(6)));\n    it(\"should not find missing values\", () => assert.ok(\n        HashMap.empty<string,number>().put(\"key1\", 6).get(\"key2\").isNone()));\n    it(\"should retrieve nulls\", () => assert.ok(\n        HashMap.empty<string,number|null>().put(\"key1\", null).get(\"key1\").contains(null)));\n    it(\"should get empty keySet\", () => assert.ok(\n        HashSet.empty<string>().equals(HashMap.empty<string,string>().keySet())));\n    it(\"should get non-empty keySet\", () => assert.ok(\n        HashSet.of(\"a\",\"c\").equals(HashMap.empty<string,string>().put(\"a\",\"b\").put(\"c\",\"d\").keySet())));\n    it(\"should get empty valueIterable\", () => assert.ok(\n        HashSet.empty<string>().equals(HashSet.ofIterable(HashMap.empty<string,string>().valueIterable()))));\n    it(\"should get non-empty valueIterable\", () => assert.ok(\n        HashSet.of(\"b\",\"d\").equals(HashSet.ofIterable(HashMap.empty<string,string>().put(\"a\",\"b\").put(\"c\",\"d\").valueIterable()))));\n    it(\"should allow iteration of valueIterable more than once\", () => {\n        const i = HashMap.empty<string, string>().put(\"a\", \"b\").put(\"c\", \"d\").valueIterable();\n        HashSet.of(\"b\", \"d\").equals(HashSet.ofIterable(Array.from(i)));\n        HashSet.of(\"b\", \"d\").equals(HashSet.ofIterable(Array.from(i)));\n    })\n    it(\"supports iterator\", () => {\n        let total = 0;\n        let letters = [];\n        const iterator = HashMap.empty<string,number>()\n            .put(\"a\",1).put(\"b\",6).put(\"c\",3)[Symbol.iterator]();\n        let curItem = iterator.next();\n        while (!curItem.done) {\n            letters.push(curItem.value[0]);\n            total += curItem.value[1];\n            curItem = iterator.next();\n        }\n        assert.equal(10, total);\n        letters.sort();\n        assert.deepEqual([\"a\",\"b\",\"c\"], letters);\n    });\n    it(\"supports empty iterator\", () => {\n        let total = 0;\n        let letters = [];\n        const iterator = HashMap.empty<string,number>()[Symbol.iterator]();\n        let curItem = iterator.next();\n        while (!curItem.done) {\n            letters.push(curItem.value[0]);\n            total += curItem.value[1];\n            curItem = iterator.next();\n        }\n        assert.equal(0, total);\n        assert.deepEqual([], letters);\n    });\n    it(\"correct returns single positive case\", () => assert.deepEqual(\n        [5,\"a\"], HashMap.of([5,\"a\"]).single().getOrThrow()));\n    it(\"correct returns single negative case\", () => assert.ok(\n        HashMap.of([5,\"a\"],[6,\"b\"]).single().isNone()));\n    it(\"correct returns single empty map\", () => assert.ok(\n        HashMap.empty<number,string>().single().isNone()));\n    it(\"supports forEach correctly\", () => {\n        const list: Array<[number,string]> = [];\n        HashMap.of([5,\"a\"],[6,\"b\"]).forEach(x => list.push(x));\n        assert.deepEqual([[5,\"a\"],[6,\"b\"]],\n                         Vector.ofIterable(list).sortOn(x=>x[0]).toArray());\n    });\n    it(\"supports forEach correctly -- empty map\", () => {\n        let count = 0;\n        HashMap.empty<number,string>().forEach(x => {count += 1});\n        assert.equal(0, count);\n    });\n});\n\ndescribe(\"hashmap transformation\", () => {\n    it(\"should transform through map\", () => assert.ok(\n        HashMap.empty<number,string>().put(12,\"key1\").put(6,\"key2\").equals(\n        HashMap.empty<string,number>().put(\"key1\",6).put(\"key2\", 3).map((k,v) => [v*2,k]))));\n    it(\"should transform through empty map\", () => assert.ok(\n        HashMap.empty<number,string>().equals(\n        HashMap.empty<string,number>().map((k,v) => [v*2,k]))));\n    it(\"flatMap works\", () => assert.deepEqual(\n        [[\"a\",1],[\"b\",2],[\"c\",3],[\"aa\",5],[\"bb\",6],[\"cc\",7]],\n            HashMap.of<string,number>([\"a\",1],[\"b\",2],[\"c\",3])\n                .flatMap((k,v)=>HashMap.of<string,number>([k+k,v+4],[k,v])).toVector().sortOn(x=>x[1]).toArray()));\n    it(\"should transform through mapValues\", () => assert.ok(\n        HashMap.empty<string,number>().put(\"key1\",12).put(\"key2\",6).equals(\n        HashMap.empty<string,number>().put(\"key1\",6).put(\"key2\", 3).mapValues(v => v*2))));\n    it(\"should transform through empty mapValues\", () => assert.ok(\n        HashMap.empty<string,number>().equals(\n        HashMap.empty<string,number>().mapValues(v => v*2))));\n    it(\"should transform non-empty to vector\", () => assert.deepEqual(\n        [[\"a\",1], [\"b\",2]],\n        HashMap.empty<string,number>().put(\"a\",1).put(\"b\",2).toVector().toArray()));\n    it(\"should transform empty to vector\", () => assert.deepEqual(\n        [],\n        HashMap.empty<string,number>().toVector().toArray()));\n    it(\"should transform non-empty to array\", () => assert.deepEqual(\n        [[\"a\",1], [\"b\",2]],\n        HashMap.empty<string,number>().put(\"a\",1).put(\"b\",2).toArray()));\n    it(\"should transform empty to array\", () => assert.deepEqual(\n        [],\n        HashMap.empty<string,number>().toArray()));\n    it(\"should transform non-empty to ObjectDictionary\", () => assert.deepEqual(\n        {\"a\":1, \"b\":2},\n        HashMap.empty<string,number>().put(\"a\",1).put(\"b\",2).toObjectDictionary(x=>x)));\n    it(\"should transform empty to ObjectDictionary\", () => assert.deepEqual(\n        {},\n        HashMap.empty<string,number>().toObjectDictionary(x=>x)));\n    it(\"should filter properly\", () => assert.deepEqual(\n        [[1,\"a\"],[3,\"c\"]], HashMap.empty<number,string>()\n            .put(1,\"a\").put(2,\"b\").put(3,\"c\").put(4,\"d\").filter((k,v) => k%2!=0).toArray()));\n    it(\"should filter empty properly\", () => assert.deepEqual(\n        [], HashMap.empty().toArray()));\n    it(\"keeps the custom equality even after filter\", () => assert.ok(\n        HashMap.empty<MyClass,string>()\n            .put(new MyClass(\"a\", 1), \"test\")\n            .put(new MyClass(\"a\", 2), \"test1\").equals(\n                HashMap.of<MyClass,string>([new MyClass(\"a\", 1), \"test1\"])\n                    .filter(x => true)\n                    .put(new MyClass(\"a\", 1), \"test\")\n                    .put(new MyClass(\"a\", 2), \"test1\"))));\n    it(\"should support allMatch, positive case\", () => assert.ok(\n        HashMap.empty<number,string>().put(1,\"a\").put(2,\"b\").allMatch((k,v) => k > 0)));\n    it(\"should support allMatch, negative case\", () => assert.ok(\n        !HashMap.empty<number,string>().put(1,\"a\").put(2,\"b\").allMatch((k,v) => k < 0)));\n    it(\"should support allMatch, empty map\", () => assert.ok(\n        HashMap.empty<number,string>().allMatch((k,v) => k > 0)));\n    it(\"should support anyMatch, positive case\", () => assert.ok(\n        HashMap.empty<number,string>().put(1,\"a\").put(-1,\"b\").anyMatch((k,v) => k > 0)));\n    it(\"should support anyMatch, negative case\", () => assert.ok(\n        !HashMap.empty<number,string>().put(1,\"a\").put(2,\"b\").anyMatch((k,v) => k < 0)));\n    it(\"should support anyMatch, empty map\", () => assert.ok(\n        !HashMap.empty<number,string>().anyMatch((k,v) => k > 0)));\n    it(\"should support contains, positive case\", () => assert.ok(\n        HashMap.empty<number,string>().put(1,\"a\").put(2,\"b\").contains([2,\"b\"])));\n    it(\"should support contains, negative case\", () => assert.ok(\n        !HashMap.empty<number,string>().put(1,\"a\").put(2,\"b\").contains([2,\"c\"])));\n    it(\"should support contains, empty map\", () => assert.ok(\n        !HashMap.empty<number,string>().contains([2,\"b\"])));\n    it(\"should support containsKey, positive case\", () => assert.ok(\n        HashMap.empty<number,string>().put(1,\"a\").put(2,\"b\").containsKey(2)));\n    it(\"should support containsKey, negative case\", () => assert.ok(\n        !HashMap.empty<number,string>().put(1,\"a\").put(2,\"b\").containsKey(3)));\n    it(\"should support containsKey, empty map\", () => assert.ok(\n        !HashMap.empty<number,string>().containsKey(2)));\n    it(\"should fold correctly\", () => assert.deepEqual(\n        [6,\"c\"], HashMap.of<number,string>([1,\"a\"],[2,\"b\"],[3,\"c\"])\n            .fold([0,\"\"], ([a,b],[c,d])=>[a+c, b>d?b:d])));\n    it(\"should foldLeft correctly\", () => assert.equal(\n        6, HashMap.of([1,\"a\"], [2,\"bb\"], [3,\"ccc\"])\n            .foldLeft(0, (soFar,[item,val])=>soFar+val.length)));\n    it(\"should foldRight correctly\", () => assert.equal(\n        6, HashMap.of([1,\"a\"], [2,\"bb\"], [3,\"ccc\"])\n            .foldRight(0, ([item,value],soFar)=>soFar+value.length)));\n    it(\"should convert to linked list correctly\", () => assert.ok(\n        LinkedList.of(Tuple2.of(\"a\",5),Tuple2.of(\"b\",6)).equals(\n            HashMap.of<string,number>([\"a\",5],[\"b\",6]).toLinkedList().map(Tuple2.ofPair))));\n    it(\"reduce works\", () => assert.deepEqual(\n        [3,\"c\"], HashMap.of<number,string>([1,\"a\"],[2,\"b\"],[3,\"c\"])\n            .reduce((kv1,kv2)=>kv1[0]>kv2[0]?kv1:kv2).getOrThrow()));\n    it(\"reduce works on an empty collection\", () => assert.ok(\n        HashMap.empty<number,string>().reduce((kv1,kv2)=>kv1[0]>kv2[0]?kv1:kv2).isNone()));\n});\n"
  },
  {
    "path": "tests/HashSet.ts",
    "content": "import { HashSet } from \"../src/HashSet\";\nimport { Vector } from \"../src/Vector\";\nimport { Stream } from \"../src/Stream\";\nimport { Option } from \"../src/Option\";\nimport { Tuple2 } from \"../src/Tuple2\";\nimport { HashMap } from \"../src/HashMap\";\nimport { instanceOf, typeOf } from \"../src/Comparison\";\nimport { MyClass, MySubclass } from \"./SampleData\";\nimport { assertFailCompile } from \"./TestHelpers\";\nimport * as CollectionTest from './Collection';\nimport * as assert from 'assert'\n\nCollectionTest.runTests(\n    \"HashSet\", HashSet.of, HashSet.empty);\n\ndescribe(\"hashset construction basic sanity tests\", () => {\n    it(\"should overwrite identical values\", () => assert.ok(\n        HashSet.empty<string>().add(\"test\").add(\"test\")\n            .equals(HashSet.empty<string>().add(\"test\"))));\n\n    it(\"should overwrite identical with custom types\", () => assert.ok(\n        HashSet.empty<MyClass>()\n            .add(new MyClass(\"a\", 1))\n            .add(new MyClass(\"a\", 1))\n            .add(new MyClass(\"a\", 2)).equals(\n                HashSet.empty<MyClass>()\n                    .add(new MyClass(\"a\", 1))\n                    .add(new MyClass(\"a\", 2)))));\n    it(\"should overwrite identical also when built using hashset.of\", () => assert.equal(\n        1, HashSet.of(new MyClass(\"a\",1)).add(new MyClass(\"a\",1)).length()));\n    it(\"should support addAll on a non-empty set\", () => assert.ok(\n        HashSet.of(1,2,3,4).equals(HashSet.of(1,2).addAll([3,4]))));\n    it(\"should support addAll on an empty set\", () => assert.ok(\n        HashSet.of(1,2,3,4).equals(HashSet.empty<number>().addAll([1,2,3,4]))));\n    it(\"should fail at runtime on key without equality\", () => assert.throws(() =>\n        HashSet.empty<any>().add({field1:'test', field2:-1})));\n});\n\ndescribe(\"hashset conversions\", () => {\n    it(\"should convert to array correctly\", () => {\n        assert.deepEqual([1,2,3,4], HashSet.empty<number>()\n                         .add(1).add(2).add(3).add(4).toArray().sort());\n    });\n    it(\"empty should convert to array correctly\", () => {\n        assert.deepEqual([], HashSet.empty<number>().toArray());\n    });\n    it(\"should be created correctly from an array\", () => {\n        assert.deepEqual([\"a\",\"b\",\"c\"], HashSet.ofIterable([\"a\",\"b\",\"c\"]).toArray().sort());\n    });\n    it(\"should be created correctly from a spread\", () => {\n        assert.deepEqual([\"a\",\"b\",\"c\"], HashSet.of(\"a\",\"b\",\"c\").toArray().sort());\n    });\n    it(\"should be displayed in a nice format by toString\", () =>\n       assert.equal(\"HashSet('a', 'b', 'c')\", HashSet.of(\"a\",\"b\",\"c\").toString()));\n    it(\"should be displayed in a nice format by toString even when nulls\", () =>\n       assert.equal(\"HashSet(null)\", HashSet.of(null).toString()));\n    it(\"converts to string using mkString\", () =>\n       assert.equal(\"a|c|null\", HashSet.of(\"a\",null,\"c\").mkString(\"|\")));\n    const testSet = HashSet.of(\n        new MyClass(\"aa\",1), new MyClass(\"aa\",2), new MyClass(\"ba\",1));\n    it(\"converts to array with multiple field sorting descending on field1\", () => {\n        assert.deepEqual([new MyClass(\"ba\",1), new MyClass(\"aa\",1), new MyClass(\"aa\",2)],\n                         testSet.toArray({sortOn:[x=>x.getField2(), {desc:x=>x.getField1()}]}));\n    });\n    it(\"converts to array with multiple field sorting descending on field1\", () => {\n        assert.deepEqual([new MyClass(\"aa\",1), new MyClass(\"ba\",1), new MyClass(\"aa\",2)],\n                         testSet.toArray({sortOn:[x=>x.getField2(), x=>x.getField1()]}));\n    });\n    it(\"converts to array with multiple field sorting descending on field2\", () => {\n        assert.deepEqual([new MyClass(\"aa\",2), new MyClass(\"aa\",1), new MyClass(\"ba\",1)],\n                         testSet.toArray({sortOn:[{desc:x=>x.getField2()}, x=>x.getField1()]}));\n    });\n    it(\"converts to array with multiple field sorting both descending\", () => {\n        assert.deepEqual([new MyClass(\"aa\",2), new MyClass(\"ba\",1), new MyClass(\"aa\",1)],\n                         testSet.toArray({sortOn:[{desc:x=>x.getField2()}, {desc:x=>x.getField1()}]}));\n    });\n});\n\ndescribe(\"hashset access\", () => {\n    it(\"should return true from contains\", () => {\n        assert.ok(HashSet.of(1,2,3).contains(2));\n    });\n    it(\"should return false from contains\", () => {\n        assert.ok(!HashSet.of(1,2,3).contains(4));\n    });\n    it(\"supports iterator\", () => {\n        let total = 0;\n        const iterator = HashSet.of(1,6,3)[Symbol.iterator]();\n        let curItem = iterator.next();\n        while (!curItem.done) {\n            total += curItem.value;\n            curItem = iterator.next();\n        }\n        assert.equal(10, total);\n    });\n    it(\"supports empty iterator\", () => {\n        let total = 0;\n        const iterator = HashSet.empty<number>()[Symbol.iterator]();\n        let curItem = iterator.next();\n        while (!curItem.done) {\n            total += curItem.value;\n        }\n        assert.equal(0, total);\n    })\n    it(\"supports allMatch, positive case\", () => assert.ok(\n        HashSet.of(2,4,8).allMatch(x => x%2 === 0)));\n    it(\"supports allMatch, negative case\", () => assert.ok(\n        !HashSet.of(2,5,8).allMatch(x => x%2 === 0)));\n    it(\"supports allMatch, empty HashSet\", () => assert.ok(\n        HashSet.empty<number>().allMatch(x => x%2 === 0)));\n    it(\"supports anyMatch, positive case\", () => assert.ok(\n        HashSet.of(3,5,8).anyMatch(x => x%2 === 0)));\n    it(\"supports anyMatch, negative case\", () => assert.ok(\n        !HashSet.of(3,5,9).anyMatch(x => x%2 === 0)));\n    it(\"supports anyMatch, empty HashSet\", () => assert.ok(\n        !HashSet.empty<number>().anyMatch(x => x%2 === 0)));\n    it(\"correct returns single positive case\", () => assert.equal(\n        5, HashSet.of(5).single().getOrThrow()));\n    it(\"correct returns single negative case\", () => assert.ok(\n        HashSet.of(5,6).single().isNone()));\n    it(\"correct returns single empty seq\", () => assert.ok(\n        HashSet.empty().single().isNone()));\n    it(\"correctly partitions also after prepend\", () => assert.deepEqual(\n        [[1,3,5,7],[2,4,6,8]],\n        HashSet.of(2,3,4,5,6,7,8).add(1).partition(x => x%2!==0)\n            .map(v => v.toVector().sortOn(x=>x).toArray())));\n    it(\"correctly infers the more precise left type on partition in case of typeguard\", () => {\n        // just checking that this compiles. 'charAt' is available on strings not numbers.\n        // the intersect is to make sure that partition returns me a HashSet\n        // not a Collection or something less precise than HashSet.\n        HashSet.of<string|number>(1,\"test\",2,\"a\")\n            .partition(typeOf(\"string\"))[0]\n            .intersect(HashSet.of<string>(\"a\"))\n            .single().getOrThrow().charAt(0);\n    });\n    it(\"correctly infers the more precise type on allMatch in case of typeguard\", () => {\n        // just checking that this compiles. 'charAt' is available on strings not numbers.\n        const v = HashSet.of<string|number>(\"test\");\n        if (v.allMatch(typeOf(\"string\"))) {\n            v.single().getOrThrow().charAt(0);\n        }\n    });\n    it(\"supports forEach, non empty set\", () => {\n        const list: number[] = [];\n        HashSet.of(1,2,3,2).forEach(x => list.push(x));\n        assert.deepEqual([1,2,3], list.sort());\n    });\n    it(\"supports forEach, empty set\", () => {\n        let i = 0;\n        HashSet.empty<number>().forEach(x=>i+=1);\n        assert.equal(0, i);\n    });\n});\n\ndescribe(\"hashset equality\", () => {\n    it(\"doesn't throw when given another type on equals\", () => assert.equal(\n        false, HashSet.of(1).equals(<any>[1,2])));\n    it(\"doesn't throw when given null on equals\", () => assert.equal(\n        false, HashSet.of(1).equals(<any>null)));\n    it(\"should refuse elements which don't offer true equality\", () => assert.throws(\n        () => HashSet.of(Vector.of([1]))));\n    it(\"should refuse elements which don't offer true equality (neither equals nor hashcode)\", () => assert.throws(\n        () => HashSet.of(<any>{name:\"\"})));\n    it(\"should refuse elements which don't offer true equality (no hashcode)\", () => assert.throws(\n        () => HashSet.of(<any>{name:\"\",equals:(x:any,y:any)=>true})));\n    it(\"should refuse elements which don't offer true equality (no equals)\", () => assert.throws(\n        () => HashSet.of(<any>{name:\"\",hashCode:()=>1})));\n    it(\"should refuse elements which don't offer true equality (vector)\", () => assert.throws(\n        () => HashSet.empty().add(Vector.of(Vector.of([1])))));\n    it(\"should refuse elements which don't offer true equality (stream)\", () => assert.throws(\n        () => HashSet.of(Stream.of([1]))));\n    it(\"should refuse elements which don't offer true equality (option)\", () => assert.throws(\n        // @ts-ignore\n        () => HashSet.of(Option.of([1]))));\n    it(\"should refuse elements which don't offer true equality (tuple2)\", () => assert.throws(\n        () => HashSet.of(Tuple2.of(1,Vector.of([1])))));\n    it(\"should refuse elements which don't offer true equality (hashmap)\", () => assert.throws(\n        () => HashSet.of(HashMap.of([\"a\",[1]]))));\n    it(\"should fail compilation on an obviously bad key type\", () =>\n       assertFailCompile(\n           \"HashSet.of([1])\", \"Argument of type \\'number[]\\' is not assignable to parameter\"));\n    it(\"hashcode should not have trivial collisions\", () => assert.equal(\n        false, HashSet.of(1,2,3).hashCode() == HashSet.of(0,2,3).hashCode()\n    ))\n});\n\ndescribe(\"hashset combinations\", () => {\n    it(\"calculates the diff well\", () => assert.ok(\n        HashSet.of(1,2,4).equals(HashSet.of(0,1,2,3,4).diff(HashSet.of(0,3)))));\n    it(\"calculates the diff from empty well\", () => assert.ok(\n        HashSet.empty<number>().equals(HashSet.empty<number>().diff(HashSet.of(0,3)))));\n    it(\"calculates the intersect well\", () => assert.ok(\n        HashSet.of(0,3).equals(HashSet.of(0,1,2,3,4).intersect(HashSet.of(0,3)))));\n    it(\"calculates the intersect from empty well\", () => assert.ok(\n        HashSet.empty<number>().equals(HashSet.empty<number>().intersect(HashSet.of(0,3)))));\n    it(\"calculates removeAll well\", () => assert.ok(\n        HashSet.of(1,2,4).equals(HashSet.of(0,1,2,3,4).removeAll([0,3]))));\n    it(\"calculates removeAll from empty well\", () => assert.ok(\n        HashSet.empty<number>().equals(HashSet.empty<number>().removeAll([0,3]))));\n    it(\"calculates remove well\", () => assert.ok(\n        HashSet.of(0,1,2,4).equals(HashSet.of(0,1,2,3,4).remove(3))));\n    it(\"calculates remove well event if item not present\", () => assert.ok(\n        HashSet.of(0,1,2,3,4).equals(HashSet.of(0,1,2,3,4).remove(5))));\n    it(\"calculates remove from empty well\", () => assert.ok(\n        HashSet.empty<number>().equals(HashSet.empty<number>().remove(3))));\n    it(\"filters correctly\", () => assert.ok(\n        HashSet.of(2,4).equals(HashSet.of(1,2,3,4,5).filter(x => x%2==0))));\n    it(\"filter upcasts if possible\", () => {\n        // here we only want to check that the code does compile,\n        // that 'x' is correctly seen has MySubclass in the 3rd line\n        HashSet.of<MyClass>(new MySubclass(\"a\",1,\"b\"))\n            .filter(instanceOf(MySubclass))\n            .filter(x => x.getField3().length>1);\n    });\n    it(\"keeps the custom equal/hash on filter\", () => assert.equal(\n        1, HashSet.of(new MyClass(\"a\",1)).filter(x=>true).add(new MyClass(\"a\",1)).length()));\n    it(\"confirms subset when correct\", () =>\n       assert.ok(HashSet.of(1,2,3).isSubsetOf(HashSet.of(0,1,2,3,4))));\n    it(\"rejects subset when it should\", () =>\n       assert.ok(!HashSet.of(1,2,3,5).isSubsetOf(HashSet.of(0,1,2,3,4))));\n});\n\ndescribe(\"hashset transformations\", () => {\n    it(\"map works\", () => assert.ok(\n        HashSet.of(5,6,7).equals(HashSet.of(1,2,3).map(x=>x+4))));\n    it(\"flatMap works\", () => assert.ok(\n        HashSet.of(5,6,7,-5,-6,-7).equals(HashSet.of(1,2,3).flatMap(x=>HashSet.of(x+4,-x-4)))));\n    it(\"mapOption works\", () => assert.ok(\n        HashSet.of(3,5,7).equals(HashSet.of(1,2,3,4,5,6).mapOption(\n            x => x%2==0 ? Option.of(x+1):Option.none<number>()))));\n    it(\"should fold correctly\", () => assert.equal(\n        6, HashSet.of(1,2,3).fold(0, (a,b)=>a+b)));\n    it(\"should foldLeft correctly\", () => assert.equal(\n        6, HashSet.of(\"a\", \"bb\", \"ccc\").foldLeft(0, (soFar,item)=>soFar+item.length)));\n    it(\"should foldRight correctly\", () => assert.equal(\n        6, HashSet.of(\"a\", \"bb\", \"ccc\").foldRight(0, (item,soFar)=>soFar+item.length)));\n});\n"
  },
  {
    "path": "tests/Lazy.ts",
    "content": "import { Lazy } from \"../src/Lazy\";\nimport * as assert from 'assert'\n\ndescribe(\"lazy basics\", () => {\n    it(\"should be lazy\", () => {\n        let evaluated = false;\n        const val = () => {\n            evaluated = true;\n            return 2;\n        }\n        const l = Lazy.of(val);\n        assert.equal(false, evaluated);\n        assert.equal(2, l.get());\n        assert.equal(true, evaluated);\n        // should get the same when it's cashed\n        // but shouldn't evaluate again\n        evaluated = false;\n        assert.equal(2, l.get());\n        assert.equal(false, evaluated);\n    });\n    it(\"map should be lazy\", () => {\n        let evaluated = false;\n        const val = () => {\n            evaluated = true;\n            return 2;\n        }\n        const l = Lazy.of(val);\n        const l2 = l.map(x => x*2);\n        assert.equal(false, evaluated);\n        assert.equal(4, l2.get());\n        assert.equal(true, evaluated);\n    });\n    it(\"should convert to string properly, value not present\", () =>\n       assert.equal(\"Lazy(?)\", Lazy.of(() => 5).toString()));\n    it(\"should convert to string properly, value present\", () => {\n        const l = Lazy.of(() => 5);\n        l.get();\n        assert.equal(\"Lazy(5)\", l.toString())\n    });\n});\n"
  },
  {
    "path": "tests/LinkedList.ts",
    "content": "import { LinkedList, ConsLinkedList } from \"../src/LinkedList\";\nimport { typeOf } from \"../src/Comparison\";\nimport { HashMap } from \"../src/HashMap\";\nimport { Option } from \"../src/Option\";\nimport { Stream } from \"../src/Stream\";\nimport { MyClass } from \"./SampleData\";\nimport * as SeqTest from \"./Seq\";\nimport * as assert from 'assert'\n\nSeqTest.runTests(\"LinkedList\",\n                 LinkedList.ofIterable,\n                 LinkedList.of,\n                 LinkedList.empty,\n                 LinkedList.unfoldRight,\n                 \"ConsLinkedList\");\n\ndescribe(\"LinkedList basics\", () => {\n    // unfortunately this doesn't work for now (does work on Vector & HashSet)\n    // \n    // it(\"correctly infers the more precise type on allMatch in case of typeguard\", () => {\n    //     // just checking that this compiles. 'charAt' is available on strings not numbers.\n    //     const v = LinkedList.of<string|number>(\"test\",\"a\");\n    //     if (v.allMatch(typeOf(\"string\"))) {\n    //         v.single().getOrThrow().charAt(0);\n    //     }\n    // });\n})\n\ndescribe(\"LinkedList toString\", () => {\n    it(\"serializes to string correctly\", () => assert.equal(\n        \"LinkedList(1, 2, 3)\", LinkedList.of(1,2,3).toString()));\n    it(\"serializes to string correctly - arrays & strings\", () => assert.equal(\n        \"LinkedList([1,'a'])\", LinkedList.of([1,'a']).toString()));\n    it(\"serializes to string correctly - custom toString\", () => assert.equal(\n        \"LinkedList({field1: hi, field2: 99})\", LinkedList.of(new MyClass(\"hi\", 99)).toString()));\n    it(\"serializes to string correctly - plain map\", () => assert.equal(\n        \"LinkedList({\\\"name\\\":\\\"hi\\\",\\\"age\\\":99})\", LinkedList.of({name:\"hi\", age:99}).toString()));\n    it(\"takes advantage of isEmpty\", () => {\n        const list = LinkedList.of(1,2,3);\n        if (!list.isEmpty()) {\n            list.head().get();\n        }\n    });\n});\n\ndescribe(\"static LinkedList.zip\", () => {\n    const r = LinkedList.zip<[number,string,number]>([1,2], [\"a\", \"b\"], LinkedList.of(11,10,9));\n    assert.equal(2, r.length());\n    // check that the types are properly inferred\n    const head: [number,string,number] = r.head().getOrThrow();\n    assert.equal(1, head[0]);\n    assert.equal(\"a\", head[1]);\n    assert.equal(11, head[2]);\n\n    const other = r.get(1).getOrThrow();\n    assert.equal(2, other[0]);\n    assert.equal(\"b\", other[1]);\n    assert.equal(10, other[2]);\n});\n"
  },
  {
    "path": "tests/Option.ts",
    "content": "import { Option, Some, None } from \"../src/Option\";\nimport { Vector } from \"../src/Vector\";\nimport { instanceOf } from \"../src/Comparison\";\nimport { Seq } from \"../src/Seq\";\nimport { MyClass, MySubclass } from \"./SampleData\";\nimport { assertFailCompile } from \"./TestHelpers\";\nimport * as assert from 'assert'\n\ndescribe(\"option creation\", () => {\n    it(\"should create a Some for Option.ofNullable(0)\", () => {\n        assert.ok(Option.ofNullable(0).equals(Option.of(0)));\n        assert.ok(Option.ofNullable(0).isSome());\n      });\n});\ndescribe(\"option comparison\", () => {\n    it(\"should mark equal options as equal\", () =>\n       assert.ok(Option.of(5).equals(Option.of(5))))\n    it(\"should mark different options as not equal\", () =>\n       assert.ok(!Option.of(5).equals(Option.of(6))))\n    it(\"should mark different options as not equal\", () =>\n       assert.ok(!Option.of<any>(Vector.of(12, 2674)).equals(Option.of<any>(null))))\n    it(\"should mark none as equals to none\", () =>\n       assert.ok(Option.none<string>().equals(Option.none<string>())));\n    it(\"should mark none and some as not equal\", () =>\n       assert.ok(!Option.of(5).equals(Option.none<number>())));\n    it(\"should mark none and some as not equal\", () =>\n       assert.ok(!Option.none<number>().equals(Option.of(5))));\n    it(\"should return true on contains\", () =>\n       assert.ok(Option.of(5).contains(5)));\n    it(\"should return false on contains on none\", () =>\n       assert.ok(!Option.none().contains(5)));\n    it(\"should return false on contains\", () =>\n       assert.ok(!Option.of(6).contains(5)));\n    it(\"doesn't throw when given another type on equals\", () => assert.equal(\n        false, Option.of(1).equals(<any>[1,2])));\n    it(\"doesn't throw when given null on equals\", () => assert.equal(\n        false, Option.of(1).equals(<any>null)));\n    it(\"empty doesn't throw when given another type on equals\", () => assert.equal(\n        false, Option.none().equals(<any>[1,2])));\n    it(\"empty doesn't throw when given null on equals\", () => assert.equal(\n        false, Option.none().equals(<any>null)));\n    it(\"should throw when comparing options without true equality\", () => assert.throws(\n        () => Option.of(Vector.of([1])).equals(Option.of(Vector.of([1])))));\n    it(\"should fail compilation on an obviously bad equality test\", () =>\n       assertFailCompile(\n           \"Option.of([1]).equals(Option.of([1]))\", \"Argument of type \\'\" +\n               \"Option<number[]>\\' is not assignable to parameter\"));\n    it(\"should fail compilation on an obviously bad contains test\", () =>\n       assertFailCompile(\n           \"Option.of([1]).contains([1])\",\n           \"Argument of type \\'number[]\\' is not assignable to parameter\"));\n});\n\ndescribe(\"option transformation\", () => {\n    it(\"should transform with map\", () => {\n        assert.ok(Option.of(5).equals(Option.of(4).map(x=>x+1)));\n    });\n    it(\"should return the original Some with orCall\", () => {\n        assert.ok(Option.of(5).equals(Option.of(5).orCall(() => Option.none())));\n    });\n    it(\"should call the function when calling orCall on None\", () => {\n        assert.ok(Option.of(5).equals(Option.none<number>().orCall(() => Option.of(5))));\n    });\n    it(\"should handle null as Some\", () =>\n       assert.ok(Option.of(5).map<number|null>(x => null).equals(Option.of<number|null>(null))));\n    it(\"should transform a Some to string properly\", () =>\n       assert.equal(\"Some(5)\", Option.of(5).toString()));\n    it(\"should transform a None to string properly\", () =>\n       assert.equal(\"None()\", Option.none().toString()));\n    it(\"should transform with flatMap x->y\", () => {\n        assert.ok(Option.of(5).equals(Option.of(4).flatMap(x=>Option.of(x+1))));\n    });\n    it(\"should transform with flatMap x->none\", () => {\n        assert.ok(Option.none<number>().equals(Option.of(4).flatMap(x=>Option.none<number>())));\n    });\n    it(\"should transform with flatMap none->none\", () => {\n        assert.ok(Option.none<number>().equals(Option.none<number>().flatMap(x=>Option.of(x+1))));\n    });\n    it(\"should filter some->some\", () =>\n       assert.ok(Option.of(5).equals(Option.of(5).filter(x => x>2))));\n    it(\"should filter some->none\", () =>\n       assert.ok(Option.of(5).filter(x => x<2).isNone()));\n    it(\"should filter none->none\", () =>\n       assert.ok(Option.none<number>().filter(x => x<2).isNone()));\n    it(\"filter upcasts if possible\", () => {\n        // here we only want to check that the code does compile,\n        // that 'x' is correctly seen has MySubclass in the 3rd line\n        Option.of<MyClass>(new MySubclass(\"a\",1,\"b\"))\n            .filter(instanceOf(MySubclass))\n            .filter(x => x.getField3().length>1);\n    });\n    it(\"should apply match to a some\", () =>\n       assert.equal(5, Option.of(4).match({\n           Some: x=>x+1,\n           None: ()=>-1\n       })));\n    it(\"should apply match to a nome\", () =>\n       assert.equal(-1, Option.none<number>().match({\n           Some: x=>x+1,\n           None: ()=>-1\n       })));\n    it(\"some supports transform\", () =>\n       assert.equal(6, Option.of(3).transform(x => 6)));\n    it(\"none supports transform\", () =>\n       assert.equal(6, Option.none<number>().transform(x => 6)));\n    it(\"should support lists combining some & none\", () => {\n        const a = <Some<number>>Option.of(5);\n        const b = <None<number>>Option.none<number>();\n        const c = Vector.of<Option<number>>(a, b);\n    });\n});\n\ndescribe(\"Option helpers\", () => {\n    it(\"should do sequence when all are some\", () =>\n       assert.ok(\n           Option.of(<Seq<number>>Vector.of(1,2,3)).equals(\n               Option.sequence(Vector.of(Option.of(1), Option.of(2), Option.of(3))))));\n    it(\"should fail sequence when some are none\", () =>\n       assert.ok(\n           Option.sequence(Vector.of(Option.of(1), Option.none<number>(), Option.of(3))).isNone()));\n    it(\"should liftA2\", () => assert.ok(Option.of(11).equals(\n        Option.liftA2((x:number,y:number) => x+y)(Option.of(5), Option.of(6)))));\n    it(\"should abort liftA2 on none\", () => assert.ok(Option.none<number>().equals(\n        Option.liftA2((x:number,y:number) => x+y)(Option.of(5), Option.none<number>()))));\n    it(\"should liftAp\", () => assert.ok(Option.of(14).equals(\n        Option.liftAp((x:{a:number,b:number,c:number}) => x.a+x.b+x.c)\n        ({a:Option.of(5), b:Option.of(6), c:Option.of(3)}))));\n    it(\"should abort liftAp on none\", () => assert.ok(Option.none<number>().equals(\n        Option.liftAp((x:{a:number,b:number}) => x.a+x.b)\n        ({a:Option.of(5), b:Option.none<number>()}))));\n    it(\"should support ifSome on Some\", () => {\n        let x = 0;\n        Option.of(5).ifSome(v => x=v);\n        assert.equal(5, x);\n    });\n    it(\"should support ifSome on None\", () => {\n        let x = 0;\n        Option.of(5).filter(x=>x<0).ifSome(v => x=v);\n        assert.equal(0, x);\n    });\n    it(\"should support ifNone on Some\", () => {\n        let x = 0;\n        Option.of(5).ifNone(() => x=5);\n        assert.equal(0, x);\n    });\n    it(\"should support ifNone on None\", () => {\n        let x = 0;\n        Option.of(5).filter(x=>x<0).ifNone(() => x=5);\n        assert.equal(5, x);\n    });\n});\n\ndescribe(\"option retrieval\", () => {\n    it(\"should return the value on Some.getOrElse\", () =>\n       assert.equal(5, Option.of(5).getOrElse(6)));\n    it(\"should return the alternative on None.getOrElse\", () =>\n       assert.equal(6, Option.none().getOrElse(6)));\n    it(\"should return the value on Some.toVector\", () =>\n       assert.deepEqual([5], Option.of(5).toVector().toArray()));\n    it(\"should return empty on None.toVector\", () =>\n       assert.deepEqual([], Option.none().toVector().toArray()));\n    it(\"should not throw on Some.getOrThrow\", () =>\n       assert.equal(5, Option.of(5).getOrThrow()));\n    it(\"should throw on None.getOrThrow\", () =>\n       assert.throws(() => Option.none().getOrThrow()));\n    it(\"should throw on None.getOrThrow with custom msg\", () =>\n        assert.throws(() => Option.none().getOrThrow(\"my custom msg\"),\n                      (err: Error) => err.message === 'my custom msg'));\n    it(\"should offer get() if i checked for isSome\", () => {\n        const opt = <Option<number>>Option.of(5);\n        if (opt.isSome()) {\n            // what we are checking here is whether this does build\n            // .get() is available only on Some not on None\n            assert.equal(5, opt.get());\n        }\n    });\n    it(\"should offer get() if i eliminated isNone\", () => {\n        const opt = <Option<number>>Option.of(5);\n        if (!opt.isNone()) {\n            // what we are checking here is whether this does build\n            // .get() is available only on Some not on None\n            assert.equal(5, opt.get());\n        }\n    });\n    it(\"should allow some & none in a list\", () => {\n        const a = Option.of(5);\n        const b = Option.none<number>();\n        if (a.isSome() && b.isNone()) {\n            Vector.of(a.asOption(),b);\n        }\n    })\n});\n\ndescribe(\"lifting\", () => {\n    it(\"should lift 0-parameter functions\", () => {\n        assert.ok(Option.lift(()=>1)().equals(Option.of(1)));\n        assert.ok(Option.lift(()=>undefined)().isNone());\n        assert.ok(Option.lift(()=>{throw \"x\"})().isNone());\n    });\n    it(\"should lift 1-parameter functions\", () => {\n        assert.ok(Option.lift((x:number)=>x+1)(1).equals(Option.of(2)));\n        assert.ok(Option.lift((x:number)=>undefined)(1).isNone());\n        assert.ok(Option.lift((x:number)=>{throw \"x\"})(1).isNone());\n    });\n    it(\"should lift 2-parameter functions\", () => {\n        assert.ok(Option.lift(\n            (x:number,y:number)=>x+1)(1,2).equals(Option.of(2)));\n        assert.ok(Option.lift(\n            (x:number,y:number)=>undefined)(1,2).isNone());\n        assert.ok(Option.lift(\n            (x:number,y:number)=>{throw \"x\"})(1,2).isNone());\n    });\n    it(\"should lift 3-parameter functions\" , () => {\n        assert.ok(Option.lift(\n            (x:number,y:number,z:number)=>x+1)(1,2,3).equals(Option.of(2)));\n        assert.ok(Option.lift(\n            (x:number,y:number,z:number)=>undefined)(1,2,3).isNone());\n        assert.ok(Option.lift(\n            (x:number,y:number,z:number)=>{throw \"x\"})(1,2,3).isNone());\n    });\n    it(\"should lift 4-parameter functions\", () => {\n        assert.ok(Option.lift(\n            (x:number,y:number,z:number,a:number)=>x+1)(1,2,3,4).equals(Option.of(2)));\n        assert.ok(Option.lift(\n            (x:number,y:number,z:number,a:number)=>undefined)(1,2,3,4).isNone());\n        assert.ok(Option.lift(\n            (x:number,y:number,z:number,a:number)=>{throw \"x\"})(1,2,3,4).isNone());\n    });\n    it(\"should lift 5-parameter functions\", () => {\n        assert.ok(Option.lift(\n            (x:number,y:number,z:number,a:number,b:number)=>x+1)(1,2,3,4,5).equals(Option.of(2)));\n        assert.ok(Option.lift(\n            (x:number,y:number,z:number,a:number,b:number)=>undefined)(1,2,3,4,5).isNone());\n        assert.ok(Option.lift(\n            (x:number,y:number,z:number,a:number,b:number)=>{throw \"x\"})(1,2,3,4,5).isNone());\n    });\n});\n"
  },
  {
    "path": "tests/Predicate.ts",
    "content": "import { Predicate } from '../src/Predicate';\nimport * as assert from 'assert'\n\ndescribe(\"predicate composition\", () => {\n    it(\"predicate and composition\", () =>\n       assert.ok(Predicate.of((x: number) =>x>2).and(x=>x<10)(5)));\n    it(\"predicate and composition 2\", () =>\n       assert.ok(!Predicate.of((x: number) =>x>2).and(x=>x<10)(11)));\n    it(\"predicate or composition\", () =>\n       assert.ok(!Predicate.of((x: number)=>x<2).or(x=>x>10)(5)));\n    it(\"predicate or composition 2\", () =>\n       assert.ok(Predicate.of((x: number)=>x<2).or(x=>x>10)(11)));\n    it(\"predicate negation\", () =>\n       assert.ok(Predicate.of((x: number)=>x<10).negate()(20)));\n    it(\"predicate allOf\", () =>\n       assert.ok(Predicate.allOf<number>(x=>x>10,x=>x<20,x=>x%2===0)(14)));\n    it(\"predicate allOf negative\", () =>\n       assert.ok(!Predicate.allOf<number>(x=>x>10,x=>x<20,x=>x%2===0)(15)));\n    it(\"predicate anyOf\", () =>\n       assert.ok(Predicate.anyOf<number>(x=>x<10,x=>x>20)(4)));\n    it(\"predicate anyOf negative\", () =>\n       assert.ok(!Predicate.anyOf<number>(x=>x<10,x=>x>20)(15)));\n    it(\"predicate noneOf\", () =>\n       assert.ok(!Predicate.noneOf<number>(x=>x<10,x=>x>20)(4)));\n    it(\"predicate noneOf negative\", () =>\n       assert.ok(Predicate.noneOf<number>(x=>x<10,x=>x>20)(15)));\n});\n"
  },
  {
    "path": "tests/SampleData.ts",
    "content": "import { areEqual, fieldsHashCode } from \"../src/Comparison\";\n\n/**\n * @hidden\n */\nexport class MyClass {\n    constructor(private field1:string, private field2:number) {}\n    equals(other: MyClass): boolean {\n        if (!other) {\n            return false;\n        }\n        return areEqual(this.field1, other.field1) &&\n            areEqual(this.field2, other.field2);\n    }\n    getField1(): string {\n        return this.field1;\n    }\n    getField2(): number {\n        return this.field2;\n    }\n    hashCode(): number {\n        return fieldsHashCode(this.field1, this.field2);\n    }\n    toString(): string {\n        return `{field1: ${this.field1}, field2: ${this.field2}}`;\n    }\n}\n\n/**\n * @hidden\n */\nexport class MySubclass extends MyClass {\n    constructor(field1: string, field2:number, private field3:string) {\n        super(field1,field2);\n        this.field3 = field3;\n    }\n    getField3(): string {\n        return this.field3;\n    }\n}\n"
  },
  {
    "path": "tests/Seq.ts",
    "content": "import { Seq } from \"../src/Seq\";\nimport { LinkedList } from \"../src/LinkedList\";\nimport { Vector } from \"../src/Vector\";\nimport { HashMap } from \"../src/HashMap\";\nimport { HashSet } from \"../src/HashSet\";\nimport { Stream } from \"../src/Stream\";\nimport { Option } from \"../src/Option\";\nimport { Predicate } from \"../src/Predicate\";\nimport { instanceOf, typeOf } from \"../src/Comparison\";\nimport { MyClass, MySubclass } from \"./SampleData\";\nimport { assertFailCompile } from \"./TestHelpers\";\nimport * as CollectionTest from './Collection';\nrequire(\"mocha-testcheck\").install();\nconst { gen, check} = require(\"mocha-testcheck\");\nimport * as assert from 'assert'\n\n/**\n * @hidden\n */\nexport function runTests(seqName: string,\n                         ofIterable: <T>(i:Iterable<T>)=>Seq<T>,\n                         of: <T>(...i:Array<T>)=>Seq<T>,\n                         empty: <T>()=>Seq<T>,\n                         unfoldRight: <T,U>(seed: T, fn: (x:T)=>Option<[U,T]>)=>Seq<U>,\n                         nonEmptySeqName_?:string) {\n    const nonEmptySeqName = nonEmptySeqName_ || seqName;\n    CollectionTest.runTests(seqName, of, empty);\n    describe(seqName + \" creation\", () => {\n        it(\"handles of() without parameters ok\", () => assert.deepEqual(\n            [], of().toArray()));\n        it(\"creates from a JS array\", () => assert.deepEqual(\n            [\"a\",\"b\", \"c\"],\n            ofIterable<string>([\"a\",\"b\",\"c\"]).toArray()));\n        it(\"creates from a spread\", () => assert.deepEqual(\n            [\"a\",\"b\", \"c\"],\n            of(\"a\",\"b\",\"c\").toArray()));\n        it(\"creates also with nulls\", () => assert.deepEqual(\n            [1, null, 2], of(1, null, 2).toArray()));\n        it(\"supports ofIterable\", () => assert.deepEqual(\n            [1,2,3], ofIterable([1,2,3]).toArray()));\n        // need to test ofIterable with a real iterable as well\n        // as an array -- vector for instance has an optimized codepath\n        // for arrays so we need to give a real iterable too for full coverage.\n        it(\"supports ofIterable from real iterable\", () => assert.deepEqual(\n            [1,2,3], ofIterable(Stream.of(1,2,3)).toArray()));\n        it(\"supports of\", () => assert.deepEqual(\n            [1,2,3], of(1,2,3).toArray()));\n        it(\"supports unfoldRight\", () => assert.deepEqual(\n            [10,9,8,7,6,5,4,3,2,1], unfoldRight(\n                10, x=>Option.of(x)\n                    .filter(x => x!==0)\n                    .map<[number,number]>(x => [x,x-1])).toArray()));\n    });\n\n    describe(seqName + \" prepend\", () => {\n        const basic = of(1,2,3,4);\n        const prepended = of(2,3,4).prepend(1);\n        it(\"prepends correctly\", () => assert.ok(basic.equals(prepended)));\n        it(\"converts to array correctly\", () => assert.deepEqual(\n            basic.toArray(), prepended.toArray()));\n        it(\"appends correctly after prepend\", () => assert.ok(\n            basic.append(5).equals(prepended.append(5))));\n        it(\"appendsAll correctly after prepend\", () => assert.ok(\n            basic.appendAll([5,6]).equals(prepended.appendAll([5,6]))));\n        it(\"converts to string correctly after prepend\", () => assert.equal(\n            basic.toString(), prepended.toString()));\n        it(\"prependsAll correctly\", () => assert.deepEqual(\n            [1,2,3,4,5], of(4,5).prependAll([1,2,3]).toArray()));\n    });\n\n    describe(seqName + \" Value tests\", () => {\n        it(\"has non-obviously-broken equals\", () => assert.ok(\n            of(\"a\",\"b\",\"c\").equals(of(\"a\", \"b\", \"c\"))));\n        it(\"doesn't throw when given another type on equals\", () => assert.equal(\n            false, of(1).equals(<any>[1,2])));\n        it(\"doesn't throw when given null on equals\", () => assert.equal(\n            false, of(1).equals(<any>null)));\n        it(\"is strict with equality\", () => assert.ok(\n            !of(1,2).equals(of(1, <any>undefined))));\n        it(\"supports contain\", () => assert.ok(\n            of(1,2,3).contains(2)));\n        it(\"should throw when using contains without true equality\", () => assert.throws(\n            () => of(Option.of([1])).contains(Option.of([1]))));\n        it(\"rejects contain\", () => assert.ok(\n            !of(1,2,3).contains(4)));\n        it(\"rejects contain, empty stream\", () => assert.ok(\n            !empty().contains(4)));\n        it(\"supports contains, custom equality\", () => assert.ok(\n            of(new MyClass(\"hi\", 3)).contains(new MyClass(\"hi\", 3))));\n        it(\"supports allMatch, positive case\", () => assert.ok(\n            of(2,4,8).allMatch(x => x%2 === 0)));\n        it(\"supports allMatch, negative case\", () => assert.ok(\n            !of(2,5,8).allMatch(x => x%2 === 0)));\n        it(\"supports allMatch, empty stream\", () => assert.ok(\n            empty<number>().allMatch(x => x%2 === 0)));\n        it(\"supports anyMatch, positive case\", () => assert.ok(\n            of(3,5,8).anyMatch(x => x%2 === 0)));\n        it(\"supports anyMatch, negative case\", () => assert.ok(\n            !of(3,5,9).anyMatch(x => x%2 === 0)));\n        it(\"supports anyMatch, empty stream\", () => assert.ok(\n            !empty<number>().anyMatch(x => x%2 === 0)));\n        it(\"should fail compilation on an obviously bad equality test\", () =>\n           assertFailCompile(\n               seqName + \".of([1]).equals(\" + seqName + \".of([1]))\", \"Argument of type \\'\" +\n                   nonEmptySeqName + \"<number[]>\\' is not assignable to parameter\"));\n        it(\"should fail compilation on an obviously bad contains test\", () =>\n           assertFailCompile(\n               seqName + \".of([1]).contains([1])\",\n               \"Argument of type \\'number[]\\' is not assignable to parameter\"));\n        it(\"should fail compilation trying to call removeAll without equality\", () =>\n           assertFailCompile(\n               seqName + \".of([1]).removeAll([1])\",\n               \"Argument of type \\'number[]\\' is not assignable to parameter\"));\n    });\n\n    describe(seqName + \" iteration\", () => {\n        // can get for..of in tests by changing the target to es6,\n        // or enabling downlevelIteration in the tsconfig.json,\n        // not doing that for now.\n        // it(\"supports for of\", () => {\n        //     let total = 0;\n        //     for (const x of of(1,2,3)) {\n        //         total += x;\n        //     }\n        //     assert.equal(6, total);\n        // })\n        it(\"finds items\", () =>\n           of(1,2,3).find(x => x >= 2).contains(2));\n        it(\"doesn't find if the predicate doesn't match\", () =>\n           of(1,2,3).find(x => x >= 4).isNone());\n        it(\"folds correctly\", () => assert.equal(\n            6, of(1,2,3).fold(0, (a,b)=>a+b)));\n        it(\"foldsLeft correctly\", () => assert.equal(\n            \"cba!\",\n            of(\"a\", \"b\", \"c\").foldLeft(\"!\", (xs,x) => x+xs)));\n        it(\"foldsRight correctly\", () => assert.equal(\n            \"!cba\",\n            of(\"a\", \"b\", \"c\").foldRight(\"!\", (x,xs) => xs+x)));\n        it(\"handles scanLeft correctly on an empty seq\", () => assert.deepEqual(\n            [0], empty<number>().scanLeft(0, (i,j)=>i+j).toArray()));\n        it(\"handles scanRight correctly on an empty seq\", () => assert.deepEqual(\n            [0], empty<number>().scanRight(0, (j,i)=>i+j).toArray()));\n        it(\"calls forEach correctly\", () => {\n            let ar: number[] = [];\n            of(1,2,3).forEach((v:number) => ar.push(v));\n            assert.deepEqual([1,2,3], ar);\n        });\n        it(\"supports iterator\", () => {\n            let total = 0;\n            const iterator = of(1,2,3)[Symbol.iterator]();\n            let curItem = iterator.next();\n            while (!curItem.done) {\n                total += curItem.value;\n                curItem = iterator.next();\n            }\n            assert.equal(6, total);\n        })\n    });\n    describe(seqName + \" conversions\", () => {\n        it(\"mkString ok for null too\", () => assert.equal(\n            \"null\", of(null).mkString(\", \")));\n        it(\"mkString works\", () => assert.equal(\n            \"1, 2, 3\", of(1,2,3).mkString(\", \")));\n        it(\"mkString works for strings too\", () => assert.equal(\n            \"a, b, c\", of(\"a\",\"b\",\"c\").mkString(\", \")));\n        const nullSeq = of(null);\n        nullSeq.last(); // needed to force the stream to get loaded\n        it(\"toString ok for null too\", () => assert.equal(\n            seqName + \"(null)\", nullSeq.toString()));\n        const onetwothree = of(1,2,3);\n        onetwothree.last(); // needed to force the stream to get loaded\n        it(\"toString works\", () => assert.equal(\n            seqName + \"(1, 2, 3)\", onetwothree.toString()));\n        const abc = of(\"a\",\"b\",\"c\");\n        abc.last(); // needed to force the stream to get loaded\n        it(\"toString works for strings too\", () => assert.equal(\n            seqName + \"('a', 'b', 'c')\", abc.toString()));\n        it(\"handles circular structures on toString too\", () => {\n            const a: any = {};\n            a.b = a;\n            assert.equal(\n                of({}).toString(), of(a).toString());\n        })\n        it(\"transforms to map\", () => {\n            assert.ok(HashMap.empty<number,string>().put(1,\"ok\").put(2, \"bad\")\n                      .equals(<HashMap<number,string>>of<[number,string]>([1,\"ok\"],[2,\"bad\"]).toMap(x => x)));\n        });\n        it(\"empty seq transforms to empty set\", () => {\n            assert.ok(HashSet.empty<number>()\n                      .equals(empty<number>().toSet(x => x)));\n        });\n    });\n    describe(seqName + \" manipulation\", () => {\n        it(\"computes the length correctly\", () => assert.equal(\n            3, of(1,2,3).length()));\n        it(\"computes the length of the empty seq correctly\", () => assert.equal(\n            0, empty().length()));\n        it(\"correctly drops right n items\", () => assert.deepEqual(\n            [1,2,3,4], of(1,2,3,4,5,6).dropRight(2).toArray()));\n        it(\"returns an empty seq when dropping right too much\", () => assert.deepEqual(\n            [], of(1,2).dropRight(3).toArray()));\n        it(\"doesn't modify the receiver upon drop\", () => {\n            const x = of(1,2,3);\n            x.drop(2);\n            assert.deepEqual([1,2,3], x.toArray())\n        });\n        it(\"sortBy sorting works\", () => assert.ok(\n            of(4,3,2,1)\n                .equals(of(1,2,3,4).sortBy((x,y) => y-x))));\n        it(\"sortOn sorting works\", () => assert.ok(\n            of(1,2,3,4)\n                .equals(of(4,2,3,1).sortOn(x => x))));\n        it(\"sortOn sorting works2\", () => assert.ok(\n            of(new MyClass(\"zz\",1),\n                     new MyClass(\"test\", 2),\n                     new MyClass(\"b\",3))\n                .equals(of(new MyClass(\"test\", 2),\n                                 new MyClass(\"zz\", 1),\n                                 new MyClass(\"b\",3)).sortOn(x => x.getField2()))));\n        it(\"sortOn sorting works with strings too\", () => assert.ok(\n            of(1,2,3,4)\n                .equals(of(4,2,3,1).sortOn(x => x+\"\"))));\n        it(\"sortOn sorting works with strings too 2\", () => assert.ok(\n            of(new MyClass(\"b\",3),\n               new MyClass(\"test\", 2),\n               new MyClass(\"zz\",1))\n                .equals(of(new MyClass(\"test\", 2),\n                                 new MyClass(\"zz\", 1),\n                                 new MyClass(\"b\",3)).sortOn(x => x.getField1()))));\n        it(\"correctly reverses\", () => assert.deepEqual(\n            [3,2,1], of(1,2,3).reverse().toArray()));\n        it(\"correctly reverses the empty vector\", () => assert.deepEqual(\n            [], empty().reverse().toArray()));\n        it(\"correctly reverses also after prepend\", () => assert.deepEqual(\n            [3,2,1], of(2,3).prepend(1).reverse().toArray()));\n        it(\"correctly partitions also after prepend\", () => assert.deepEqual(\n            [[1,3,5,7],[2,4,6,8]],\n            of(2,3,4,5,6,7,8).prepend(1).partition(x => x%2!==0)\n                .map(v => v.toArray())));\n        it(\"correctly infers the more precise left and right type on partition in case of typeguard\", () => {\n            // just checking that this compiles. 'charAt' is available on strings not numbers.\n            // 'toExponential' is available on numbers not strings.\n            const [a,b] = of<string|number>(1,\"a\")\n                .partition(typeOf(\"number\"))\n            a.single().getOrThrow().toExponential(2);\n            b.single().getOrThrow().charAt(0);\n        });\n        it(\"correctly infers the more precise right type on partition in case of typeguard\", () => {\n            // just checking that this compiles. 'charAt' is available on strings not numbers.\n            // 'toExponential' is available on numbers not strings.\n            const [a,b] = of<string|number>(1,\"a\")\n                .partition(typeOf(\"string\"))\n            a.single().getOrThrow().charAt(0);\n            b.single().getOrThrow().toExponential(2);\n        });\n        it(\"zips with an array\", () => assert.deepEqual(\n            [[1,\"a\"], [2,\"b\"]], of(1,2,3).zip([\"a\",\"b\"]).toArray()));\n        it(\"zips with a stream\", () => assert.deepEqual(\n            [[\"a\",0], [\"b\",1]], of(\"a\",\"b\").zip(Stream.iterate(0,x=>x+1)).toArray()));\n        it(\"richer example\", () => assert.deepEqual(\n            [[1,\"a\"],[2,\"b\"]], of(1,2,3)\n                .zip([\"a\", \"b\", \"c\"]).takeWhile(([k,v]) => k<3).toArray()));\n        it(\"flatMap works\", () => assert.ok(\n            of(1,2,2,3,3,3,4,4,4,4)\n                .equals(of(1,2,3,4).flatMap(\n                    x => ofIterable(Array.from(Array(x), ()=>x))))));\n        it(\"map works\", () => assert.ok(\n            of(5,6,7).equals(of(1,2,3).map(x=>x+4))));\n        it(\"mapOption works\", () => assert.deepEqual(\n            [3,5,7],of(1,2,3,4,5,6).mapOption(\n                x => x%2==0 ? Option.of(x+1):Option.none<number>()).toArray()));\n        it(\"supports append\", () => assert.deepEqual(\n            [1,2,3,4], of(1,2,3).append(4).toArray()));\n        it(\"doesn't modify the receiver upon append\", () => {\n            const x = of(1,2,3);\n            x.append(4);\n            assert.deepEqual([1,2,3], x.toArray())\n        });\n        it(\"supports appendAll\", () => assert.deepEqual(\n            [1,2,3,4,5], of(1,2,3).appendAll([4,5]).toArray()));\n        it(\"doesn't modify the receiver upon appendAll\", () => {\n            const x = of(1,2,3);\n            x.appendAll([4,5]);\n            assert.deepEqual([1,2,3], x.toArray())\n        });\n        it(\"supports appendAll of a linkedlist iterable\", () => assert.deepEqual(\n            [1,2,3,4,5], of(1,2,3).appendAll(LinkedList.of(4,5)).toArray()));\n        it(\"doesn't modify the receiver upon appendAll of a linkedlist iterable\", () => {\n            const x = of(1,2,3);\n            x.appendAll(LinkedList.of(4,5));\n            assert.deepEqual([1,2,3], x.toArray())\n        });\n        it(\"supports appendAll of a vector iterable\", () => assert.deepEqual(\n            [1,2,3,4,5], of(1,2,3).appendAll(Vector.of(4,5)).toArray()));\n        it(\"doesn't modify the receiver upon appendAll of a vector iterable\", () => {\n            const x = of(1,2,3);\n            x.appendAll(Vector.of(4,5));\n            assert.deepEqual([1,2,3], x.toArray())\n        });\n        it(\"supports take\", () => assert.deepEqual(\n            [1,2,3], of(1,2,3,4,5,6).take(3).toArray()));\n        it(\"supports take with an index higher than the length\", () =>\n           assert.deepEqual([1,2,3], of(1,2,3).take(6).toArray()));\n        it(\"supports take with a negative index\", () =>\n           assert.deepEqual([], of(1,2,3).take(-1).toArray()));\n        it(\"doesn't modify the receiver upon take\", () => {\n            const x = of(1,2,3);\n            x.take(2);\n            assert.deepEqual([1,2,3], x.toArray())\n        });\n        check.it(\"applying reverse twice is the identity\", gen.array(gen.string), (ar:string[]) => {\n            assert.deepEqual(ofIterable(ar).reverse().reverse().toArray(),\n                             ofIterable(ar).toArray());\n        });\n        check.it(\"calling take() on the seq is the same as on the array\",\n                 gen.array(gen.string), gen.int.suchThat((n:number) => !Number.isNaN(n)), (ar:number[],n:number) => {\n            assert.deepEqual(ofIterable(ar).take(n).toArray(),\n                             ar.slice(0,Math.max(0,n)));\n        });\n        it(\"correctly implements sliding on a non-empty seq\", () => {\n            assert.deepEqual([[1,2],[3,4],[5,6]], of(1,2,3,4,5,6).sliding(2).map(x => x.toArray()).toArray())\n        });\n        it(\"correctly implements sliding on a non-empty seq with length non-multiple of count\", () => {\n            assert.deepEqual([[1,2,3],[4,5,6],[7]], of(1,2,3,4,5,6,7).sliding(3).map(x => x.toArray()).toArray())\n        });\n        it(\"correctly implements sliding on an empty seq\", () => {\n            assert.deepEqual([], empty().sliding(2).map(x => x.toArray()).toArray())\n        });\n    });\n    describe(seqName + \" filtering\", () => {\n        it(\"filter works\", () => assert.ok(\n            of(2,4)\n                .equals(of(1,2,3,4).filter(x => x%2 === 0))));\n        it(\"filter works with prepend\", () => assert.ok(\n            of(2,4)\n                .equals(of(3,4).prepend(2).prepend(1).filter(x => x%2 === 0))));\n        it(\"filter upcasts if possible - instanceOf\", () => {\n            // here we only want to check that the code does compile,\n            // that 'x' is correctly seen as MySubclass in the 3rd line\n            of<MyClass>(new MySubclass(\"a\",1,\"b\"))\n                .filter(instanceOf(MySubclass))\n                .filter(x => x.getField3().length>1);\n        });\n        it(\"filter upcasts if possible - typeOf\", () => {\n            // here we only want to check that the code does compile,\n            // that 'x' is correctly seen as string in the 3rd line\n            of<any>(1,3,\"a\",\"b\")\n                .filter(typeOf(\"string\"))\n                .filter(x => x.replace(\"x\",\"\").length > 0);\n        });\n        it(\"distinctBy\", () => assert.deepEqual(\n            [1,2,3], of(1,1,2,3,2,3,1).distinctBy(x => x).toArray()));\n        it(\"distinctBy for the empty seq\", () => assert.deepEqual(\n            [], empty<number>().distinctBy(x => x).toArray()));\n        it(\"distinctBy for a single value\", () => assert.deepEqual(\n            [1], of(1).distinctBy(x => x).toArray()));\n        it(\"distinctBy, custom equality\", () => assert.deepEqual(\n            [1,0,2], of(1,0,1,2,3,2,3,1).distinctBy(x => new MyClass(\"hi\", x%3)).toArray()));\n        it(\"distinctBy with prepend\", () => assert.deepEqual(\n            [1,2,3], of(2,3,2,3,1).prepend(1).distinctBy(x => x).toArray()));\n        it(\"correctly dropsWhile\", () => assert.deepEqual(\n            [4,3,5,6], of(1,2,3,4,3,5,6).dropWhile(x=>x<4).toArray()));\n        it(\"correctly dropsWhile, only the first one is removed\", () => assert.deepEqual(\n            [2,3,4,3,5,6], of(1,2,3,4,3,5,6).dropWhile(x=>x<2).toArray()));\n        it(\"correctly dropsWhile, nothing matches\", () => assert.deepEqual(\n            [], of(1,2,3,4,3,5,6).dropWhile(x=>x>=0).toArray()));\n        it(\"correctly dropsWhile, everything matches\", () => assert.deepEqual(\n            [1,2,3,4,3,5,6], of(1,2,3,4,3,5,6).dropWhile(x=>x<0).toArray()));\n        it(\"correctly dropsRightWhile\", () => assert.deepEqual(\n            [1,4,2,3], of(1,4,2,3,4,5,6).dropRightWhile(x=>x>=4).toArray()));\n        it(\"correctly dropsRightWhile, only the last one is removed\", () => assert.deepEqual(\n            [1,4,2,3,4,5], of(1,4,2,3,4,5,6).dropRightWhile(x=>x>5).toArray()));\n        it(\"correctly dropsRightWhile, nothing matches\", () => assert.deepEqual(\n            [], of(1,4,2,3,4,5,6).dropRightWhile(x=>x>=0).toArray()));\n        it(\"correctly dropsRightWhile, everything matches\", () => assert.deepEqual(\n            [1,4,2,3,4,5,6], of(1,4,2,3,4,5,6).dropRightWhile(x=>x<0).toArray()));\n        it(\"correctly drops n items\", () => assert.deepEqual(\n            [4,5,6], of(1,2,3,4,5,6).drop(3).toArray()));\n        it(\"returns an empty stream when dropping too much\", () => assert.deepEqual(\n            [], of(1,2).drop(3).toArray()));\n        it(\"calculates removeFirst well\", () => assert.deepEqual(\n            [0,1,3,4], of(0,1,2,3,4).removeFirst(Predicate.isIn([3,2])).toArray()));\n        it(\"calculates removeFirst well event if item not present\", () => assert.deepEqual(\n            [0,1,2,3,4], of(0,1,2,3,4).removeFirst(Predicate.equals(5)).toArray()));\n        it(\"calculates removeFirst from empty well\", () => assert.ok(\n            empty<number>().equals(empty<number>().removeFirst(x => x === 3))));\n        it(\"calculates removeAll from empty well\", () => assert.ok(\n            empty<number>().equals(empty<number>().removeAll([2,3]))));\n        it(\"handles a simple splitAt\", () => assert.deepEqual(\n            [[1,2,3],[4,5]], of(1,2,3,4,5).splitAt(3).map(x=>x.toArray())));\n        it(\"handles a simple splitAt 2\", () => assert.deepEqual(\n            [[1],[2,3]], of(1,2,3).splitAt(1).map(x=>x.toArray())));\n        it(\"handles splitAt with empty second list\", () => assert.deepEqual(\n            [[1,2,3],[]], of(1,2,3).splitAt(3).map(x=>x.toArray())));\n        it(\"handles splitAt with empty first list\", () => assert.deepEqual(\n            [[],[1,2,3]], of(1,2,3).splitAt(0).map(x=>x.toArray())));\n        it(\"handles splitAt with out of bounds 1\", () => assert.deepEqual(\n            [[],[1,2,3]], of(1,2,3).splitAt(-1).map(x=>x.toArray())));\n        it(\"handles splitAt with out of bounds 2\", () => assert.deepEqual(\n            [[1,2,3],[]], of(1,2,3).splitAt(4).map(x=>x.toArray())));\n        it(\"handles a regular span\", () => assert.deepEqual(\n            [[1,2],[3,4,5]], of(1,2,3,4,5).span(i=>i<3).map(x=>x.toArray())));\n        it(\"handles a span matching everything\", () => assert.deepEqual(\n            [[1,2,3,4,5],[]], of(1,2,3,4,5).span(i=>i<9).map(x=>x.toArray())));\n        it(\"handles a span matching nothing\", () => assert.deepEqual(\n            [[],[1,2,3,4,5]], of(1,2,3,4,5).span(i=>i<0).map(x=>x.toArray())));\n    });\n    describe(seqName + \" value extraction\", () => {\n        it(\"get finds when present\", () => assert.ok(\n            Option.of(5).equals(of(1,2,3,4,5,6).get(4))));\n        it(\"get finds when present after prepend\", () => assert.ok(\n            Option.of(5).equals(of(2,3,4,5,6).prepend(1).get(4))));\n        it(\"get doesn't find when stream too short\", () => assert.ok(\n            Option.none<number>().equals(of(1,2,3).get(4))));\n        it(\"get doesn't find when negative index\", () => assert.ok(\n            Option.none<number>().equals(of(1,2,3).get(-1))));\n        it(\"correctly gets the tail of the empty vector\", () => assert.ok(\n            empty().tail().isNone()));\n        it(\"correctly gets the tail of a simple vector\", () => assert.ok(\n            of(2,3,4).equals(of(1,2,3,4).tail().getOrThrow())));\n        it(\"correctly gets the tail of a vector after prepend\", () => assert.ok(\n            of(2,3,4).equals(of(2,3,4).prepend(1).tail().getOrThrow())));\n        it(\"gets the last value correctly\", () => assert.equal(\n            3, of(1,2,3).last().getOrThrow()));\n        it(\"gets the last value correctly for an empty seq\", () => assert.ok(\n            empty().last().isNone()));\n        it(\"correctly gets the last element also after prepend\", () => assert.equal(\n            5, of(4,5).prependAll(of(1,2,3)).last().getOrUndefined()));\n        it(\"correctly gets the first element\", () => assert.equal(\n            1, of(1,2,3,4,5).head().getOrUndefined()));\n        it(\"correctly gets the first element of an empty vector\", () => assert.ok(\n            empty().head().isNone()));\n        it(\"correctly gets the first element also after prepend\", () => assert.equal(\n            1, of(4,5).prependAll(of(1,2,3)).head().getOrUndefined()));\n        it(\"correct returns single positive case\", () => assert.equal(\n            5, of(5).single().getOrThrow()));\n        it(\"correct returns single negative case\", () => assert.ok(\n            of(5,6).single().isNone()));\n        it(\"correct returns single empty seq\", () => assert.ok(\n            empty().single().isNone()));\n    });\n    describe(seqName + \" supports shuffle\", () => {\n        const original = of(1,2,3,4,5,6,7,2,9,10);\n        const shuffle1 = original.shuffle();\n        const shuffle2 = original.shuffle();\n        const shuffle3 = original.shuffle();\n        const shuffle4 = original.shuffle();\n        it(\"should conserve all the items1\", () => assert.deepEqual(\n            original.sortOn(x=>x).toArray(), shuffle1.sortOn(x=>x).toArray()));\n        it(\"should conserve all the items2\", () => assert.deepEqual(\n            original.sortOn(x=>x).toArray(), shuffle2.sortOn(x=>x).toArray()));\n        it(\"should conserve all the items3\", () => assert.deepEqual(\n            original.sortOn(x=>x).toArray(), shuffle3.sortOn(x=>x).toArray()));\n        it(\"should conserve all the items4\", () => assert.deepEqual(\n            original.sortOn(x=>x).toArray(), shuffle4.sortOn(x=>x).toArray()));\n        it(\"should change the order of elements\", () => assert.equal(false,\n            original.equals(shuffle1) &&\n                original.equals(shuffle2) &&\n                original.equals(shuffle3) &&\n                original.equals(shuffle4)))\n    });\n\n    const list = of({a:1, b:\"aa\"}, {a:2, b:\"aa\"}, {a:1, b:\"ba\"});\n\n    describe(seqName + \" multiple criteria sorting\", () => {\n        it (\"sorts normally, descending on b\", () => {\n            assert.deepEqual([{a:1,b:\"ba\"},{a:1,b:\"aa\"},{a:2,b:\"aa\"}], list.sortOn(x=>x.a,{desc:x=>x.b}).toArray());\n        });\n        it (\"sorts normally ascending on b\", () => {\n            assert.deepEqual([{a:1,b:\"aa\"},{a:1,b:\"ba\"},{a:2,b:\"aa\"}], list.sortOn(x=>x.a, x=>x.b).toArray());\n        });\n        it (\"sorts normally descending on a\", () => {\n            assert.deepEqual([{a:2,b:\"aa\"},{a:1,b:\"aa\"},{a:1,b:\"ba\"}], list.sortOn({desc:x=>x.a},x=>x.b).toArray());\n        });\n        it (\"sorts normally descending on both\", () => {\n            assert.deepEqual([{a:2,b:\"aa\"},{a:1,b:\"ba\"},{a:1,b:\"aa\"}], list.sortOn({desc:x=>x.a},{desc:x=>x.b}).toArray());\n        });\n    });\n\n    const list1 = of({a:1, b:true}, {a:2, b:false}, {a:1, b:false});\n\n    describe(seqName + \" multiple criteria sorting (including booleans)\", () => {\n        it (\"sorts normally, descending on b\", () => {\n            assert.deepEqual([{a:1,b:true},{a:1,b:false},{a:2,b:false}], list1.sortOn(x=>x.a,{desc:x=>x.b}).toArray());\n        });\n        it (\"sorts normally ascending on b\", () => {\n            assert.deepEqual([{a:1,b:false},{a:2,b:false},{a:1,b:true}], list1.sortOn(x=>x.b, x=>x.a).toArray());\n        });\n    });\n}\n\ndescribe(\"Seq fuzzer\", () => {\n    const testsToRun = 2000; \n    const opsToRun = 64;\n    const randomArrayMaxLength = 256;\n    const getRandomArray = () => Stream.iterate(0,i=>i+1)\n        .take(Math.random()*randomArrayMaxLength)\n        .toArray();\n    const getRandomVal = () => Math.round(Math.random()*randomArrayMaxLength);\n    const fuzOps: (()=>[string,(x:Seq<number>)=>Seq<number>])[] = [\n        () => {\n            const arr = getRandomArray();\n            return [\"prepend \" + arr.length, s => s.prependAll(arr)];\n        },\n        () => [\"reverse\", s => s.reverse()],\n        () => {\n            const arr = getRandomArray();\n            return [\"append \" + arr.length, s => s.appendAll(arr)];\n        },\n        () => {\n            const count = getRandomVal();\n            return [\"take \" + count, s => s.take(count)];\n        },\n        () => {\n            const count = getRandomVal();\n            return [\"drop \" + count, s => s.drop(count)];\n        },\n        () => [\"map *2\", s => s.map(x=>x*2)],\n        () => {\n            const val = getRandomVal();\n            return [\"filter >=\" + val, s => <any>s.filter(x=>x>=val)];\n        }\n    ];\n    it(\"should pass the fuzzer\", () => {\n        for (let testIdx=0;testIdx<testsToRun;testIdx++) {\n            if (testIdx % 1000 === 0) {\n                console.log(`fuzzer: ran ${testIdx} tests`);\n            }\n            let vec: Seq<number> = Vector.empty<number>();\n            let llist: Seq<number> = LinkedList.empty<number>();\n            let stream: Seq<number> = Stream.empty<number>();\n            const ops:string[] = [];\n            for (let opIdx=0;opIdx<opsToRun;opIdx++) {\n                const opIdx = Math.round(Math.random()*(fuzOps.length-1));\n                const [opDesc, opFn] = fuzOps[opIdx]();\n                ops.push(opDesc);\n\n                const checkSeq = (desc: string, seq:Seq<number>, updateSeq:(val:Seq<number>)=>void) => {\n                    const previousSeqAr = seq.toArray();\n                    const previousSeq = seq;\n                    try {\n                        updateSeq(opFn(seq));\n                    } catch (ex) {\n                        console.error(`*** ${desc}: got exception`);\n                        console.error(ops);\n                        throw ex;\n                    }\n                    if (previousSeq.toArray().toString() !== previousSeqAr.toString()) {\n                        console.error(`*** ${desc} BUG previous ${desc} was modified`);\n                        console.error(ops);\n                        assert.deepEqual(previousSeqAr, previousSeq.toArray());\n                    }\n                };\n\n                checkSeq(\"Vector\", vec, n=>{vec=n});\n                checkSeq(\"LinkedList\", llist, n=>{llist=n});\n                checkSeq(\"Stream\", stream, n=>{stream=n});\n\n                if (vec.toArray().toString() !== llist.toArray().toString()) {\n                    console.error(\"*** vector/llist BUG\");\n                    console.error(ops);\n                    assert.deepEqual(vec.toArray(), llist.toArray());\n                }\n                if (stream.toArray().toString() !== llist.toArray().toString()) {\n                    console.error(\"*** stream/llist BUG\");\n                    console.error(ops);\n                    assert.deepEqual(stream.toArray(), llist.toArray());\n                }\n            }\n        }\n    });\n});\n"
  },
  {
    "path": "tests/Stream.ts",
    "content": "import { Stream } from \"../src/Stream\";\nimport { typeOf } from \"../src/Comparison\";\nimport { Vector } from \"../src/Vector\";\nimport { Option } from \"../src/Option\";\nimport { MyClass} from \"./SampleData\";\nimport { HashMap} from \"../src/HashMap\";\nimport * as SeqTest from \"./Seq\";\nimport * as assert from 'assert'\n\nSeqTest.runTests(\"Stream\",\n                 Stream.ofIterable,\n                 Stream.of,\n                 Stream.empty,\n                 Stream.unfoldRight,\n                \"ConsStream\");\n\ndescribe(\"Stream basics\", () => {\n    it(\"creates a continually constant value\", () => assert.deepEqual(\n        [1,1,1,1], Stream.continually(() => 1).take(4).toArray()));\n    it(\"iterates from a seed\", () => assert.deepEqual(\n        [1,2,4,8], Stream.iterate(1, x => x*2).take(4).toArray()));\n    it(\"maps lazily correctly\", () => assert.deepEqual(\n        [4,5,7,11], Stream.iterate(1, x => x*2).map(x => x+3).take(4).toArray()));\n    it(\"supports appendStream\", () => assert.deepEqual(\n        [1,2,3,4,5,6], Stream.of(1,2,3).appendStream(Stream.of(4,5,6)).toArray()));\n    it(\"supports cycle\", () => assert.deepEqual(\n        [1,2,3,1,2,3,1,2], Stream.of(1,2,3).cycle().take(8).toArray()));\n    it(\"takes advantage of isEmpty\", () => {\n        const stream = Stream.of(1,2,3);\n        if (!stream.isEmpty()) {\n            stream.head().get();\n        }\n    });\n    // unfortunately this doesn't work for now (does work on Vector & HashSet)\n    // \n    // it(\"correctly infers the more precise type on allMatch in case of typeguard\", () => {\n    //     // just checking that this compiles. 'charAt' is available on strings not numbers.\n    //     const v = Stream.of<string|number>(\"test\",\"a\");\n    //     if (v.allMatch(typeOf(\"string\"))) {\n    //         v.single().getOrThrow().charAt(0);\n    //     }\n    // });\n});\n\ndescribe(\"Stream filtering\", () => {\n    it(\"implements takeWhile correctly\", () => assert.deepEqual(\n        [1,2,3], Stream.iterate(1, x=>x+1).takeWhile(x=>x<4).toArray()));\n    it(\"filters lazily correctly\", () => assert.deepEqual(\n        [8,32,64,128], Stream.iterate(1, x => x*2).filter(x => x>5 && (x<15 || x > 30)).take(4).toArray()));\n});\n\ndescribe(\"Stream toString\", () => {\n    it(\"implements toString correctly on infinite streams\", () => assert.equal(\n        \"Stream(1, 2, ?)\", (() => {\n            const s = Stream.iterate(1, x=>x+1);\n            s.get(1);\n            return s.toString();\n        })()));\n    it(\"implements toString ok on fully-evaluated\", () => assert.equal(\n        \"Stream(1, 2, 3)\", (()=> {\n            const s = Stream.iterate(1,x=>x+1).take(3);\n            s.length();\n            return s.toString();\n        })()));\n    it(\"implements toString ok on fully-lazy\", () => assert.equal(\n        \"Stream(1, ?)\", Stream.iterate(1,x=>x+1).take(3)));\n    it(\"serializes to string correctly\", () => assert.equal(\n        \"Stream(1, ?)\", Stream.of(1,2,3).toString()));\n    it(\"serializes to string correctly - arrays & strings\", () => assert.equal(\n        \"Stream([1,'a'], ?)\", Stream.of([1,'a']).toString()));\n    it(\"serializes to string correctly - custom toString\", () => assert.equal(\n        \"Stream({field1: hi, field2: 99}, ?)\", Stream.of(new MyClass(\"hi\", 99)).toString()));\n    it(\"serializes to string correctly - plain map\", () => assert.equal(\n        \"Stream({\\\"name\\\":\\\"hi\\\",\\\"age\\\":99}, ?)\", Stream.of({name:\"hi\", age:99}).toString()));\n});\n\ndescribe(\"static Stream.zip\", () => {\n    const r = Stream.zip<[number,string,number]>([1,2], [\"a\", \"b\"], Stream.of(11,10,9));\n    assert.equal(2, r.length());\n    // check that the types are properly inferred\n    const head: [number,string,number] = r.head().getOrThrow();\n    assert.equal(1, head[0]);\n    assert.equal(\"a\", head[1]);\n    assert.equal(11, head[2]);\n\n    const other = r.get(1).getOrThrow();\n    assert.equal(2, other[0]);\n    assert.equal(\"b\", other[1]);\n    assert.equal(10, other[2]);\n});\n"
  },
  {
    "path": "tests/TestHelpers.ts",
    "content": "import * as ts from \"typescript\";\nconst fs = require('fs');\nimport * as assert from 'assert'\n\nconst TMP_FILENAME = \"tmp.ts\";\n\nfunction diagnosticMsgToString(diagMsg: string|ts.DiagnosticMessageChain): string {\n    if (typeof diagMsg === \"string\") {\n        return diagMsg;\n    }\n    let curMsg: ts.DiagnosticMessageChain|undefined = diagMsg;\n    while (curMsg) {\n        if (typeof curMsg.messageText === \"string\") {\n            return curMsg.messageText;\n        }\n        curMsg = curMsg.next;\n    }\n    return \"found no error\";\n}\n\nfunction diagnosticMsgContains(diagMsg: string|ts.DiagnosticMessageChain, contents: string): boolean {\n    return diagnosticMsgToString(diagMsg).indexOf(contents) >= 0;\n}\n\n/**\n * @hidden\n */\nexport function assertFailCompile(contents: string, expectedMsg: string): void {\n    fs.writeFileSync(\n        TMP_FILENAME, \"import { HashSet } from './dist/src/HashSet';\" +\n            \" import { Stream } from './dist/src/Stream';\" +\n            \" import { LinkedList } from './dist/src/LinkedList';\" +\n            \" import { HashMap } from './dist/src/HashMap';\" +\n            \" import { Option } from './dist/src/Option';\" +\n            \" import { Either } from './dist/src/Either';\" +\n            \" import { Vector } from './dist/src/Vector';\" + contents);\n    const tsProgram = ts.createProgram([TMP_FILENAME], {target:ts.ScriptTarget.ES2016});\n    const emitResult = tsProgram.emit();\n    const allDiagnostics = ts.getPreEmitDiagnostics(tsProgram)\n        .concat(emitResult.diagnostics as ts.Diagnostic[]);\n    const allErrorsTxt = allDiagnostics.map(x => diagnosticMsgToString(x.messageText)).join(\", \");\n    // for some reason getting tons of 'cannot find module' errors\n    // on circleCI. The test is otherwise still valid since i do \"contains\"\n    // and the real error is still in there.\n    //\n    // if (allDiagnostics.length > 1) {\n    //     console.log(allErrorsTxt);\n    // }\n    // assert.equal(1, allDiagnostics.length);\n    const isMatch = allDiagnostics.filter(d => diagnosticMsgContains(d.messageText, expectedMsg)).length > 0;\n    if (isMatch) {\n        assert.ok(true);\n    } else {\n        assert.equal(allErrorsTxt, expectedMsg);\n    }\n    fs.unlinkSync(TMP_FILENAME);\n    fs.unlinkSync(TMP_FILENAME.replace(/.ts$/, \".js\"));\n}\n"
  },
  {
    "path": "tests/Tuple2.ts",
    "content": "import { Tuple2 } from \"../src/Tuple2\";\nimport { Option } from \"../src/Option\";\nimport * as assert from 'assert'\n\ndescribe(\"Tuple2 manipulation\", () => {\n    it(\"fst works\", () => assert.equal(\n        1,\n        Tuple2.of(1,2).fst()));\n    it(\"snd works\", () => assert.equal(\n        2,\n        Tuple2.of(1,2).snd()));\n    it(\"equality works\", () => assert.ok(\n        Tuple2.of(1,2).equals(Tuple2.of(1,2))));\n    it(\"equality fails when it should\", () => assert.ok(\n        !Tuple2.of(1,2).equals(Tuple2.of(2,2))));\n    it(\"doesn't throw when given another type on equals\", () => assert.equal(\n        false, Tuple2.of(1,2).equals(<any>[1,2])));\n    it(\"doesn't throw when given null on equals\", () => assert.equal(\n        false, Tuple2.of(1,2).equals(<any>null)));\n    it(\"map1 works\", () => assert.ok(\n        Tuple2.of(2,2).equals(Tuple2.of(1,2).map1(x=>x*2))));\n    it(\"map2 works\", () => assert.ok(\n        Tuple2.of(1,4).equals(Tuple2.of(1,2).map2(x=>x*2))));\n    it(\"bimap works\", () => assert.ok(\n        Tuple2.of(2,4).equals(Tuple2.of(1,2).map((x,y)=>Tuple2.of(x*2,y*2)))));\n    it(\"build from tuple works\", () => assert.ok(\n        Tuple2.of(1,2).equals(Tuple2.ofPair([1,2]))));\n    it(\"build from array works - success\", () => assert.ok(\n        Option.of(Tuple2.of(1,2)).equals(Tuple2.ofArray<number,number>([1,2]))));\n    it(\"build from array works - failure\", () => assert.ok(\n        Tuple2.ofArray([1,2,3]).isNone()));\n    it(\"gives correct equality answer even if fst is falsy\", () => assert.ok(\n        Tuple2.of(0, \"\").equals(Tuple2.of(0, \"\"))));\n    it(\"gives correct equality answer #2\", () => assert.ok(\n        !Tuple2.of(0, \"\").equals(Tuple2.of(0, \"a\"))));\n    it(\"gives correct equality answer #3\", () => assert.ok(\n        !Tuple2.of(1, \"\").equals(Tuple2.of(0, \"\"))));\n});\n"
  },
  {
    "path": "tests/Vector.ts",
    "content": "import { Vector } from \"../src/Vector\";\nimport { Stream } from \"../src/Stream\";\nimport { MyClass } from \"./SampleData\";\nimport { typeOf } from \"../src/Comparison\";\nimport { Option } from \"../src/Option\";\nimport { assertFailCompile } from \"./TestHelpers\";\nimport * as SeqTest from \"./Seq\";\nimport * as assert from 'assert'\nimport * as util from \"util\";\n\nSeqTest.runTests(\"Vector\",\n                 Vector.ofIterable,\n                 Vector.of,\n                 Vector.empty,\n                 Vector.unfoldRight);\n\ndescribe(\"Vector toString\", () => {\n    it(\"serializes to string correctly\", () => assert.equal(\n        \"Vector(1, 2, 3)\", Vector.of(1,2,3).toString()));\n    it(\"serializes to string correctly - arrays & strings\", () => assert.equal(\n        \"Vector([1,'a'])\", Vector.of([1,'a']).toString()));\n    it(\"serializes to string correctly - custom toString\", () => assert.equal(\n        \"Vector({field1: hi, field2: 99})\", Vector.of(new MyClass(\"hi\", 99)).toString()));\n    it(\"serializes to string correctly - plain map\", () => assert.equal(\n        \"Vector({\\\"name\\\":\\\"hi\\\",\\\"age\\\":99})\", Vector.of({name:\"hi\", age:99}).toString()));\n    it(\"supports util.inspect on node\", () =>\n      assert.equal(\"Vector(1, 2, 3)\", util.inspect(Vector.of(1, 2, 3)))\n    );\n});\n\n// tests with over 32 elements\ndescribe(\"Vector over one node\", () => {\n    it(\"maps also on longer lists\", () => assert.deepEqual(\n        [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,\n         25,26,27,28,29,30,31,32,33,34,35,36,37,38,39],\n        Stream.iterate(1,x=>x+1).take(40).toVector().map(x=>x-1).toArray()));\n    it(\"iterator is correct also on longer lists\", () => assert.deepEqual(\n        [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,\n         25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40],\n        Array.from(Stream.iterate(1,x=>x+1).take(40).toVector())));\n    it(\"actually broke once\", () => assert.ok(\n        Stream.iterate(0,i=>i+1).take(33).toVector().equals(\n            Stream.iterate(0,i=>i+1).take(31).toVector().appendAll([31,32]))));\n})\n\ndescribe(\"Vector extra methods\", () => {\n    it(\"map calls the conversion function once per element\", () => {\n        let i = 0;\n        Vector.of(1,2,3).map(x=>{i+=1; return x+4;});\n        assert.equal(3, i);\n    });\n    it(\"map works on the empty vector\", () => assert.ok(\n        Vector.empty<number>().equals(Vector.empty<number>().map(x=>x+1))));\n    it(\"handles init correctly on a non-empty vector\", () => assert.deepEqual(\n        [1,2,3], Vector.of(1,2,3,4).init().toArray()));\n    it(\"handles init correctly on an empty vector\", () => assert.deepEqual(\n        [], Vector.empty<number>().init().toArray()));\n    it(\"handles init correctly on a single-element vector\", () => assert.deepEqual(\n        [], Vector.of(1).init().toArray()));\n    it(\"doesn't modify the receiver on init\", () => {\n        const x = Vector.of(1,2,3);\n        x.init();\n        assert.deepEqual(\n            [1,2,3], x.toArray())\n    });\n    it(\"handles replace correctly on a simple example\", () => assert.deepEqual(\n        [1,4,3], Vector.of(1,2,3).replace(1,4).toArray()));\n    it(\"should throw on replace on negative index\", () => assert.throws(\n        () => Vector.of(1,2,3).replace(-1,0)));\n    it(\"should throw on replace on out of bounds index\", () => assert.throws(\n        () => Vector.of(1,2,3).replace(5,0)));\n    it(\"doesn't modify the receiver on replace\", () => {\n        const x = Vector.of(1,2,3);\n        x.replace(1,4);\n        assert.deepEqual(\n            [1,2,3], x.toArray())\n    });\n    it(\"correctly infers the more precise left type on partition in case of typeguard\", () => {\n        // just checking that this compiles. 'charAt' is available on strings not numbers.\n        // the get(0) is to make sure that partition returns me a Vector\n        // not a Collection or something less precise than Vector.\n        Vector.of<string|number>(1,\"test\",2,\"a\")\n            .partition(typeOf(\"string\"))[0]\n            .get(0).getOrThrow().charAt(0);\n    });\n    it(\"correctly infers the more precise type on allMatch in case of typeguard\", () => {\n        // just checking that this compiles. 'charAt' is available on strings not numbers.\n        // the get(0) is to make sure that I get a Vector\n        // not a Collection or something less precise than Vector.\n        const v = Vector.of<string|number>(\"test\",\"a\");\n        if (v.allMatch(typeOf(\"string\"))) {\n            v.get(0).getOrThrow().charAt(0);\n        }\n    });\n});\n\ndescribe(\"Vector search methods beside those defined in Seq\", () => {\n    it(\"should find last by predicate\", () => {\n        const x = Vector.of(1,2,3,4);\n        assert.ok(\n            Option.some(4).equals(\n                x.findLast(i => i % 2 === 0)\n            )\n        );\n    });\n    it(\"should return none from findList if not found\", () => {\n        const x = Vector.of(1,2,3,4);\n        assert.ok(\n            Option.none().equals(\n                x.findLast(i => i === 5)\n            )\n        );\n    });\n    it(\"should find first index\", () => {\n        const x = Vector.of(1,2,3,4);\n        assert.ok(\n            Option.some(1).equals(\n                x.findIndex(i => i % 2 === 0)\n            )\n        );\n    });\n    it(\"should return none from findIndex it not found\", () => {\n        const x = Vector.of(1,2,3,4);\n        assert.ok(\n            Option.none().equals(\n                x.findIndex(i => i === 5)\n            )\n        );\n    });\n});\n\nfunction checkTake<T>(longer: Vector<T>, n: number, shorter: Vector<T>) {\n    const arrayBefore = longer.toArray();\n    assert.deepStrictEqual(\n        shorter.toArray(),\n        longer.take(n).toArray());\n    // taking should not have modified the original vector\n    assert.deepStrictEqual(arrayBefore, longer.toArray());\n}\n\n// check that the internal structure of the vector trie\n// is correct after take, that means also root killing and so on.\ndescribe(\"Vector.take() implementation\", () => {\n    it(\"handles simple cases correctly\", () =>\n       checkTake(Vector.of(1,2,3,4,5,6), 3, Vector.of(1,2,3)));\n    it(\"handles root killing correctly\", () => checkTake(\n        Vector.ofIterable(Stream.iterate(1,i=>i+1).take(40)),\n        3, Vector.of(1,2,3)));\n    it(\"handles double root killing correctly\", () => checkTake(\n        Vector.ofIterable(Stream.iterate(1,i=>i+1).take(1100)),\n        3, Vector.of(1,2,3)));\n    it(\"handles taking all on length multiple of node size correctly\", () => checkTake(\n        Stream.iterate(1,i=>i+1).take(128).toVector(),\n        128, Stream.iterate(1,i=>i+1).take(128).toVector()));\n    it(\"handles taking more than the whole length on length multiple of node size correctly\", () => checkTake(\n        Stream.iterate(1,i=>i+1).take(128).toVector(),\n        129, Stream.iterate(1,i=>i+1).take(128).toVector()));\n});\n\nfunction checkAppend<T>(base: Vector<T>, toAppend: Iterable<T>, combined: Vector<T>) {\n    const arrayBefore = base.toArray();\n    assert.deepStrictEqual(\n        combined.toArray(),\n        base.appendAll(toAppend).toArray());\n    // appending should not have modified the original vector\n    assert.deepStrictEqual(arrayBefore, base.toArray());\n}\n\ndescribe(\"Vector.appendAll() implementation\", () => {\n    it(\"handles simple cases correctly\", () => {\n        checkAppend(Vector.of(1,2,3), [4,5,6,7,8], Vector.of(1,2,3,4,5,6,7,8));\n    });\n    it(\"handles adding nodes correctly\", () => {\n        checkAppend(Vector.of(1,2,3), Stream.iterate(4,i=>i+1).take(70),\n                    Vector.ofIterable(Stream.iterate(1,i=>i+1).take(73)));\n    });\n    it(\"handles adding nodes correctly, adding an array\", () => {\n        checkAppend(Vector.of(1,2,3), Stream.iterate(4,i=>i+1).take(70).toArray(),\n                    Vector.ofIterable(Stream.iterate(1,i=>i+1).take(73)));\n    });\n    it(\"handles adding nodes correctly, adding a vector\", () => {\n        checkAppend(Vector.of(1,2,3), Stream.iterate(4,i=>i+1).take(70).toVector(),\n                    Vector.ofIterable(Stream.iterate(1,i=>i+1).take(73)));\n    });\n    it(\"handles large vectors at node boundaries\", () => {\n        assert.deepStrictEqual(\n            Stream.iterate(0,i=>i+1).take(86016).toArray(),\n            Stream.iterate(0,i=>i+1).take(86015).toVector().appendAll([86015]).toArray());\n    });\n});\ndescribe(\"static Vector.zip\", () => {\n    it(\"performs static correctly\", () => {\n        const r = Vector.zip<[number,string,number]>([1,2], [\"a\", \"b\"], Vector.of(11,10,9));\n        assert.equal(2, r.length());\n        // check that the types are properly inferred\n        const head: [number,string,number] = r.head().getOrThrow();\n        assert.equal(1, head[0]);\n        assert.equal(\"a\", head[1]);\n        assert.equal(11, head[2]);\n\n        const other = r.get(1).getOrThrow();\n        assert.equal(2, other[0]);\n        assert.equal(\"b\", other[1]);\n        assert.equal(10, other[2]);\n    });\n});\ndescribe(\"vector replaceFirst\", () => {\n    it(\"empty vector\", () => {\n        assert.ok(Vector.empty<number>().equals(Vector.empty<number>().replaceFirst(2, 3)));\n    });\n    it(\"value not present\", () => {\n        assert.ok(Vector.of(1, 3, 4, 5).equals(Vector.of(1, 3, 4, 5).replaceFirst(2, 3)));\n    });\n    it(\"type with real equals\", () => {\n        assert.ok(Vector.of(new MyClass(\"c\", 2), new MyClass(\"b\", 2), new MyClass(\"a\", 1)).equals(\n            Vector.of(new MyClass(\"a\", 1), new MyClass(\"b\", 2), new MyClass(\"a\", 1))\n                .replaceFirst(new MyClass(\"a\", 1), new MyClass(\"c\", 2))));\n    });\n    it(\"should fail compilation on replace if not equality\", () =>\n       assertFailCompile(\n           \"Vector.of([1]).replaceFirst([1], [2])\", \"Argument of type \\'\" +\n               \"number[]\\' is not assignable to parameter\"));\n});\ndescribe(\"vector replaceAll\", () => {\n    it(\"empty vector\", () => {\n        assert.ok(Vector.empty<number>().equals(Vector.empty<number>().replaceAll(2, 3)));\n    });\n    it(\"value not present\", () => {\n        assert.ok(Vector.of(1, 3, 4, 5).equals(Vector.of(1, 3, 4, 5).replaceFirst(2, 3)));\n    });\n    it(\"type with real equals\", () => {\n        assert.ok(Vector.of(new MyClass(\"c\", 2), new MyClass(\"b\", 2), new MyClass(\"c\", 2)).equals(\n            Vector.of(new MyClass(\"a\", 1), new MyClass(\"b\", 2), new MyClass(\"a\", 1))\n                .replaceAll(new MyClass(\"a\", 1), new MyClass(\"c\", 2))));\n    });\n    it(\"should fail compilation on replace if not equality\", () =>\n       assertFailCompile(\n           \"Vector.of([1]).replaceAll([1], [2])\", \"Argument of type \\'\" +\n               \"number[]\\' is not assignable to parameter\"));\n});\ndescribe(\"vector indexOf\", () => {\n    it(\"empty vector\", () => {\n        assert.ok(Option.none<number>().equals(Vector.empty<number>().indexOf(2)));\n    });\n    it(\"value not present\", () => {\n        assert.ok(Option.none<number>().equals(Vector.of(1, 3, 4, 5).indexOf(2)));\n    });\n    it(\"type with real equals\", () => {\n        assert.ok(Option.of(1).equals(\n            Vector.of(new MyClass(\"a\", 1), new MyClass(\"b\", 2), new MyClass(\"a\", 1))\n                .indexOf(new MyClass(\"b\", 2))));\n    });\n    it(\"should fail compilation on replace if not equality\", () =>\n       assertFailCompile(\n           \"Vector.of([1]).indexOf([1])\", \"Argument of type \\'\" +\n               \"number[]\\' is not assignable to parameter\"));\n});\n"
  },
  {
    "path": "tsconfig.benchmarks.json",
    "content": "{\n    \"extends\": \"./tsconfig.json\",\n    \"include\": [\n        \"src/**/*\",\n        \"benchmarks/**/*\"\n    ]\n}\n"
  },
  {
    "path": "tsconfig.docgen.json",
    "content": "{\n    \"extends\": \"./tsconfig.json\",\n    \"include\": [\n        \"src/**/*\",\n        \"scripts/**/*\"\n    ]\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n    \"compilerOptions\": {\n        \"noImplicitAny\": true,\n        \"strictNullChecks\": true,\n        \"noImplicitReturns\": true,\n        \"noImplicitThis\": true,\n        \"alwaysStrict\": true,\n        \"strict\": true,\n        \"rootDir\": \"./\",\n        \"outDir\": \"./dist\",\n        \"declaration\": true,\n        \"sourceMap\": true,\n        \"lib\": [\"es2015\", \"dom\"] // I need DOM because of typedoc..\n    }\n}\n"
  },
  {
    "path": "tsconfig.prepublish.json",
    "content": "{\n    \"extends\": \"./tsconfig.json\",\n    \"include\": [\n        \"src/**/*\"\n    ]\n}\n"
  },
  {
    "path": "tsconfig.test.json",
    "content": "{\n    \"extends\": \"./tsconfig.json\",\n    \"include\": [\n        \"src/**/*\",\n        \"tests/**/*\"\n    ]\n}\n"
  },
  {
    "path": "www_demo/index.html",
    "content": "<html>\n    <head>\n        <script src=\"../dist/src/prelude_ts.min.js\"></script>\n        <script src=\"../dist/src/chrome_dev_tools_formatters.js\"></script>\n        <script>\n         const v = prelude_ts.LinkedList.of(\n             {x:1,y:[1,2,3]},\n             prelude_ts.Tuple2.of(prelude_ts.Option.none(), prelude_ts.Option.of({x:2,y:1})),\n             prelude_ts.Stream.iterate(1,x=>x+1).take(5),3);\n         const v1 = prelude_ts.HashMap.of(\n             [\"a\",{x:1,y:prelude_ts.Vector.of(1,2)}],\n             [\"b\",{x:2,y:prelude_ts.Vector.empty()}]);\n         alert(v1.toString());\n        </script>\n    </head>\n    <body>\n    </body>\n</html>\n"
  }
]