[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\nend_of_line = lf\ninsert_final_newline = true\ntrim_trailing_whitespace = true\ncharset = utf-8\nindent_style = space\nindent_size = 2\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "<!--\nPLEASE HELP US PROCESS GITHUB ISSUES FASTER BY PROVIDING THE FOLLOWING INFORMATION.\n\nISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION.\n-->\n\n## I'm submitting a...\n<!-- Check one of the following options with \"x\" -->\n<pre><code>\n[ ] Regression (a behavior that used to work and stopped working in a new release)\n[ ] Bug report  <!-- Please search GitHub for a similar issue or PR before submitting -->\n[ ] Feature request\n[ ] Documentation issue or request\n[ ] Support request => Please do not submit support request here, instead see https://github.com/LokiJS-Forge/LokiDB/blob/master/CONTRIBUTING.md#question\n</code></pre>\n\n## Current behavior\n<!-- Describe how the issue manifests. -->\n\n\n## Expected behavior\n<!-- Describe what the desired behavior would be. -->\n\n\n## Minimal reproduction of the problem with instructions\n<!--\nFor bug reports please provide the *STEPS TO REPRODUCE* and if possible a *MINIMAL DEMO* of the problem via https://plnkr.co or similar.\n-->\n\n## What is the motivation / use case for changing the behavior?\n<!-- Describe the motivation or the concrete use case. -->\n\n\n## Environment\n\n<pre><code>\nLokiDB version: X.Y.Z\n<!-- Check whether this is still an issue in the most recent LokiDB version -->\n\nBrowser/Node version: Browser X.Y.Z.\n\nOthers:\n<!-- Anything else relevant?  Operating system version, other frameworks, ... -->\n</code></pre>\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "## PR Checklist\nPlease check if your PR fulfills the following requirements:\n\n- [ ] The commit message follows our guidelines: https://github.com/LokiJS-Forge/LokiDB/blob/master/CONTRIBUTING.md#commit\n- [ ] Tests for the changes have been added (for bug fixes / features)\n- [ ] Docs have been added / updated (for bug fixes / features)\n\n\n## PR Type\nWhat kind of change does this PR introduce?\n\n<!-- Please check the one that applies to this PR using \"x\". -->\n```\n[ ] Bugfix\n[ ] Feature\n[ ] Code style update (formatting, local variables)\n[ ] Refactoring (no functional changes, no api changes)\n[ ] Build related changes\n[ ] CI related changes\n[ ] Documentation content changes\n[ ] Other... Please describe:\n```\n\n## What is the current behavior?\n<!-- Please describe the current behavior that you are modifying, or link to a relevant issue. -->\n\nIssue Number: N/A\n\n\n## What is the new behavior?\n\n\n## Does this PR introduce a breaking change?\n```\n[ ] Yes\n[ ] No\n```\n\n<!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. -->\n\n\n## Other information\n"
  },
  {
    "path": ".gitignore",
    "content": "# IDE\n.idea/\n\n# NODE\nnode_modules/\n\n# Tests\ncoverage/\n.nyc_output\n\n# Typescript\n.ts/\n\n# Build artifacts\nbuild/\ndist/packages-dist/\npackages/**/*.html\nsite/\ndocs/api/\n\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: python\npython:\n  - \"3.5\"\nnode_js:\n    - \"10\"\n\ndist: trusty\nsudo: required\n\nenv:\n    global:\n        - GIT_NAME: Travis CI\n        - GIT_EMAIL: builds@travis-ci.org\n        - GIT_BRANCH: master\n\nservices:\n  - elasticsearch\n\naddons:\n  chrome: stable\n\nbefore_install:\n  - pip3 install mkdocs\n  - pip3 install mkdocs-material\n\nscript:\n    - npm install\n    - PATH=${PATH}:\\.\\/node_modules\\/\\.bin/\n    - npm run lint\n    - npm test\n    - codecov\n    - npm run docs\n    - mkdocs build\n    - npm run build\n    - npm run build -- --dist\n    - npm install --prefix integration\n    - npm run test:integration\n\nafter_success:\n  - npm run deploy\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "<a name=\"2.1.0\"></a>\n# [2.1.0](https://github.com/LokiJS-Forge/LokiDB/compare/2.0.0...2.1.0) (2020-08-23)\n\n\n### Features\n\n* **fts:** support optional, empty or number fields ([#181](https://github.com/LokiJS-Forge/LokiDB/issues/181)) ([57e2ff8](https://github.com/LokiJS-Forge/LokiDB/commit/57e2ff8))\n\n\n<a name=\"2.0.0\"></a>\n# [2.0.0](https://github.com/LokiJS-Forge/LokiDB/compare/2.0.0-beta.9...2.0.0) (2020-08-22)\n\n\n### Bug Fixes\n\n* **persistence:** ignore error if database is not found on autoload ([#179](https://github.com/LokiJS-Forge/LokiDB/issues/179)) ([d1703c6](https://github.com/LokiJS-Forge/LokiDB/commit/d1703c6))\n\n\n<a name=\"2.0.0-beta.9\"></a>\n# [2.0.0-beta.9](https://github.com/LokiJS-Forge/LokiDB/compare/2.0.0-beta.8...2.0.0-beta.9) (2020-02-07)\n\n\n### Bug Fixes\n\n* **loki:** unique search with no matching entry should not fail ([#172](https://github.com/LokiJS-Forge/LokiDB/issues/172)) ([fd2c7d9](https://github.com/LokiJS-Forge/LokiDB/commit/fd2c7d9))\n* **loki:** use global.proceas in getENV ([#170](https://github.com/LokiJS-Forge/LokiDB/issues/170)) ([a65e668](https://github.com/LokiJS-Forge/LokiDB/commit/a65e668))\n\n\n<a name=\"2.0.0-beta.8\"></a>\n# [2.0.0-beta.8](https://github.com/LokiJS-Forge/LokiDB/compare/2.0.0-beta.7...2.0.0-beta.8) (2018-09-14)\n\n\n### Bug Fixes\n\n* **loki:** define nested properties on rollback transaction ([#149](https://github.com/LokiJS-Forge/LokiDB/issues/149)) ([9e06e91](https://github.com/LokiJS-Forge/LokiDB/commit/9e06e91))\n\n\n### Features\n\n* **loki:** remove binary index  ([#146](https://github.com/LokiJS-Forge/LokiDB/issues/146)) ([1fb99f2](https://github.com/LokiJS-Forge/LokiDB/commit/1fb99f2))\n* **loki:** user definable comparators and operator packages ([#152](https://github.com/LokiJS-Forge/LokiDB/issues/152)) ([5c14bc2](https://github.com/LokiJS-Forge/LokiDB/commit/5c14bc2))\n\n\n<a name=\"2.0.0-beta.7\"></a>\n# [2.0.0-beta.7](https://github.com/LokiJS-Forge/LokiDB/compare/2.0.0-beta.6...2.0.0-beta.7) (2018-06-27)\n\n\n### Bug Fixes\n\n* **full-text-search:** apply bool query boost to subquery results ([#122](https://github.com/LokiJS-Forge/LokiDB/issues/122)) ([5548fe5](https://github.com/LokiJS-Forge/LokiDB/commit/5548fe5))\n* **full-text-search:** handle not and filter bool queries right ([#128](https://github.com/LokiJS-Forge/LokiDB/issues/128)) ([98d0cd8](https://github.com/LokiJS-Forge/LokiDB/commit/98d0cd8))\n* **loki:** fix autosave and autoload of the database ([#112](https://github.com/LokiJS-Forge/LokiDB/issues/112)) ([ef260fd](https://github.com/LokiJS-Forge/LokiDB/commit/ef260fd))\n* **loki:** when cloning, meta will be applied correctly and clones emitted ([#111](https://github.com/LokiJS-Forge/LokiDB/issues/111)) ([d287a2d](https://github.com/LokiJS-Forge/LokiDB/commit/d287a2d)), closes [techfort/LokiJS#666](https://github.com/techfort/LokiJS/issues/666)\n\n\n### Features\n\n* improve type notation ([#109](https://github.com/LokiJS-Forge/LokiDB/issues/109)) ([3b60c9f](https://github.com/LokiJS-Forge/LokiDB/commit/3b60c9f))\n* **full-text-search:** allow number or string as document id ([#115](https://github.com/LokiJS-Forge/LokiDB/issues/115)) ([1d81e25](https://github.com/LokiJS-Forge/LokiDB/commit/1d81e25))\n* **full-text-search:** export function analyze ([#102](https://github.com/LokiJS-Forge/LokiDB/issues/102)) ([c1dd78c](https://github.com/LokiJS-Forge/LokiDB/commit/c1dd78c))\n* **full-text-search:** if elasticsearch is not available, disable its unit test ([#98](https://github.com/LokiJS-Forge/LokiDB/issues/98)) ([a1c7d8d](https://github.com/LokiJS-Forge/LokiDB/commit/a1c7d8d))\n* **full-text-search:** implement conditional minimum should match parameter ([#129](https://github.com/LokiJS-Forge/LokiDB/issues/129)) ([baa6311](https://github.com/LokiJS-Forge/LokiDB/commit/baa6311))\n* **full-text-search:** make analyzers classes instead of objects ([#123](https://github.com/LokiJS-Forge/LokiDB/issues/123)) ([1959688](https://github.com/LokiJS-Forge/LokiDB/commit/1959688))\n\n\n<a name=\"2.0.0-beta.6\"></a>\n# [2.0.0-beta.6](https://github.com/LokiJS-Forge/LokiDB/compare/2.0.0-beta.5...2.0.0-beta.6) (2018-03-23)\n\nFor a better distinction, the library has been renamed to LokiDB.\n\nThe repository is now located under https://github.com/LokiJS-Forge/LokiDB\n\nThe npm packages can be found under the organization scope @lokidb.\n\n\n## Commit Summary\n### Bug Fixes\n\n* **full-text-search:** fix fuzzy's prefix length, edit distance and idf ([#68](https://github.com/LokiJS-Forge/LokiDB/issues/68)) ([da06836](https://github.com/LokiJS-Forge/LokiDB/commit/da06836))\n* **full-text-search:** rename field option \"name\" to \"field\" ([#67](https://github.com/LokiJS-Forge/LokiDB/issues/67)) ([ff74219](https://github.com/LokiJS-Forge/LokiDB/commit/ff74219))\n* **loki:** fix a autosave race condition when using asynchronous adapter ([#79](https://github.com/LokiJS-Forge/LokiDB/issues/79)) ([db26d02](https://github.com/LokiJS-Forge/LokiDB/commit/db26d02))\n* **loki:** fix binary index in batch updates when not cloning ([#78](https://github.com/LokiJS-Forge/LokiDB/issues/78)) ([8081799](https://github.com/LokiJS-Forge/LokiDB/commit/8081799))\n\n\n### Features\n\n* **full-text-search:** remove query builder ([#73](https://github.com/LokiJS-Forge/LokiDB/issues/73)) ([84757ab](https://github.com/LokiJS-Forge/LokiDB/commit/84757ab))\n* **full-text-search:** remove unnecessary array query ([#75](https://github.com/LokiJS-Forge/LokiDB/issues/75)) ([4ff5165](https://github.com/LokiJS-Forge/LokiDB/commit/4ff5165))\n* **full-text-search:** replace the old \"tokenizer\" class with an analyzer interface ([#76](https://github.com/LokiJS-Forge/LokiDB/issues/76)) ([2d44384](https://github.com/LokiJS-Forge/LokiDB/commit/2d44384))\n* **full-text-search:** return score result as an equivalent array to result set data ([#69](https://github.com/LokiJS-Forge/LokiDB/issues/69)) ([7ea17c0](https://github.com/LokiJS-Forge/LokiDB/commit/7ea17c0))\n* **loki:** add diagnostic function to test binary index validity ([#85](https://github.com/LokiJS-Forge/LokiDB/issues/85)) ([d611722](https://github.com/LokiJS-Forge/LokiDB/commit/d611722))\n* **loki:** add option to disable meta property for documents added to a collection ([#80](https://github.com/LokiJS-Forge/LokiDB/issues/80)) ([1a49470](https://github.com/LokiJS-Forge/LokiDB/commit/1a49470))\n* **loki:** add simplified javascript comparisons $jgt, $jgte, $jlt, $jlte, $jbetween ([#87](https://github.com/LokiJS-Forge/LokiDB/issues/87)) ([32e4b1e](https://github.com/LokiJS-Forge/LokiDB/commit/32e4b1e))\n* **loki:** change and improve nested property support ([#81](https://github.com/LokiJS-Forge/LokiDB/issues/81)) ([2730284](https://github.com/LokiJS-Forge/LokiDB/commit/2730284))\n* **loki:** return an existing collection if a collection with the same name already exists ([#77](https://github.com/LokiJS-Forge/LokiDB/issues/77)) ([75afd67](https://github.com/LokiJS-Forge/LokiDB/commit/75afd67))\n* **loki:** simplesort leverages binary indices better when filtered ([#83](https://github.com/LokiJS-Forge/LokiDB/issues/83)) ([4d1b25b](https://github.com/LokiJS-Forge/LokiDB/commit/4d1b25b))\n\n\n<a name=\"2.0.0-beta.5\"></a>\n# [2.0.0-beta.5](https://github.com/LokiJS-Forge/LokiJS2/compare/2.0.0-beta.4...2.0.0-beta.5) (2018-01-02)\n\n\n### Bug Fixes\n\n* **full-text-search-language:** add missing function export ([#64](https://github.com/LokiJS-Forge/LokiJS2/issues/64)) ([9b926e2](https://github.com/LokiJS-Forge/LokiJS2/commit/9b926e2))\n\n\n### Features\n\n* improve typings ([#62](https://github.com/LokiJS-Forge/LokiJS2/issues/62)) ([b44f550](https://github.com/LokiJS-Forge/LokiJS2/commit/b44f550))\n* **full-text-search:** add an optional score explanation ([#65](https://github.com/LokiJS-Forge/LokiJS2/issues/65)) ([9fde195](https://github.com/LokiJS-Forge/LokiJS2/commit/9fde195))\n* **memory-storage:** move memory storage to a separate package ([#63](https://github.com/LokiJS-Forge/LokiJS2/issues/63)) ([7cea02a](https://github.com/LokiJS-Forge/LokiJS2/commit/7cea02a))\n\n\n<a name=\"2.0.0-beta.4\"></a>\n# [2.0.0-beta.4](https://github.com/LokiJS-Forge/LokiJS2/compare/2.0.0-beta.3...2.0.0-beta.4) (2017-12-01)\n\n\n### Features\n\n* **full-text-search:** make index Unicode safe and improve fuzzy performance ([#55](https://github.com/LokiJS-Forge/LokiJS2/issues/55)) ([f1dea05](https://github.com/LokiJS-Forge/LokiJS2/commit/f1dea05))\n\n\n<a name=\"2.0.0-beta.3\"></a>\n# [2.0.0-beta.3](https://github.com/LokiJS-Forge/LokiJS2/compare/2.0.0-beta.2...2.0.0-beta.3) (2017-11-26)\n\n\n### Bug Fixes\n\n* coverage ([#42](https://github.com/LokiJS-Forge/LokiJS2/issues/42)) ([3509429](https://github.com/LokiJS-Forge/LokiJS2/commit/3509429))\n* **full-text-search:** fix fuzzy extended to withdraw wrong results ([#51](https://github.com/LokiJS-Forge/LokiJS2/issues/51)) ([4d493ac](https://github.com/LokiJS-Forge/LokiJS2/commit/4d493ac))\n* **loki:** cloning method for specific classes ([#30](https://github.com/LokiJS-Forge/LokiJS2/issues/30)) ([4f4a182](https://github.com/LokiJS-Forge/LokiJS2/commit/4f4a182))\n* **loki:** fix error if passed parameters are not serializable for transform ([#43](https://github.com/LokiJS-Forge/LokiJS2/issues/43)) ([dde34ed](https://github.com/LokiJS-Forge/LokiJS2/commit/dde34ed))\n* **loki:** implement deep clone as default clone option ([#44](https://github.com/LokiJS-Forge/LokiJS2/issues/44)) ([2f3b718](https://github.com/LokiJS-Forge/LokiJS2/commit/2f3b718))\n\n\n### Features\n\n* **full-text-search:** add full-text-search as separate package ([#35](https://github.com/LokiJS-Forge/LokiJS2/issues/35)) ([14b9947](https://github.com/LokiJS-Forge/LokiJS2/commit/14b9947))\n* **full-text-search:** english and german language support ([3a93477](https://github.com/LokiJS-Forge/LokiJS2/commit/3a93477))\n* **full-text-search:** implement extended fuzzy ([#47](https://github.com/LokiJS-Forge/LokiJS2/issues/47)) ([0579026](https://github.com/LokiJS-Forge/LokiJS2/commit/0579026))\n* **loki:** add 'dataOptions' to eqJoin ([#33](https://github.com/LokiJS-Forge/LokiJS2/issues/33)) ([efa450e](https://github.com/LokiJS-Forge/LokiJS2/commit/efa450e))\n* **loki:** add optional flag for Changes API to limit update operation output to modified properties only ([#29](https://github.com/LokiJS-Forge/LokiJS2/issues/29)) ([a8abe99](https://github.com/LokiJS-Forge/LokiJS2/commit/a8abe99))\n* **loki:** allow sorting on nested properties ([#31](https://github.com/LokiJS-Forge/LokiJS2/issues/31)) ([9b426a4](https://github.com/LokiJS-Forge/LokiJS2/commit/9b426a4))\n* **loki:** chained/transform map op now accepts 'dataOptions' for clone/removeMeta ([#34](https://github.com/LokiJS-Forge/LokiJS2/issues/34)) ([67d61ac](https://github.com/LokiJS-Forge/LokiJS2/commit/67d61ac))\n* **loki:** make Resultset and DynamicView sortable by full-text-search scoring ([#45](https://github.com/LokiJS-Forge/LokiJS2/issues/45)) ([0a5b946](https://github.com/LokiJS-Forge/LokiJS2/commit/0a5b946))\n* **loki:** rename collection ([#32](https://github.com/LokiJS-Forge/LokiJS2/issues/32)) ([745e025](https://github.com/LokiJS-Forge/LokiJS2/commit/745e025))\n* integrate full-text-search to loki (insert/update/remove + search) ([8fbc174](https://github.com/LokiJS-Forge/LokiJS2/commit/8fbc174))\n* move to typescript ([#36](https://github.com/LokiJS-Forge/LokiJS2/issues/36)) ([d47f190](https://github.com/LokiJS-Forge/LokiJS2/commit/d47f190))\n\n\n<a name=\"2.0.0-beta.2\"></a>\n# [2.0.0-beta.2](https://github.com/LokiJS-Forge/LokiJS2/compare/2.0.0-beta.1...2.0.0-beta.2) (2017-09-21)\n\n\n\n\n\n<a name=\"2.0.0-beta.1\"></a>\n# 2.0.0-beta.1 (2017-09-21)\n\n\n### Features\n\n* **fs-storage:** add fs storage as separate package ([#19](https://github.com/LokiJS-Forge/LokiJS2/issues/19)) ([ec2e523](https://github.com/LokiJS-Forge/LokiJS2/commit/ec2e523))\n* **indexed-storage:** add indexed storage as separate package ([#20](https://github.com/LokiJS-Forge/LokiJS2/issues/20)) ([1150029](https://github.com/LokiJS-Forge/LokiJS2/commit/1150029))\n* **local-storage:** add local storage as separate package ([#18](https://github.com/LokiJS-Forge/LokiJS2/issues/18)) ([548abfe](https://github.com/LokiJS-Forge/LokiJS2/commit/548abfe))\n* **loki:** add lokijs as core package ([#9](https://github.com/LokiJS-Forge/LokiJS2/issues/9)) ([f670ea0](https://github.com/LokiJS-Forge/LokiJS2/commit/f670ea0))\n* **partitioning-adapter:** add partitioning-adapter as separate package ([#14](https://github.com/LokiJS-Forge/LokiJS2/issues/14)) ([c6b18ca](https://github.com/LokiJS-Forge/LokiJS2/commit/c6b18ca))\n\n\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at lutztonineubert@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "<!-- This page is a modified version of [Angular's CONTRIBUTING.md](https://github.com/angular/angular/blob/master/CONTRIBUTING.md). -->\n\n# Contributing to LokiDB\n\nWe would love for you to contribute to LokiDB and help make it even better than it is\ntoday! As a contributor, here are the guidelines we would like you to follow:\n\n - [Code of Conduct](#coc)\n - [Question or Problem?](#question)\n - [Issues and Bugs](#issue)\n - [Feature Requests](#feature)\n - [Submission Guidelines](#submit)\n - [Coding Rules](#rules)\n - [Test LokiDB](#develop)\n\n## <a name=\"coc\"></a> Code of Conduct\nHelp us keep LokiDB open and inclusive. Please read and follow our [Code of Conduct][coc].\n\n## <a name=\"question\"></a> Got a Question or Problem?\n\nPlease ask your questions tagged with `lokidb` at [Stack Overflow][stackoverflow].\n\nIf you would like to chat about the questions in real-time, you can reach out via [our gitter channel][gitter].\n\n## <a name=\"issue\"></a> Found a Bug?\nIf you find a bug in the source code, you can help us by\n[submitting an issue](#submit-issue) to our [GitHub Repository][github]. Even better, you can\n[submit a Pull Request](#submit-pr) with a fix.\n\n## <a name=\"feature\"></a> Missing a Feature?\nYou can *request* a new feature by [submitting an issue](#submit-issue) to our GitHub\nRepository. If you would like to *implement* a new feature, please submit an issue with\na proposal for your work first, to be sure that we can use it.\n\n## <a name=\"submit\"></a> Submission Guidelines\n\n### <a name=\"submit-issue\"></a> Submitting an Issue\n\nBefore you submit an issue, please search the issue tracker, maybe an issue for your problem already exists and the discussion might inform you of workarounds readily available.\n\nWe want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs we will systematically ask you to provide a minimal reproduction scenario using http://plnkr.co. Having a live, reproducible scenario gives us wealth of important information without going back & forth to you with additional questions like:\n\n- version of LokiDB used\n- 3rd-party libraries and their versions\n- and most importantly - a use-case that fails\n\nA minimal reproduce scenario using http://plnkr.co/ allows us to quickly confirm a bug (or point out coding problem) as well as confirm that we are fixing the right problem. If plunker is not a suitable way to demonstrate the problem (for example for issues related to our npm packaging), please create a standalone git repository demonstrating the problem.\n\nWe will be insisting on a minimal reproduce scenario in order to save maintainers time and ultimately be able to fix more bugs. Interestingly, from our experience users often find coding problems themselves while preparing a minimal plunk. We understand that sometimes it might be hard to extract essentials bits of code from a larger code-base but we really need to isolate the problem before we can fix it.\n\nUnfortunately we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you we are going to close an issue that don't have enough info to be reproduced.\n\nYou can file new issues by filling out our [new issue form][new-issue].\n\n\n### <a name=\"submit-pr\"></a> Submitting a Pull Request (PR)\nBefore you submit your Pull Request (PR) consider the following guidelines:\n\n* Search [GitHub][pulls] for an open or closed PR that relates to your submission. You don't want to duplicate effort.\n* Create your patch, **including appropriate test cases**.\n* Follow our [Coding Rules](#rules).\n* Run the full LokiDB test suite, as described in the [developer documentation][dev-doc],\n  and ensure that all tests pass.\n* Commit your changes using a descriptive commit message that follows our\n  [commit message conventions](#commit). Adherence to these conventions\n  is necessary because release notes are automatically generated from these messages.\n* In GitHub, send a pull request to `LokiDB:master`.\n* If we suggest changes then:\n  * Make the required updates.\n  * Re-run the LokiDB test suites to ensure tests are still passing.\n\nThat's it! Thank you for your contribution!\n\n## <a name=\"rules\"></a> Coding Rules\nTo ensure consistency throughout the source code, keep these rules in mind as you are working:\n\n* All features or bug fixes **must be tested** by one or more specs (unit-tests).\n* All public API methods **must be documented**. (Details TBC).\n* We use a consistent code formatting. An automated formatter is available, see the [developer guideline][dev-doc].\n\n## <a name=\"commit\"></a> Commit Message Guidelines\n\nWe have very precise rules over how our git commit messages can be formatted.  This leads to **more\nreadable messages** that are easy to follow when looking through the **project history**.  But also,\nwe use the git commit messages to **generate the LokiDB change log**.\n\n### Commit Message Format\nEach commit message consists of a **header**, a **body** and a **footer**.  The header has a special\nformat that includes a **type**, a **scope** and a **subject**:\n\n```\n<type>(<scope>): <subject>\n<BLANK LINE>\n<body>\n<BLANK LINE>\n<footer>\n```\n\nThe **header** is mandatory and the **scope** of the header is optional.\n\nAny line of the commit message cannot be longer 100 characters! This allows the message to be easier\nto read on GitHub as well as in various git tools.\n\nFooter should contain a [closing reference to an issue](https://help.github.com/articles/closing-issues-via-commit-messages/) if any.\n\nSamples: (even more [samples][commits])\n\n```\ndocs(changelog): update change log to beta.5\n```\n```\nfix(release): need to depend on latest rxjs and zone.js\n\nThe version in our package.json gets copied to the one we publish, and users need the latest of these.\n```\n\n### Revert\nIf the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.\n\n### Type\nMust be one of the following:\n\n* **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)\n* **ci**: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)\n* **docs**: Documentation only changes\n* **feat**: A new feature\n* **fix**: A bug fix\n* **perf**: A code change that improves performance\n* **refactor**: A code change that neither fixes a bug nor adds a feature\n* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)\n* **test**: Adding missing tests or correcting existing tests\n\n### Scope\nThe scope should be the name of the npm package affected (as perceived by person reading changelog generated from commit messages.\n\nThe following is the list of supported scopes:\n\n* **loki**: The LokiDB database.\n* **partitioning-adapter**: The partitioning adapter.\n* **local-storage**: The local storage adapter.\n* **indexed-storage**: The indexed db storage adapter.\n* **fs-storage**: The file system storage adapter.\n* **memory-storage**: The in-memory storage adapter.\n* **full-text-search**: The full-text search engine.\n* **full-text-search-language**: The language analyzer utility package.\n* **full-text-search-language-de**: The german language analyzer.\n* **full-text-search-language-en**: The english language analyzer.\n\nThere are currently a few exceptions to the \"use package name\" rule:\n\n* **packaging**: used for changes that change the npm package layout in all of our packages, e.g. public path changes, package.json changes done to all packages, d.ts file/format changes, changes to bundles, etc.\n* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all packages (e.g. `style: add missing semicolons`)\n\n### Subject\nThe subject contains succinct description of the change:\n\n* use the imperative, present tense: \"change\" not \"changed\" nor \"changes\"\n* don't capitalize first letter\n* no dot (.) at the end\n\n### Body\nJust as in the **subject**, use the imperative, present tense: \"change\" not \"changed\" nor \"changes\".\nThe body should include the motivation for the change and contrast this with previous behavior.\n\n### Footer\nThe footer should contain any information about **Breaking Changes** and is also the place to\nreference GitHub issues that this commit **Closes**.\n\n**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.\n\n[coc]: https://github.com/LokiJS-Forge/LokiDB/blob/master/CODE_OF_CONDUCT.md\n[dev-doc]: https://github.com/LokiJS-Forge/LokiDB/blob/master/DEVELOPER.md\n[github]: https://github.com/LokiJS-Forge/LokiDB\n[new-issue]: https://github.com/LokiJS-Forge/LokiDB/issues/new\n[pulls]: https://github.com/LokiJS-Forge/LokiDB/pulls\n[commit]: https://github.com/LokiJS-Forge/LokiDB/commits/master\n[gitter]: https://gitter.im/techfort/LokiDB\n[plunker]: http://plnkr.co/edit\n[stackoverflow]: http://stackoverflow.com/questions/tagged/lokidb?sort=newest\n"
  },
  {
    "path": "DEVELOPER.md",
    "content": "<!-- This page is a modified version of [Angular](https://github.com/angular/angular/blob/master/docs/DEVELOPER.md). -->\n\n# Building and testing LokiDB\n\nThis document describes how to set up your development environment to build and test LokiDB.\n\n* [Prerequisite software](#prerequisite-software)\n* [Running tests](#running-tests)\n* [Formatting your source code](#formatting-your-source-code)\n* [Building LokiDB](#building-lokidb)\n\nSee the [contribution guidelines][contribution] if you'd like to contribute to LokiDB.\n\n## Prerequisite software\n\nBefore you can build and test LokiDB, you must install and configure the\nfollowing products on your development machine:\n\n* [Git](http://git-scm.com) and/or the **GitHub app** (for [Mac](http://mac.github.com) or\n  [Windows](http://windows.github.com)); [GitHub's Guide to Installing\n  Git](https://help.github.com/articles/set-up-git) is a good source of information.\n\n* [Node.js](http://nodejs.org), (version `>=7.0.0`) which is used to run tests and generate distributable files.\n  We also use Node's Package Manager, `npm`(version `>=4.0.0`), which comes with Node.\n  Depending on your system, you can install Node either from source or as a pre-packaged bundle.\n\n* [Elasticsearch](https://www.elastic.co/downloads/elasticsearch) which is used to unit test LokiDB's full text search.\n\n## Running tests\n\nTo run tests:\n\n```shell\n$ npm run test            # Run all LokiDB tests\n\n$ npm run test:web        # Run tests only in web browser\n$ npm run test:node       # Run tests only in node\n```\n\nAll the tests are executed on our Continuous Integration infrastructure and a PR could only be merged once the tests pass.\n\n## Formatting your source code\n\nLokiDB uses [ESLint][eslint] to format the source code. If the source code is not properly formatted, the CI will fail and the PR can not be merged.\n\nYou can check that your code is properly formatted and adheres to coding style by running:\n\n``` shell\n$ npm run lint\n```\n\nYou can automatically format your code by running:\n\n``` shell\n$ npm run lint:fix\n```\n\n## Building LokiDB\n\nTo build LokiDB, run:\n\n``` shell\n$ npm run build\n```\n\n[eslint]: https://eslint.org/\n[contribution]: https://github.com/LokiJS-Forge/LokiDB/blob/master/CONTRIBUTING.md\n"
  },
  {
    "path": "LICENSE",
    "content": "This text consists of three parts:\n\nPart I: Remarks regarding the license given in\nPart II: MIT License\nPart III: Apache License\n\n-------------------------------------------------------------------------------\nPart I:\n\nLokiDB is mostly distributed under the MIT License.\n\nExcept the following packages:\n\n@lokidb/full-text-search\n  - Apache License (https://lucene.apache.org/)\n  - Apache License (https://www.elastic.co/)\n\n-------------------------------------------------------------------------------\nPart II:\n\n                                 MIT License\n\n  Copyright (c) 2015-2018 Joe Minichino <joe.minichino@gmail.com>\n                          David Easterday <admin@obeliskos.com>\n                          Toni Neubert  <lutztonineubert@gmail.com>\n\n  Permission is hereby granted, free of charge, to any person obtaining a\n  copy of this software and associated documentation files (the \"Software\"),\n  to deal in the Software without restriction, including without limitation\n  the rights to use, copy, modify, merge, publish, distribute, sublicense,\n  and/or sell copies of the Software, and to permit persons to whom the\n  Software is furnished to do so, subject to the following conditions:\n\n  The above copyright notice and this permission notice shall be included in\n  all copies or substantial portions of the Software.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n  DEALINGS IN THE SOFTWARE.\n\n\n-------------------------------------------------------------------------------\nPart III:\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n"
  },
  {
    "path": "README.md",
    "content": "[![npm status][npm]][npm-url]\n[![build status][build]][build-url]\n[![coverage status][coverage]][coverage-url]\n\n# LokiDB\n\nLokiDB is a document oriented database written in TypeScript.\n\nIts purpose is to store javascript objects as documents in a blazing fast nosql fashion and retrieve them with a similar mechanism.\n\nLokiDB is the official successor of [LokiJS][lokijs-url].\n\n## Install\n\nInstall with npm:\n\n```bash\nnpm install @lokidb/loki\n```\n\n## Documentation\n\nCheck out our interactive [documentation](https://LokiJS-Forge.github.io/LokiDB/).\n\n## Plugins\n\n### Storage and Adapter\n\n|Name|Description|\n|:---|:----------|\n|[@lokidb/fs-storage][fs-storage-npm-url]                             |  A persistence adapter which persists to node fs module storage. |\n|[@lokidb/local-storage][local-storage-npm-url]                       |  A persistence adapter which persists to web browser's local storage. |\n|[@lokidb/indexed-storage][indexed-storage-npm-url]                   |  A persistence adapter which persists to web browser's indexed db storage. |\n|[@lokidb/memory-storage][memory-storage-npm-url]                     |  A persistence adapter which persists to memory. |\n|[@lokidb/partitioning-adapter][partitioning-adapter-npm-url]         |  An adapter for adapters. Converts a non reference mode adapter into a reference mode adapter which can perform destructuring and partitioning.|\n\n### Full-Text Search\n\n|Name|Description|\n|:---|:----------|\n|[@lokidb/full-text-search][full-text-search-npm-url]                         |  A full-text search engine. |\n|[@lokidb/full-text-search-language][full-text-search-language-npm-url]       |  A language analyzer utility package. |\n|[@lokidb/full-text-search-language-de][full-text-search-language-de-npm-url] |  ![flag][full-text-search-language-de-flag] A german language analyzer. |\n|[@lokidb/full-text-search-language-en][full-text-search-language-en-npm-url] |  ![flag][full-text-search-language-en-flag] An english language analyzer. |\n\n[build]: https://travis-ci.org/LokiJS-Forge/LokiDB.svg?branch=master\n[build-url]: https://travis-ci.org/LokiJS-Forge/LokiDB\n[coverage]: https://codecov.io/gh/LokiJS-Forge/LokiDB/branch/master/graph/badge.svg\n[coverage-url]: https://codecov.io/gh/LokiJS-Forge/LokiDB/branch/master\n\n[lokijs-url]: https://github.com/techfort/LokiJS\n\n[npm]: https://img.shields.io/npm/v/@lokidb/loki.svg\n[npm-url]: https://www.npmjs.com/package/@lokidb/loki\n\n[fs-storage]: https://github.com/LokiJS-Forge/LokiDB\n[fs-storage-npm-url]: https://www.npmjs.com/package/@lokidb/fs-storage\n\n[local-storage]: https://github.com/LokiJS-Forge/LokiDB\n[local-storage-npm-url]: https://www.npmjs.com/package/@lokidb/local-storage\n\n[indexed-storage]: https://github.com/LokiJS-Forge/LokiDB\n[indexed-storage-npm-url]: https://www.npmjs.com/package/@lokidb/indexed-storage\n\n[memory-storage]: https://github.com/LokiJS-Forge/LokiDB\n[memory-storage-npm-url]: https://www.npmjs.com/package/@lokidb/memory-storage\n\n[partitioning-adapter]: https://github.com/LokiJS-Forge/LokiDB\n[partitioning-adapter-npm-url]: https://www.npmjs.com/package/@lokidb/partitioning-adapter\n\n[full-text-search]: https://github.com/LokiJS-Forge/LokiDB\n[full-text-search-npm-url]: https://www.npmjs.com/package/@lokidb/full-text-search\n[full-text-search-language]: https://github.com/LokiJS-Forge/LokiDB\n[full-text-search-language-npm-url]: https://www.npmjs.com/package/@lokidb/full-text-search-language\n[full-text-search-language-de]: https://github.com/LokiJS-Forge/LokiDB\n[full-text-search-language-de-flag]: https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/de.png\n[full-text-search-language-de-npm-url]: https://www.npmjs.com/package/@lokidb/full-text-search-language-de\n[full-text-search-language-en]: https://github.com/LokiJS-Forge/LokiDB\n[full-text-search-language-en-npm-url]: https://www.npmjs.com/package/@lokidb/full-text-search-language-en\n[full-text-search-language-en-flag]: https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/us.png\n"
  },
  {
    "path": "benchmark/benchmark.js",
    "content": "/**\n * Core, \"single object lookup\" benchmarks\n */\n\nlet Loki = require('../build/packages/loki/lokidb.loki.js').default,\n  crypto = require(\"crypto\");\n\n/**\n * Generates a random string using node crypto library which is less memory 'leaky'\n */\nfunction genRandomVal() {\n  return crypto.randomBytes(50).toString('hex');\n}\n\n/**\n * Helper method for instantiating a loki database\n * @param {*} mode \n */\nfunction createDatabase(mode) {\n  let tdb = new Loki(\"temp.db\");\n  let coll;\n\n  switch (mode) {\n    case \"avl\":\n      coll = tdb.addCollection('perfcoll', {\n        rangedIndexes: {\n          \"customId\": { indexTypeName: \"avl\", comparatorName: \"js\" }\n        }\n      });\n      break;\n    case \"unique\":\n      coll = tdb.addCollection('perfcoll', {\n        unique: ['customId']\n      });\n      break;\n    case \"none\":\n    default:\n      coll = tdb.addCollection('perfcoll');\n      break;\n  }\n\n  return tdb;\n}\n\n/**\n * Helper method for populating a collection\n * @param {*} db \n * @param {*} count \n */\nfunction populateDatabase(db, count) {\n  let coll = db.getCollection(\"perfcoll\");\n\n  // populate collection\n  let idxbuf = [];\n  let customIdx, v1;\n  for (let idx = 0; idx < count; idx++) {\n    customIdx = count - idx;\n\n    idxbuf.push(customIdx);\n    v1 = genRandomVal();\n\n    coll.insert({\n      customId: customIdx,\n      val: v1,\n      val2: \"more data 1234567890\"\n    });\n  }\n\n  return idxbuf;\n}\n\n/**\n * Benchmarks collection.by() performance with unique index\n * @param {*} count \n * @param {*} multiple \n */\nfunction benchUniquePerf(count, multiple) {\n  let udb = createDatabase(\"unique\");\n  let uniquecoll = udb.getCollection('perfcoll');\n\n  let v1, idxbuf = [];\n\n  for (let idx = 0; idx < count; idx++) {\n    v1 = genRandomVal();\n\n    uniquecoll.insert({\n      customId: (count - idx),\n      val: v1,\n      val2: \"more data 1234567890\"\n    });\n\n    idxbuf.push(count - idx);\n  }\n\n  let start, end;\n  let totalTimes = [];\n  let totalMS = 0.0;\n\n  let customIdx, result;\n\n  for (let m = 0; m < multiple; m++) {\n    for (let idx = 0; idx < count; idx++) {\n      customIdx = idxbuf[idx];\n\n      start = process.hrtime();\n      result = uniquecoll.by('customId', customIdx);\n      end = process.hrtime(start);\n      totalTimes.push(end);\n\n      if (result.customId !== customIdx) {\n        console.log(\"(perfUnique) object retrieved does match custom id\");\n      }\n    }\n  }\n\n  for (let idx = 0; idx < totalTimes.length; idx++) {\n    totalMS += totalTimes[idx][0] * 1e3 + totalTimes[idx][1] / 1e6;\n  }\n\n  totalMS = totalMS.toFixed(2);\n  let rate = multiple * count * 1000 / totalMS;\n  rate = rate.toFixed(2);\n  console.log(\"coll.by() : \" + totalMS + \"ms (\" + rate + \" ops/s)  \" + multiple*count + \" iterations, \" + count + \" docs x \" + multiple);\n};\n\n/**\n * Benchmarks collection.get() performance\n * @param {*} count number of documents to insert into collection\n * @param {*} multiple number of times to repeat get() for each document\n */\nfunction testperfGet(count, multiple) {\n  let gdb = createDatabase(\"none\");\n  let coll = gdb.getCollection('perfcoll');\n\n  let start, end;\n  let totalTimes = [];\n  let totalMS = 0.0;\n\n  let customIdx, v1, obj = {}, idxbuf = [];\n\n  for (let idx = 0; idx < count; idx++) {\n    v1 = genRandomVal();\n\n    obj = coll.insert({\n      customId: (count - idx),\n      val: v1,\n      val2: \"more data 1234567890\"\n    });\n\n    idxbuf.push(obj.$loki);\n  }\n\n  let result;\n\n  for (let m = 0; m < multiple; m++) {\n    for (let idx = 0; idx < count; idx++) {\n      customIdx = idxbuf[idx];\n\n      start = process.hrtime();\n      result = coll.get(customIdx);\n      end = process.hrtime(start);\n      totalTimes.push(end);\n\n      if (result.$loki !== customIdx) {\n        console.log(\"(perfGet) object retrieved does match get id\");\n      }\n    }\n  }\n\n  for (let idx = 0; idx < totalTimes.length; idx++) {\n    totalMS += totalTimes[idx][0] * 1e3 + totalTimes[idx][1] / 1e6;\n  }\n\n  totalMS = totalMS.toFixed(2);\n  let rate = multiple * count * 1000 / totalMS;\n  rate = rate.toFixed(2);\n  console.log(\"coll.get() : \" + totalMS + \"ms (\" + rate + \" ops/s)  \" + multiple*count + \" iterations, \" + count + \" docs x \" + multiple);\n}\n\n/**\n * Benchmark collection find() performance\n * @param {*} mode Index Mode (\"none\", \"unique\", \"avl\")\n * @param {*} count Document count to populate collection with\n * @param {*} multiple Used to repeat finding each document this number of times\n */\nfunction testperfFind(mode, count, multiple) {\n  multiple = multiple || 1;\n\n  let fdb = createDatabase(mode);\n  let idxbuf = populateDatabase(fdb, count);\n  let coll = fdb.getCollection(\"perfcoll\");\n\n  let start, end;\n  let totalTimes = [];\n  let totalMS = 0;\n\n  let results;\n\n  for (let m = 0; m < multiple; m++) {\n    for (let idx = 0; idx < count; idx++) {\n      customIdx = idxbuf[idx];\n  \n      start = process.hrtime();\n      results = coll.find({\n        'customId': customIdx\n      });\n      end = process.hrtime(start);\n      totalTimes.push(end);\n  \n      if (results.length !== 1) {\n        console.log(\"(perfFind) received \" + results.length + \"instead of 1 matches!\");\n      }\n    }\n  }\n\n  for (let idx = 0; idx < totalTimes.length; idx++) {\n    totalMS += totalTimes[idx][0] * 1e3 + totalTimes[idx][1] / 1e6;\n  }\n\n  totalMS = totalMS.toFixed(2);\n  let rate = multiple * count * 1000 / totalMS;\n  rate = rate.toFixed(2);\n  console.log(\"coll.find() : \" + totalMS + \"ms (\" + rate + \" ops/s) \" + multiple * count + \" iterations, \" + count + \" docs x \" + multiple);\n}\n\n/**\n * Resultset benchmark\n * @param {*} mode \n * @param {*} count \n */\nfunction testperfRS(mode, count, multiple) {\n  multiple = multiple || 1;\n\n  let rsdb = createDatabase(mode);\n  let idxbuf = populateDatabase(rsdb, count);\n  let coll = rsdb.getCollection(\"perfcoll\");\n\n  let start, end;\n  let totalTimes = [];\n  let totalMS = 0;\n\n  let customIdx, results;\n\n  for (let m = 0; m < multiple; m++) {\n    for (let idx = 0; idx < count; idx++) {\n      customIdx = idxbuf[idx];\n  \n      start = process.hrtime();\n      results = coll.chain().find({\n        'customId': customIdx\n      }).data();\n      end = process.hrtime(start)\n      totalTimes.push(end);\n  \n      if (results.length !== 1) {\n        console.log(\"(perfRS) received \" + results.length + \"instead of 1 matches!\");\n      }\n    }\n  }\n\n  for (let idx = 0; idx < totalTimes.length; idx++) {\n    totalMS += totalTimes[idx][0] * 1e3 + totalTimes[idx][1] / 1e6;\n  }\n\n  totalMS = totalMS.toFixed(2);\n  let rate = multiple * count * 1000 / totalMS;\n  rate = rate.toFixed(2);\n  console.log(\"resultset chained find() :  \" + totalMS + \"ms (\" + rate + \" ops/s) \" + multiple * count + \" iterations, \" + count + \" docs x \" + multiple);\n}\n\n/**\n * Benchmark dynamic view performance\n * @param {*} mode \n * @param {*} count \n * @param {*} multiple \n */\nfunction testperfDV(mode, count, multiple) {\n  multiple = multiple || 1;\n  \n  let dvdb = createDatabase(mode);\n  let idxbuf = populateDatabase(dvdb, count);\n  let coll = dvdb.getCollection(\"perfcoll\");\n\n  let start, end;\n  let start2, end2, totalTime2 = 0.0;\n  let totalTimes = [];\n  let totalTimes2 = [];\n  let totalMS = 0;\n  let totalMS2 = 0;\n\n  let customIdx, dv, results;\n\n  for (let m = 0; m < multiple; m++) {\n    for (let idx = 0; idx < count; idx++) {\n      customIdx = idxbuf[idx];\n  \n      start = process.hrtime();\n      dv = coll.addDynamicView(\"perfview\");\n      dv.applyFind({\n        'customId': customIdx\n      });\n      results = dv.data();\n      end = process.hrtime(start);\n      totalTimes.push(end);\n  \n      // test speed of repeated query on an already set up dynamicview\n      start2 = process.hrtime();\n      results = dv.data();\n      end2 = process.hrtime(start2);\n      totalTimes2.push(end2);\n  \n      coll.removeDynamicView(\"perfview\");\n    }\n  }\n\n  for (let idx = 0; idx < totalTimes.length; idx++) {\n    totalMS += totalTimes[idx][0] * 1e3 + totalTimes[idx][1] / 1e6;\n    totalMS2 += totalTimes2[idx][0] * 1e3 + totalTimes2[idx][1] / 1e6;\n  }\n\n  totalMS = totalMS.toFixed(2);\n  totalMS2 = totalMS2.toFixed(2);\n  let rate = multiple * count * 1000 / totalMS;\n  let rate2 = multiple * count * 1000 / totalMS2;\n  rate = rate.toFixed(2);\n  rate2 = rate2.toFixed(2);\n\n  console.log(\"loki dynamic view first find : \" + totalMS + \"ms (\" + rate + \" ops/s) \" + multiple * count + \" iterations, \" + count + \" docs x \" + multiple);\n  console.log(\"loki dynamic view subsequent finds : \" + totalMS2 + \"ms (\" + rate2 + \" ops/s) \" + multiple * count + \" iterations, \" + count + \" docs x \" + multiple);\n}\n\n/**\n * Attempt to free up global variables and invoke node garbage collector (if enabled)\n */\nfunction cleanup() {\n  if (global.gc) {\n    global.gc()\n  }\n}\n\nlet corePerf = [\n  () => testperfGet(200000, 20),\n  () => benchUniquePerf(200000, 20)\n];\n\nlet nonIndexedSteps = [\n  () => testperfFind(\"none\", 5000, 8),\n  () => testperfRS(\"none\", 5000, 8),\n  () => testperfDV(\"none\", 5000, 8)\n];\n\nlet nonIndexedStepsHigh = [\n  () => testperfFind(\"none\", 10000, 1),\n  () => testperfRS(\"none\", 10000, 1),\n  () => testperfDV(\"none\", 10000, 1)\n];\n\nlet avlIndexSteps = [\n  () => testperfFind(\"avl\", 20000, 20),\n  () => testperfRS(\"avl\", 20000, 20),\n  () => testperfDV(\"avl\", 20000, 20)\n];\n\nlet avlIndexStepsHigh = [\n  () => testperfFind(\"avl\", 200000, 2),\n  () => testperfRS(\"avl\", 200000, 2),\n  () => testperfDV(\"avl\", 200000, 2)\n];\n\nlet perfGroups = [\n  { name: \"Benchmarking Core Id lookup performance\", steps: corePerf },\n  { name: \"Benchmarking NON-INDEX query performance (Lower doc count)\", steps: nonIndexedSteps },\n  { name: \"Benchmarking NON-INDEX query performance (Higher doc count)\", steps: nonIndexedStepsHigh },\n  { name: \"Benchmarking AVL TREE INDEX query performance (Lower doc count)\", steps: avlIndexSteps },\n  { name: \"Benchmarking AVL TREE INDEX query performance (Higher doc count)\", steps: avlIndexStepsHigh }\n];\n\n/**\n * Executes steps within a benchmark group, pausing in between steps.\n * Once the benchmark group steps are depleted, we initiate next group.\n * @param {*} steps \n */\nfunction execSteps(steps) {\n  // if we are finished with this group's steps...\n  if (steps.length === 0) {\n    // wait a few seconds in between benchmark groups\n    setTimeout(execGroups, 4000);\n    return;\n  }\n\n  let s = steps.shift();\n\n  s();\n\n  setTimeout(() => { execSteps(steps); }, 1000);\n}\n\n/**\n * Kicks off a group of benchmarks, cleaning up in between\n */\nfunction execGroups() {\n  let g = perfGroups.shift();\n  if (!g) return;\n\n  cleanup();\n\n  console.log(\"\");\n  console.log(\"## \" + g.name + \" ##\");\n  console.log(\"\");\n  execSteps(g.steps);\n}\n\nconsole.log(\"\");\nconsole.log(\"Note: run 'npm run build' before benchmarking after getting latest or modifying code\");\nconsole.log(\"\");\n\nif (!global.gc) {\n  console.warn(\"##\");\n  console.warn(\"## IMPORTANT! : For accuracy of results, launch node with --expose-gc flag\");\n  console.warn(\"##\");\n}\n\nexecGroups();"
  },
  {
    "path": "benchmark/benchmark_indexes.js",
    "content": "/**\n * This module is to be used to benchmark loki binary index lifecycle\n *\n * Attempt to simulate and benchmark effects of various rebuild strategies on\n * insert, find, remove, and update to be used to instrument refactorings/optimizations.\n *\n * Since a given index type may prioritize lookups/finds over maintenance of insert/update/remove ops,\n * the 'Nightmare' tests attempt to pair a find along with insert/update/removes. The resulting\n * times tend to average out this bias to allow examining overall performance for scale.\n * \n * Currently, this benchmark will compare the following index options :\n * - Unindexed\n * - Adaptive Binary Indices (Lazy benchmarks can be uncommented if you wish those as well)\n * - AVL Indexes based on self-balancing AVL binary search trees \n */\n\n\nlet Loki = require('../build/packages/loki/lokidb.loki.js').default,\n  crypto = require(\"crypto\"); // for less 'leaky' random string generation\n\n/**\n * Generate random string using node cryto lib for less memory 'leaky' behavior than js string construction\n */\nfunction genRandomVal() {\n  return crypto.randomBytes(50).toString('hex');\n}\n\n/**\n * Helper method to shuffle array\n * @param {*} array \n */\nfunction shuffle(array) {\n  let 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 * Helper method to convert number of bytes into more readable representation.\n * @param {*} bytes \n * @param {*} decimals \n */\nfunction formatBytes(bytes, decimals) {\n  if (bytes == 0) return '0 Byte';\n  let k = 1000; // or 1024 for binary\n  let dm = decimals + 1 || 3;\n  let sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];\n  let i = Math.floor(Math.log(bytes) / Math.log(k));\n  return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];\n}\n\n/**\n * Logs memory usage info to console\n * @param {*} msg \n */\nfunction logMemoryUsage(msg) {\n  let pmu = process.memoryUsage();\n  console.log(msg + \" => rss : \" + formatBytes(pmu.rss) + \" heapTotal : \" + formatBytes(pmu.heapTotal) + \" heapUsed : \" + formatBytes(pmu.heapUsed));\n}\n\n/**\n * Helper method for instantiating a loki database\n * @param {*} mode indexing mode (\"none\", \"avl\")\n */\nfunction createDatabase(mode) {\n  let tdb = new Loki(\"temp.db\");\n  let coll;\n\n  switch (mode) {\n    case \"avl\":\n      coll = tdb.addCollection('perfcoll', {\n        rangedIndexes: {\n          \"customId\": { indexTypeName: \"avl\", comparatorName: \"js\" }\n        }\n      });\n      break;\n    case \"none\":\n    default:\n      coll = tdb.addCollection('perfcoll');\n      break;\n  }\n\n  return tdb;\n}\n\n/**\n * Helper method for populating a collection\n * @param {*} db loki database instance containing collection to populate\n * @param {*} count number of documents to insert\n */\nfunction populateDatabase(db, count) {\n  let coll = db.getCollection(\"perfcoll\");\n\n  // populate collection\n  let idxbuf = [];\n  let customIdx, v1;\n  for (let idx = 0; idx < count; idx++) {\n    customIdx = count - idx;\n\n    idxbuf.push(customIdx);\n    v1 = genRandomVal();\n\n    coll.insert({\n      customId: customIdx,\n      val: v1,\n      val2: \"more data 1234567890\"\n    });\n  }\n\n  return idxbuf;\n}\n\n/**\n * Profiles memory usage for unindexed and avl indexed collections\n * @param {*} mode indexing mode (\"none\", \"avl\") \n * @param {*} count \n */\nfunction profileDatabaseMemory(mode, count) {\n  let mdb = createDatabase(mode);\n  populateDatabase(mdb, count);\n  let coll = mdb.getCollection(\"perfcoll\");\n\n  let id, v1;\n\n  for (let idx = 0; idx < 100000; idx++) {\n    id = count - idx;\n    v1 = genRandomVal();\n\n    coll.insert({\n      customId: id,\n      val1: v1,\n      val2: \"more data 1234567890\"\n    });\n  }\n\n  logMemoryUsage(mode);\n}\n\n/**\n * Benchmarks insertion rates for unindexed and avl indexed collections\n * @param {*} mode indexing mode (\"none\", \"avl\") \n * @param {*} count \n */\nfunction profileInsertion(mode, count) {\n  let mdb = createDatabase(mode);\n  let coll = mdb.getCollection(\"perfcoll\");\n\n  let start, end;\n  let totalTimes = [];\n  let totalMS = 0;\n\n  // populate collection manually instead of helper since we won't retain idxbuf\n  let customIdx, v1;\n  for (let idx = 0; idx < count; idx++) {\n    customIdx = count - idx;\n\n    v1 = genRandomVal();\n\n    start = process.hrtime();\n\n    coll.insert({\n      customId: customIdx,\n      val: v1,\n      val2: \"more data 1234567890\"\n    });\n\n    end = process.hrtime(start);\n    totalTimes.push(end);\n  }\n\n  for (let idx = 0; idx < totalTimes.length; idx++) {\n    totalMS += totalTimes[idx][0] * 1e3 + totalTimes[idx][1] / 1e6;\n  }\n\n  totalMS = totalMS.toFixed(2);\n  let rate = count * 1000 / totalMS;\n  rate = rate.toFixed(2);\n  console.log(\"insertion rate (\" + mode + \") : \" + totalMS + \"ms (\" + rate + \" ops/s) \" + count + \" documents\");\n}\n\n/**\n * Benchmarks find performance for given document count (not multiplied to show raw ms perf)\n * @param {*} mode indexing mode (\"none\", \"avl\")\n * @param {*} count \n */\nfunction perfFind(mode, count) {\n  let fdb = createDatabase(mode);\n  let idxbuf = populateDatabase(fdb, count);\n  let coll = fdb.getCollection(\"perfcoll\");\n\n  let start, end;\n  let totalTimes = [];\n  let totalMS = 0;\n\n  let customIdx, results;\n\n  for (let idx = 0; idx < count; idx++) {\n    customIdx = idxbuf[idx];\n\n    start = process.hrtime();\n    results = coll.find({\n      'customId': customIdx\n    });\n    end = process.hrtime(start);\n    totalTimes.push(end);\n  }\n\n  for (let idx = 0; idx < totalTimes.length; idx++) {\n    totalMS += totalTimes[idx][0] * 1e3 + totalTimes[idx][1] / 1e6;\n  }\n\n  totalMS = totalMS.toFixed(2);\n  let rate = count * 1000 / totalMS;\n  rate = rate.toFixed(2);\n  console.log(\"random coll.find() : \" + totalMS + \"ms (\" + rate + \" ops/s) \" + count + \" iterations\");\n}\n\n/**\n * Benchmarks interlacing insert + find (on indexed column) to measure index thrashing\n * @param {*} mode indexing mode (\"none\", \"avl\")\n * @param {*} count \n */\nfunction perfFindInterlacedInserts(mode, count) {\n  let fdb = createDatabase(mode);\n  let idxbuf = [];\n  let coll = fdb.getCollection(\"perfcoll\");\n\n  let start, end;\n  let totalTimes = [];\n  let totalMS = 0;\n\n  let customIdx, results;\n\n  for (let idx = 0; idx < count; idx++) {\n    customIdx = count - idx;\n\n    start = process.hrtime();\n\n    // insert record with id outside range of pre-populated records\n    coll.insert({\n      customId: customIdx,\n      val: 999,\n      val2: 999,\n      val3: \"more data 1234567890\"\n    });\n\n    // do quick find of object just inserted\n    results = coll.find({\n      'customId': customIdx\n    });\n\n    end = process.hrtime(start);\n    totalTimes.push(end);\n\n    if (results.length !== 1 || results[0].customId !== customIdx) {\n      console.log(\"(interlaced inserts) unexpected results\")\n    }\n  }\n\n  if (coll.find().length !== count) {\n    console.log(\"(interlaced inserts) unexpected total inserted document count\");\n  }\n\n  for (let idx = 0; idx < totalTimes.length; idx++) {\n    totalMS += totalTimes[idx][0] * 1e3 + totalTimes[idx][1] / 1e6;\n  }\n\n  totalMS = totalMS.toFixed(2);\n  let rate = count * 1000 / totalMS;\n  rate = rate.toFixed(2);\n  console.log(\"interlaced inserts + coll.find() : \" + totalMS + \"ms (\" + rate + \" ops/s) \" + count + \" iterations\");\n}\n\n/**\n * Benchmarks interlacing find + remove (on indexed column) to measure index thrashing\n * @param {*} mode indexing mode (\"none\", \"avl\")\n * @param {*} count\n */\nfunction perfFindInterlacedRemoves(mode, count, multiple) {\n  let fdb = createDatabase(mode);\n  let idxbuf = populateDatabase(fdb, count);\n  let coll = fdb.getCollection(\"perfcoll\");\n\n  let start, end;\n  let totalTimes = [];\n  let totalMS = 0;\n\n  let removeId, result;\n\n  for (let idx = 0; idx < count; idx++) {\n    removeId = idxbuf.pop();\n\n    start = process.hrtime();\n    result = coll.findOne({\n      'customId': removeId\n    });\n    coll.remove(result);\n\n    end = process.hrtime(start);\n    totalTimes.push(end);\n  }\n\n  if (coll.find().length !== 0) {\n    console.log(\"(interlaces removes) unexpected final doc count\");\n  }\n\n  for (let idx = 0; idx < totalTimes.length; idx++) {\n    totalMS += totalTimes[idx][0] * 1e3 + totalTimes[idx][1] / 1e6;\n  }\n\n  totalMS = totalMS.toFixed(2);\n  let rate = count * 1000 / totalMS;\n  rate = rate.toFixed(2);\n  console.log(\"interlaced removes + coll.find() : \" + totalMS + \"ms (\" + rate + \" ops/s) \" + count + \" iterations\");\n}\n\n/**\n * Benchmarks interlacing find + update (on indexed column) to measure index thrashing\n * @param {*} mode indexing mode (\"none\", \"avl\")\n * @param {*} count number of interlaced finds+updates to perform\n */\nfunction perfFindInterlacesUpdates(mode, count) {\n  let fdb = createDatabase(mode);\n  let idxbuf = populateDatabase(fdb, count);\n  let coll = fdb.getCollection(\"perfcoll\");\n\n  let start, end;\n  let totalTimes = [];\n  let totalMS = 0;\n\n  let customIdx, newIdx, result;\n\n  for (let idx = 0; idx < count; idx++) {\n    customIdx = idxbuf.pop();\n    newIdx = count + idx;\n\n    start = process.hrtime();\n\n    // lookup next doc\n    result = coll.findOne({\n      'customId': customIdx\n    });\n\n    // update doc, modifying the field (potentially) being indexed\n    result.customId = newIdx;\n    coll.update(result);\n\n    end = process.hrtime(start);\n    totalTimes.push(end);\n  }\n\n  if (coll.find().length !== count) {\n    console.log(\"(interlaced updates) unexpected final doc count\");\n  }\n\n  for (let idx = 0; idx < totalTimes.length; idx++) {\n    totalMS += totalTimes[idx][0] * 1e3 + totalTimes[idx][1] / 1e6;\n  }\n\n  totalMS = totalMS.toFixed(2);\n  let rate = count * 1000 / totalMS;\n  rate = rate.toFixed(2);\n  console.log(\"interlaced updates + coll.find() : \" + totalMS + \"ms (\" + rate + \" ops/s) \" + count + \" iterations\");\n}\n\n/**\n * Attempt to free up global variables and invoke node garbage collector (if enabled)\n */\nfunction cleanup() {\n  if (global.gc) {\n    global.gc();\n  }\n}\n\nlet memoryProfileSteps = [\n  cleanup,\n  () => logMemoryUsage(\"baseline\"),\n  () => profileDatabaseMemory(\"unindexed\", 10000),\n  cleanup,\n  () => logMemoryUsage(\"baseline\"),\n  () => profileDatabaseMemory(\"avl\", 10000)\n];\n\nlet insertionProfileSteps = [\n  // Unindexed Inserts\n  cleanup,\n  () => console.log(\"no index\"),\n  () => profileInsertion(\"none\", 100000),\n  // AVL indexed inserts\n  cleanup,\n  () => console.log(\"avl tree index\"),\n  () => profileInsertion(\"avl\", 100000)\n];\n\nlet nightmareUnindexedLowSteps = [\n  () => {\n    console.log(\"\");\n    console.log(\"------------ Beginning Nightmare Benchmarks ------------\");\n    console.log(\"Nightmare tests combine a find() with either an insert(), update(), or remove()\");\n    console.log(\"to remove any bias and show weaknesses that each indexing strategy may be leveraging, \");\n    console.log(\"such as placing all emphasis on find() performance to detriment of index maintenance costs.\");\n    console.log(\"\");\n  },\n  () => {\n    console.log(\"Perf: Unindexed Nightmare (Lower Scale @ 5,000 docs/iterations) ------------------------\");\n    createDatabase(\"none\");\n  },\n  cleanup,\n  () => perfFind(\"none\", 5000),\n  cleanup,\n  () => perfFindInterlacedInserts(\"none\", 5000),\n  cleanup,\n  () => perfFindInterlacedRemoves(\"none\", 5000),\n  cleanup,\n  () => perfFindInterlacesUpdates(\"none\", 5000)\n];\n\nlet nightmareUnindexedHighSteps = [\n  () => {\n    console.log(\"Perf: Unindexed Nightmare (Higher Scale @ 10,000 docs/iterations) ------------------------\");\n    createDatabase(\"none\");\n  },\n  cleanup,\n  () => perfFind(\"none\", 10000),\n  cleanup,\n  () => perfFindInterlacedInserts(\"none\", 10000),\n  cleanup,\n  () => perfFindInterlacedRemoves(\"none\", 10000),\n  cleanup,\n  () => perfFindInterlacesUpdates(\"none\", 10000),\n];\n\nlet nightmareAvlLowSteps = [\n  () => console.log(\"Perf: AVL Indexed Nightmare (Lower Scale @ 40,000 docs/iterations) ---\"),\n  cleanup,\n  () => perfFind(\"avl\", 40000),\n  cleanup,\n  () => perfFindInterlacedInserts(\"avl\", 40000),\n  cleanup,\n  () => perfFindInterlacedRemoves(\"avl\", 40000),\n  cleanup,\n  () => perfFindInterlacesUpdates(\"avl\", 40000),\n];\n\nlet nightmareAvlHighSteps = [\n  () => console.log(\"Perf: AVL Indexed Nightmare (Higher Scale @ 100,000 docs/iterations) ---\"),\n  cleanup,\n  () => perfFind(\"avl\", 100000),\n  cleanup,\n  () => perfFindInterlacedInserts(\"avl\", 100000),\n  cleanup,\n  () => perfFindInterlacedRemoves(\"avl\", 100000),\n  cleanup,\n  () => perfFindInterlacesUpdates(\"avl\", 100000)\n];\n\nlet perfGroups = [\n  //{ name: \"Memory Profiling of database with various indexing\", steps: memoryProfileSteps },\n  //{ name: \"Document Insertion rates with various indexes\", steps: insertionProfileSteps },\n  { name: \"Nightmare Unindexed (Low Range)\", steps: nightmareUnindexedLowSteps },\n  { name: \"Nightmare Unindexed (High Range)\", steps: nightmareUnindexedHighSteps },\n  { name: \"Nightmare AVL Index (Low Range)\", steps: nightmareAvlLowSteps },\n  { name: \"Nightmare AVL Index (High Range)\", steps: nightmareAvlHighSteps }\n];\n\nfunction execSteps(steps) {\n  if (steps.length === 0) {\n    setTimeout(execGroups, 4000);\n    return;\n  }\n\n  let s = steps.shift();\n\n  s();\n\n  setTimeout(() => { execSteps(steps); }, 1000);\n}\n\nfunction execGroups() {\n  let g = perfGroups.shift();\n  if (!g) return;\n\n  cleanup();\n\n  console.log(\"\");\n  console.log(\"## \" + g.name + \" ##\");\n  console.log(\"\");\n  execSteps(g.steps);\n}\n\nif (!global.gc) {\n  console.warn(\"##\");\n  console.warn(\"## IMPORTANT! : For accuracy of results, launch node with --expose-gc flag\");\n  console.warn(\"##\");\n}\n\nconsole.log(\"\");\nconsole.log(\"Note: run 'npm run build' before benchmarking after getting latest or modifying code\");\nconsole.log(\"\");\n\nexecGroups();"
  },
  {
    "path": "config/jasmine.json",
    "content": "{\n  \"spec_dir\": \"packages/*/spec\",\n  \"spec_files\": [\n    \"generic/**/*.spec.[jt]s\",\n    \"node/**/*.spec.[jt]s\"\n  ],\n  \"helpers\": [\n    \"../../../node_modules/ts-node/register/index.js\",\n    \"../../../node_modules/jasmine-expect/index.js\",\n    \"../../common/spec/helper/**/*helper.[jt]s\",\n    \"helper/**/*.[jt]s\"\n  ],\n  \"stopSpecOnExpectationFailure\": false,\n  \"random\": false\n}\n"
  },
  {
    "path": "config/karma.config.js",
    "content": "/* global process, require, module, require */\nconst path = require(\"path\");\n\nmodule.exports = function (config) {\n  const configuration = {\n    frameworks: [\"jasmine\", \"jasmine-matchers\"],\n    browsers: [\"ChromeHeadless\"],\n    basePath: \"../\",\n    files: [\n      {pattern: \"packages/*/spec/generic/**/*.spec.ts\", watched: false},\n      {pattern: \"packages/*/spec/web/**/*.spec.ts\", watched: false}\n    ],\n    preprocessors: {\n      \"packages/*/spec/generic/**/*.spec.ts\": [\"webpack\"],\n      \"packages/*/spec/web/**/*.spec.ts\": [\"webpack\"]\n    },\n    // coverage reporter generates the coverage\n    reporters: [\"progress\", \"coverage-istanbul\"],\n    coverageIstanbulReporter: {\n      dir: \"coverage/karma/\",\n      reports: [\"text-summary\", \"json\"],\n      fixWebpackSourcePaths: true\n    },\n    mime: {\n      \"text/x-typescript\": [\"ts\"]\n    },\n    webpack: {\n      mode: \"development\",\n      stats: 'errors-only',\n      resolve: {\n        extensions: [\".ts\"],\n      },\n      devtool: \"source-map\",\n      module: {\n        rules: [\n          {\n            enforce: \"pre\",\n            test: /\\.ts$/,\n            loader: \"tslint-loader\",\n            exclude: /node_modules/,\n            options: {\n              failOnHint: false,\n              configFile: path.join(__dirname, \"tslint.json\"),\n            }\n          },\n          {\n            test: /\\.ts$/,\n            loader: \"ts-loader\",\n            options: {\n              configFile: path.join(__dirname, \"tsconfig.webpack.json\")\n            }\n          },\n          {\n            enforce: \"post\",\n            exclude: [\n              /node_modules/,\n              /\\.spec\\.ts$/,\n              /.*\\/spec\\/.+\\.ts/,\n              /\\.helper\\.ts$/,\n              /.*\\/helper\\/.+\\.ts/\n            ],\n            loader: \"istanbul-instrumenter-loader?esModules=true\",\n            test: /\\.ts$/\n          }\n        ]\n      }\n    },\n    webpackMiddleware: {\n      logLevel: \"warn\"\n    },\n    plugins: [\n      \"karma-chrome-launcher\",\n      \"karma-coverage-istanbul-reporter\",\n      \"karma-jasmine\",\n      \"karma-jasmine-matchers\",\n      \"karma-webpack\",\n    ],\n  };\n\n  config.set(configuration);\n};\n"
  },
  {
    "path": "config/nycrc.json",
    "content": "{\n  \"reporter\": [\n    \"text-summary\",\n    \"html\"\n  ],\n  \"report-dir\": \"./coverage/\",\n  \"temp-directory\": \"./coverage/\"\n}\n"
  },
  {
    "path": "config/nycrc.node.json",
    "content": "{\n  \"extension\": [\n    \".ts\"\n  ],\n  \"reporter\": [\n    \"text-summary\",\n    \"json\"\n  ],\n  \"exclude\": [\n    \"**/*.helper.[jt]s\",\n    \"**/*.spec.[jt]s\",\n    \"**/spec/**/*.[jt]s\"\n  ],\n  \"report-dir\": \"./coverage/node/\"\n}\n"
  },
  {
    "path": "config/tsconfig.tslint.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"compilerOptions\": {\n    \"outDir\": \"../types/\",\n    \"sourceMap\": true,\n    \"declaration\": true,\n    \"moduleResolution\": \"classic\",\n    \"strictPropertyInitialization\": true,\n    \"alwaysStrict\": true,\n    \"noImplicitAny\": true,\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"target\": \"es6\",\n    \"lib\": [\n      \"es2017\"\n    ],\n    \"typeRoots\": [\n      \"node_modules/@types\"\n    ],\n    \"types\": [\n      \"jasmine\",\n      \"jasmine-expect\",\n      \"node\"\n    ]\n  },\n  \"include\": [\n    \"../packages/**/*.ts\"\n  ]\n}\n"
  },
  {
    "path": "config/tsconfig.webpack.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"compilerOptions\": {\n    \"outDir\": \"../types/\",\n    \"sourceMap\": true,\n    \"declaration\": true,\n    \"moduleResolution\": \"classic\",\n    \"strictPropertyInitialization\": true,\n    \"alwaysStrict\": true,\n    \"noImplicitAny\": true,\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"target\": \"es6\",\n    \"lib\": [\n      \"es2017\",\n      \"dom\"\n    ],\n    \"typeRoots\": [\n      \"node_modules/@types\"\n    ],\n    \"types\": [\n      \"jasmine\",\n      \"jasmine-expect\",\n      \"node\"\n    ]\n  },\n  \"include\": [\n    \"../packages/*/src/**/*.ts\"\n  ]\n}\n"
  },
  {
    "path": "config/tslint.json",
    "content": "{\n  \"rulesDirectory\": [\n    \"../node_modules/vrsource-tslint-rules/rules\",\n    \"../node_modules/tslint-eslint-rules/dist/rules\"\n  ],\n  \"extends\": [\n    \"tslint-eslint-rules\"\n  ],\n  \"rules\": {\n    \"no-console\": [true, \"log\"],\n    \"no-duplicate-imports\": true,\n    \"no-duplicate-variable\": true,\n    \"no-jasmine-focus\": true,\n    \"no-var-keyword\": true,\n    \"semicolon\": [true],\n    \"variable-name\": [true, \"ban-keywords\"],\n    \"no-inner-declarations\": [true, \"function\"],\n    \"quotemark\": [true, \"double\"],\n    \"eofline\": true,\n    \"ter-indent\": [true, 2, {\n      \"SwitchCase\": 1\n    }],\n    \"whitespace\": [true, \"check-branch\", \"check-decl\", \"check-operator\", \"check-module\", \"check-separator\",\n      \"check-rest-spread\", \"check-type\", \"check-type\", \"check-typecast\", \"check-type-operator\", \"check-preblock\"],\n    \"no-trailing-whitespace\": true\n  }\n}\n"
  },
  {
    "path": "config/webpack-config-creator.js",
    "content": "/* global __dirname, module, require */\nconst path = require(\"path\");\n\nmodule.exports = (options) => {\n  if (options.entry === undefined) {\n    throw Error(\"options.entry must be specified.\")\n  }\n  if (options.filename === undefined) {\n    throw Error(\"options.Filename must be specified.\")\n  }\n  if (options.library === undefined) {\n    throw Error(\"options.library must be specified.\")\n  }\n\n  return {\n    mode: \"production\",\n    entry: options.entry,\n    output: {\n      filename: options.filename,\n      library: options.library,\n      libraryTarget: \"umd2\",\n      umdNamedDefine: true,\n      globalObject: \"typeof self !== 'undefined' ? self : this\"\n    },\n    externals: options.externals,\n    resolve: {\n      extensions: [\".ts\"]\n    },\n    devtool: \"source-map\",\n    module: {\n      rules: [\n        {\n          enforce: \"pre\",\n          test: /\\.ts$/,\n          loader: \"tslint-loader\",\n          exclude: /node_modules/,\n          options: {\n            failOnHint: true,\n            configFile: path.join(\"config\", \"tslint.json\"),\n          }\n        },\n        {\n          test: /\\.ts$/,\n          loader: \"ts-loader\",\n          options: {\n            configFile: path.join(\"config\", \"tsconfig.webpack.json\")\n          }\n        }\n      ]\n    },\n    optimization: {\n      minimize: false\n    },\n  };\n};\n"
  },
  {
    "path": "dist/packages/fs-storage/lokidb.fs-storage.js",
    "content": "(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"fs\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"@lokidb/fs-storage\", [\"fs\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"@lokidb/fs-storage\"] = factory(require(\"fs\"));\n\telse\n\t\t{ root[\"@lokidb/fs-storage\"] = factory(root[\"fs\"]); root[\"LokiFsStorage\"] = root[\"@lokidb/fs-storage\"].default; }\n})(typeof self !== 'undefined' ? self : this, function(__WEBPACK_EXTERNAL_MODULE__0__) {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// define __esModule on exports\n/******/ \t__webpack_require__.r = function(exports) {\n/******/ \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n/******/ \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n/******/ \t\t}\n/******/ \t\tObject.defineProperty(exports, '__esModule', { value: true });\n/******/ \t};\n/******/\n/******/ \t// create a fake namespace object\n/******/ \t// mode & 1: value is a module id, require it\n/******/ \t// mode & 2: merge all properties of value into the ns\n/******/ \t// mode & 4: return value when already ns object\n/******/ \t// mode & 8|1: behave like require\n/******/ \t__webpack_require__.t = function(value, mode) {\n/******/ \t\tif(mode & 1) value = __webpack_require__(value);\n/******/ \t\tif(mode & 8) return value;\n/******/ \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n/******/ \t\tvar ns = Object.create(null);\n/******/ \t\t__webpack_require__.r(ns);\n/******/ \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n/******/ \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n/******/ \t\treturn ns;\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 3);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, exports) {\n\nmodule.exports = __WEBPACK_EXTERNAL_MODULE__0__;\n\n/***/ }),\n/* 1 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return PLUGINS; });\nfunction getGlobal() {\n    let glob;\n    (function (global) {\n        glob = global;\n    })(global !== undefined && global || this);\n    return glob;\n}\nfunction create() {\n    const global = getGlobal();\n    const sym = Symbol.for(\"LOKI\");\n    if (global[sym] === undefined) {\n        global[sym] = {};\n    }\n    return global[sym];\n}\n/**\n * @hidden\n */\nconst PLUGINS = create();\n\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(2)))\n\n/***/ }),\n/* 2 */\n/***/ (function(module, exports) {\n\nvar g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || Function(\"return this\")() || (1, eval)(\"this\");\n} catch (e) {\n\t// This works if the window reference is available\n\tif (typeof window === \"object\") g = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n\n\n/***/ }),\n/* 3 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"FSStorage\", function() { return FSStorage; });\n/* harmony import */ var _common_plugin__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);\n/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(0);\n/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__);\n\n\n/**\n * A loki persistence adapter which persists using node fs module.\n */\nclass FSStorage {\n    /**\n     * Registers the fs storage as plugin.\n     */\n    static register() {\n        _common_plugin__WEBPACK_IMPORTED_MODULE_0__[/* PLUGINS */ \"a\"][\"FSStorage\"] = FSStorage;\n    }\n    /**\n     * Deregisters the fs storage as plugin.\n     */\n    static deregister() {\n        delete _common_plugin__WEBPACK_IMPORTED_MODULE_0__[/* PLUGINS */ \"a\"][\"FSStorage\"];\n    }\n    /**\n     * Load data from file, will throw an error if the file does not exist\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname) {\n        return new Promise((resolve, reject) => {\n            fs__WEBPACK_IMPORTED_MODULE_1__[\"stat\"](dbname, (err, stats) => {\n                if (!err && stats.isFile()) {\n                    fs__WEBPACK_IMPORTED_MODULE_1__[\"readFile\"](dbname, {\n                        encoding: \"utf8\"\n                    }, function readFileCallback(err, data) {\n                        if (err) {\n                            reject(err);\n                        }\n                        else {\n                            resolve(data);\n                        }\n                    });\n                }\n                else {\n                    reject(null);\n                }\n            });\n        });\n    }\n    /**\n     * Save data to file, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname, dbstring) {\n        const tmpdbname = dbname + \"~\";\n        return new Promise((resolve, reject) => {\n            fs__WEBPACK_IMPORTED_MODULE_1__[\"writeFile\"](tmpdbname, dbstring, (err) => {\n                if (err) {\n                    reject(err);\n                }\n                else {\n                    fs__WEBPACK_IMPORTED_MODULE_1__[\"rename\"](tmpdbname, dbname, (err) => {\n                        if (err) {\n                            reject(err);\n                        }\n                        else {\n                            resolve();\n                        }\n                    });\n                }\n            });\n        });\n    }\n    /**\n     * Delete the database file, will throw an error if the\n     * file can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname) {\n        return new Promise((resolve, reject) => {\n            fs__WEBPACK_IMPORTED_MODULE_1__[\"unlink\"](dbname, function deleteDatabaseCallback(err) {\n                if (err) {\n                    reject(err);\n                }\n                else {\n                    resolve();\n                }\n            });\n        });\n    }\n}\n\n\n/***/ })\n/******/ ]);\n});\n//# sourceMappingURL=lokidb.fs-storage.js.map"
  },
  {
    "path": "dist/packages/fs-storage/types/common/plugin.d.ts",
    "content": "/**\n * @hidden\n */\nexport declare const PLUGINS: void;\n"
  },
  {
    "path": "dist/packages/fs-storage/types/common/types.d.ts",
    "content": "/**\n * @hidden\n */\nimport { Loki } from \"../loki/src/loki\";\nexport interface StorageAdapter {\n    loadDatabase(dbname: string): Promise<any>;\n    saveDatabase?(dbname: string, serialization: string): Promise<void>;\n    deleteDatabase?(dbname: string): Promise<void>;\n    mode?: string;\n    exportDatabase?(dbname: string, dbref: Loki): Promise<void>;\n}\nexport declare type Doc<T extends object = object> = T & {\n    $loki: number;\n    meta?: {\n        created: number;\n        revision: number;\n        version: number;\n        updated?: number;\n    };\n};\nexport interface Dict<T> {\n    [index: string]: T;\n    [index: number]: T;\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/fs-storage/src/fs_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists using node fs module.\n */\nexport declare class FSStorage implements StorageAdapter {\n    /**\n     * Registers the fs storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the fs storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * Load data from file, will throw an error if the file does not exist\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Save data to file, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Delete the database file, will throw an error if the\n     * file can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/fs-storage/src/index.d.ts",
    "content": "import { FSStorage } from \"./fs_storage\";\nexport { FSStorage };\nexport default FSStorage;\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search/src/analyzer/analyzer.d.ts",
    "content": "import { CharacterFilter } from \"./character_filter\";\nimport { Tokenizer, whitespaceTokenizer } from \"./tokenizer\";\nimport { lowercaseTokenFilter, TokenFilter } from \"./token_filter\";\n/**\n * A analyzer converts a string into tokens which are added to the inverted index for searching.\n */\nexport interface Analyzer {\n    /**\n     * The character filters of the analyzer.\n     */\n    char_filter?: CharacterFilter[];\n    /**\n     * The tokenizer of the analyzer.\n     */\n    tokenizer: Tokenizer;\n    /**\n     * The token filters of the analyzer.\n     */\n    token_filter?: TokenFilter[];\n}\n/**\n * Analyzes a given string.\n * @param {Analyzer} analyzer - the analyzer\n * @param {string} str - the string\n * @returns {string[]} - the tokens\n */\nexport declare function analyze(analyzer: Analyzer, str: string): string[];\n/**\n * An analyzer with the whitespace tokenizer and the lowercase token filter.\n */\nexport declare class StandardAnalyzer implements Analyzer {\n    tokenizer: typeof whitespaceTokenizer;\n    token_filter: (typeof lowercaseTokenFilter)[];\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search/src/analyzer/character_filter.d.ts",
    "content": "/**\n * A character filter is used to preprocess a string before it is passed to a tokenizer.\n */\nexport declare type CharacterFilter = (value: string) => string;\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search/src/analyzer/token_filter.d.ts",
    "content": "/**\n * A token filter takes tokens from a tokenizer and modify, delete or add tokens.\n */\nexport declare type TokenFilter = (value: string, index: number, array: string[]) => string;\n/**\n * Converts a token to lowercase.\n * @param {string} token - the token\n * @returns {string} - the lowercased token\n */\nexport declare function lowercaseTokenFilter(token: string): string;\n/**\n * Converts a token to uppercase.\n * @param {string} token - the token\n * @returns {string} - the uppercased token\n */\nexport declare function uppercaseTokenFilter(token: string): string;\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search/src/analyzer/tokenizer.d.ts",
    "content": "/**\n * A tokenizer splits a string into individual tokens.\n */\nexport declare type Tokenizer = (value: string) => string[];\n/**\n * Splits a string at whitespace characters into tokens.\n * @param {string} value - the string\n * @returns {string[]} - the tokens\n */\nexport declare function whitespaceTokenizer(value: string): string[];\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search/src/full_text_search.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\nimport { Scorer } from \"./scorer\";\nimport { Analyzer } from \"./analyzer/analyzer\";\nexport declare class FullTextSearch {\n    private _id;\n    private _docs;\n    private _idxSearcher;\n    private _invIdxs;\n    /**\n     * Registers the full-text search as plugin.\n     */\n    static register(): void;\n    /**\n     * Initialize the full-text search for the given fields.\n     * @param {object[]} fieldOptions - the field options\n     * @param {string} fieldOptions.field - the name of the property field\n     * @param {boolean=true} fieldOptions.store - flag to indicate if the full-text search should be stored on serialization or\n     *  rebuild on deserialization\n     * @param {boolean=true} fieldOptions.optimizeChanges - flag to optimize updating and deleting of documents\n     *    (requires more memory but performs faster)\n     * @param {Analyzer} fieldOptions.analyzer - an analyzer for the field\n     * @param {string} [id] - the property name of the document index\n     */\n    constructor(fieldOptions?: FullTextSearch.FieldOptions[], id?: string);\n    addDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    removeDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    updateDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    clear(): void;\n    search(query: Query): Scorer.ScoreResults;\n    toJSON(): FullTextSearch.Serialization;\n    static fromJSONObject(serialized: FullTextSearch.Serialization, analyzers?: Dict<Analyzer>): FullTextSearch;\n}\nexport declare namespace FullTextSearch {\n    interface FieldOptions extends InvertedIndex.FieldOptions {\n        field: string;\n    }\n    interface Serialization {\n        id: string;\n        ii: Dict<InvertedIndex.Serialization>;\n    }\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search/src/fuzzy/automaton.d.ts",
    "content": "/**\n * Transition with dest, min and max.\n * @hidden\n */\nexport declare type Transition = [number, number, number];\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MIN_CODE_POINT = 0;\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MAX_CODE_POINT = 1114111;\n/**\n * From org/apache/lucene/util/automaton/Automaton.java\n * @hidden\n */\nexport declare class Automaton {\n    private _stateTransitions;\n    private _accept;\n    private _nextState;\n    private _currState;\n    private _transitions;\n    constructor();\n    isAccept(n: number): boolean;\n    createState(): number;\n    setAccept(state: number, accept: boolean): void;\n    finishState(): void;\n    private _finishCurrentState();\n    getStartPoints(): number[];\n    step(state: number, label: number): number;\n    getNumStates(): number;\n    addTransition(source: number, dest: number, min: number, max: number): void;\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search/src/fuzzy/lev1t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev1TParametricDescription.java\n * @hidden\n */\nexport declare class Lev1TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search/src/fuzzy/lev2t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev2TParametricDescription.java\n * @hidden\n */\nexport declare class Lev2TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search/src/fuzzy/levenshtein_automata.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java\n * @hidden\n */\nexport declare class LevenshteinAutomata {\n    private _word;\n    private _numRanges;\n    private _rangeLower;\n    private _rangeUpper;\n    private _description;\n    private _alphabet;\n    private _editDistance;\n    constructor(input: number[], editDistance: number);\n    /**\n     * Transforms the NDFA to a DFA.\n     * @returns {Automaton}\n     */\n    toAutomaton(): Automaton;\n    private _getVector(x, pos, end);\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search/src/fuzzy/long.d.ts",
    "content": "/**\n * Class supports 64Bit integer operations.\n * A cut-down version of dcodeIO/long.js.\n * @hidden\n */\nexport declare class Long {\n    private _low;\n    private _high;\n    constructor(low?: number, high?: number);\n    /**\n     * Returns this long with bits arithmetically shifted to the right by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftRight(numBits: number): Long;\n    /**\n     * Returns this long with bits arithmetically shifted to the left by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftLeft(numBits: number): Long;\n    /**\n     * Returns the bitwise AND of this Long and the specified.\n     * @param {Long} other - the other Long\n     * @returns {Long} the long\n     */\n    and(other: Long): Long;\n    /**\n     * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.\n     * @returns {number}\n     */\n    toInt(): number;\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search/src/fuzzy/parametric_description.d.ts",
    "content": "import { Long } from \"./long\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java#ParametricDescription\n * @hidden\n */\nexport declare class ParametricDescription {\n    protected _w: number;\n    private _n;\n    private _minErrors;\n    constructor(w: number, n: number, minErrors: number[]);\n    /**\n     * Return the number of states needed to compute a Levenshtein DFA\n     */\n    size(): number;\n    /**\n     * Returns true if the <code>state</code> in any Levenshtein DFA is an accept state (final state).\n     */\n    isAccept(absState: number): boolean;\n    /**\n     * Returns the position in the input word for a given <code>state</code>.\n     * This is the minimal boundary for the state.\n     */\n    getPosition(absState: number): number;\n    static unpack(data: Long[], index: number, bitsPerValue: number): number;\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search/src/fuzzy/run_automaton.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/RunAutomaton.java\n * @hidden\n */\nexport declare class RunAutomaton {\n    private _points;\n    private _accept;\n    private _transitions;\n    private _classmap;\n    constructor(automaton: Automaton);\n    getCharClass(c: number): number;\n    step(state: number, c: number): number;\n    isAccept(state: number): boolean;\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search/src/index.d.ts",
    "content": "import { FullTextSearch } from \"./full_text_search\";\nimport { analyze, StandardAnalyzer } from \"./analyzer/analyzer\";\nimport { whitespaceTokenizer } from \"./analyzer/tokenizer\";\nimport { lowercaseTokenFilter, uppercaseTokenFilter } from \"./analyzer/token_filter\";\nexport { FullTextSearch, analyze, StandardAnalyzer, whitespaceTokenizer, lowercaseTokenFilter, uppercaseTokenFilter };\nexport default FullTextSearch;\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search/src/index_searcher.d.ts",
    "content": "import { Scorer } from \"./scorer\";\nimport { InvertedIndex } from \"./inverted_index\";\nimport { Query } from \"./query_types\";\nimport { Dict } from \"../../common/types\";\n/**\n * @hidden\n */\nexport declare class IndexSearcher {\n    private _invIdxs;\n    private _docs;\n    private _scorer;\n    /**\n     * Constructs an index searcher.\n     * @param {Dict<InvertedIndex>} invIdxs - the inverted indexes\n     * @param {Set<number>} docs - the ids of the documents\n     */\n    constructor(invIdxs: Dict<InvertedIndex>, docs: Set<InvertedIndex.DocumentIndex>);\n    search(query: Query): Scorer.ScoreResults;\n    setDirty(): void;\n    private _recursive(query, doScoring);\n    private _getUnique(queries, doScoring, queryResults);\n    private _getAll(queries, doScoring, queryResults?);\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search/src/inverted_index.d.ts",
    "content": "import { Analyzer } from \"./analyzer/analyzer\";\n/**\n * Converts a string into an array of code points.\n * @param str - the string\n * @returns {number[]} to code points\n * @hidden\n */\nexport declare function toCodePoints(str: string): number[];\n/**\n * Inverted index class handles featured text search for specific document fields.\n * @hidden\n */\nexport declare class InvertedIndex {\n    analyzer: Analyzer;\n    docCount: number;\n    docStore: Map<InvertedIndex.DocumentIndex, InvertedIndex.DocStore>;\n    totalFieldLength: number;\n    root: InvertedIndex.Index;\n    private _store;\n    private _optimizeChanges;\n    /**\n     * @param {boolean} [options.store=true] - inverted index will be stored at serialization rather than rebuilt on load\n     * @param {boolean} [options.optimizeChanges=true] - flag to store additional metadata inside the index for better\n     *  performance if an existing field is updated or removed\n     * @param {Analyzer} [options.analyzer=] - the analyzer of this inverted index\n     */\n    constructor(options?: InvertedIndex.FieldOptions);\n    /**\n     * Adds defined fields of a document to the inverted index.\n     * @param {string} field - the field to add\n     * @param {number} docId - the doc id of the field\n     */\n    insert(field: string, docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Removes all relevant terms of a document from the inverted index.\n     * @param {number} docId - the document.\n     */\n    remove(docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Gets the term index of a term.\n     * @param {string} term - the term\n     * @param {object} root - the term index to start from\n     * @param {number} start - the position of the term string to start from\n     * @return {object} - The term index or null if the term is not in the term tree.\n     */\n    static getTermIndex(term: number[], root: InvertedIndex.Index, start?: number): InvertedIndex.Index;\n    /**\n     * Extends a term index to all available term leafs.\n     * @param {object} idx - the term index to start from\n     * @param {number[]} [term=[]] - the current term\n     * @param {Array} termIndices - all extended indices with their term\n     * @returns {Array} - Array with term indices and extension\n     */\n    static extendTermIndex(idx: InvertedIndex.Index, term?: number[], termIndices?: InvertedIndex.IndexTerm[]): InvertedIndex.IndexTerm[];\n    /**\n     * Serialize the inverted index.\n     * @returns {{docStore: *, _fields: *, index: *}}\n     */\n    toJSON(): InvertedIndex.Serialization;\n    /**\n     * Deserialize the inverted index.\n     * @param {{docStore: *, _fields: *, index: *}} serialized - The serialized inverted index.\n     * @param {Analyzer} analyzer[undefined] - an analyzer\n     */\n    static fromJSONObject(serialized: InvertedIndex.Serialization, analyzer?: Analyzer): InvertedIndex;\n    private static _serializeIndex(idx);\n    private static _deserializeIndex(serialized);\n    /**\n     * Set parent of to each index and regenerate the indexRef.\n     * @param {Index} index - the index\n     * @param {Index} parent - the parent\n     */\n    private _regenerate(index, parent);\n    /**\n     * Iterate over the whole inverted index and remove the document.\n     * Delete branch if not needed anymore.\n     * Function is needed if index is used without optimization.\n     * @param {Index} idx - the index\n     * @param {number} docId - the doc id\n     * @returns {boolean} true if index is empty\n     */\n    private _remove(idx, docId);\n}\nexport declare namespace InvertedIndex {\n    interface FieldOptions {\n        store?: boolean;\n        optimizeChanges?: boolean;\n        analyzer?: Analyzer;\n    }\n    type Index = Map<number, any> & {\n        dc?: Map<DocumentIndex, number>;\n        df?: number;\n        pa?: Index;\n    };\n    type IndexTerm = {\n        index: Index;\n        term: number[];\n    };\n    interface SerializedIndex {\n        d?: {\n            df: number;\n            dc: [DocumentIndex, number][];\n        };\n        k?: number[];\n        v?: SerializedIndex[];\n    }\n    type Serialization = SpareSerialization | FullSerialization;\n    type SpareSerialization = {\n        _store: false;\n        _optimizeChanges: boolean;\n    };\n    type FullSerialization = {\n        _store: true;\n        _optimizeChanges: boolean;\n        docCount: number;\n        docStore: [DocumentIndex, DocStore][];\n        totalFieldLength: number;\n        root: SerializedIndex;\n    };\n    interface DocStore {\n        fieldLength?: number;\n        indexRef?: Index[];\n    }\n    type DocumentIndex = number | string;\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search/src/query_types.d.ts",
    "content": "/**\n * Base query to enable boost to a query type.\n */\nexport interface BaseQuery<Type> {\n    type: Type;\n    boost?: number;\n}\n/**\n * A query which finds documents where a document field contains a term.\n */\nexport interface TermQuery extends BaseQuery<\"term\"> {\n    field: string;\n    value: string;\n}\n/**\n * A query which finds documents where a document field contains any of the terms.\n */\nexport interface TermsQuery extends BaseQuery<\"terms\"> {\n    field: string;\n    value: string[];\n}\n/**\n * A query which finds documents where the wildcard term can be applied at an existing document field term.\n */\nexport interface WildcardQuery extends BaseQuery<\"wildcard\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which finds documents where the fuzzy term can be transformed into an existing document field term within a\n * given edit distance.\n */\nexport interface FuzzyQuery extends BaseQuery<\"fuzzy\"> {\n    field: string;\n    value: string;\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query which matches documents containing the prefix of a term inside a field.\n */\nexport interface PrefixQuery extends BaseQuery<\"prefix\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which matches all documents with a given field.\n */\nexport interface ExistsQuery extends BaseQuery<\"exists\"> {\n    field: string;\n}\n/**\n * A query which tokenizes the given text into tokens and performs a sub query for each token. The results are combined\n * using a boolean operator.\n */\nexport interface MatchQuery extends BaseQuery<\"match\"> {\n    field: string;\n    value: string;\n    minimum_should_match?: number | string;\n    operator?: \"and\" | \"or\";\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query that matches all documents and giving them a constant score equal to the query boost.\n*/\nexport interface MatchQueryAll extends BaseQuery<\"match_all\"> {\n}\n/**\n * A query that wraps sub queries and returns a constant score equal to the query boost for every document in the filter.\n */\nexport interface ConstantScoreQuery extends BaseQuery<\"constant_score\"> {\n    filter: QueryTypes[];\n}\n/**\n * A query that matches documents matching boolean combinations of sub queries.\n */\nexport interface BoolQuery extends BaseQuery<\"bool\"> {\n    must?: QueryTypes[];\n    filter?: QueryTypes[];\n    should?: QueryTypes[];\n    not?: QueryTypes[];\n    minimum_should_match?: number | string;\n}\n/**\n * Union type of possible query types.\n */\nexport declare type QueryTypes = BoolQuery | ConstantScoreQuery | TermQuery | TermsQuery | WildcardQuery | FuzzyQuery | MatchQuery | MatchQueryAll | PrefixQuery | ExistsQuery;\n/**\n * The main query with the actually full-text search query and the scoring parameters.\n */\nexport interface Query {\n    query: QueryTypes;\n    calculate_scoring?: boolean;\n    explain?: boolean;\n    bm25?: {\n        k1: number;\n        b: number;\n    };\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search/src/scorer.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\n/**\n * @hidden\n */\nexport declare class Scorer {\n    private _invIdxs;\n    private _cache;\n    constructor(invIdxs: Dict<InvertedIndex>);\n    setDirty(): void;\n    score(fieldName: string, boost: number, termIdx: InvertedIndex.Index, doScoring: boolean | null, queryResults: Scorer.QueryResults, term: number[], df?: number): void;\n    scoreConstant(boost: number, docId: InvertedIndex.DocumentIndex, queryResults: Scorer.QueryResults): Scorer.QueryResults;\n    finalScore(query: Query, queryResults: Scorer.QueryResults): Scorer.ScoreResults;\n    private static _calculateFieldLength(fieldLength);\n    private _getCache(fieldName);\n    /**\n     * Returns the idf by either calculate it or use a cached one.\n     * @param {string} fieldName - the name of the field\n     * @param {number} docFreq - the doc frequency of the term\n     * @returns {number} the idf\n     * @private\n     */\n    private _idf(fieldName, docFreq);\n    private _avgFieldLength(fieldName);\n}\nexport declare namespace Scorer {\n    interface IDFCache {\n        idfs: Dict<number>;\n        avgFieldLength: number;\n    }\n    interface QueryResult {\n        tf?: number;\n        idf?: number;\n        boost: number;\n        fieldName?: string;\n        term?: number[];\n    }\n    type QueryResults = Map<InvertedIndex.DocumentIndex, QueryResult[]>;\n    interface BM25Explanation {\n        boost: number;\n        score: number;\n        docID: number;\n        fieldName: string;\n        index: string;\n        idf: number;\n        tfNorm: number;\n        tf: number;\n        fieldLength: number;\n        avgFieldLength: number;\n    }\n    interface ConstantExplanation {\n        boost: number;\n        score: number;\n    }\n    type ScoreExplanation = BM25Explanation | ConstantExplanation;\n    type ScoreResult = {\n        score: number;\n        explanation?: ScoreExplanation[];\n    };\n    type ScoreResults = Dict<ScoreResult>;\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search-language/src/index.d.ts",
    "content": "export { generateStopWordFilter, generateTrimmer, Among, SnowballProgram } from \"./language\";\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search-language/src/language.d.ts",
    "content": "export declare function generateTrimmer(wordCharacters: string): (token: string) => string;\nexport declare function generateStopWordFilter(stopWords: string[]): (token: string) => string;\nexport declare class Among {\n    s_size: number;\n    s: number[];\n    substring_i: number;\n    result: number;\n    method: any;\n    constructor(s: string, substring_i: number, result: number, method?: any);\n}\nexport declare class SnowballProgram {\n    current: string;\n    bra: number;\n    ket: number;\n    limit: number;\n    cursor: number;\n    limit_backward: number;\n    constructor();\n    setCurrent(word: string): void;\n    getCurrent(): string;\n    in_grouping(s: number[], min: number, max: number): boolean;\n    in_grouping_b(s: number[], min: number, max: number): boolean;\n    out_grouping(s: number[], min: number, max: number): boolean;\n    out_grouping_b(s: number[], min: number, max: number): boolean;\n    eq_s(s_size: number, s: string): boolean;\n    eq_s_b(s_size: number, s: string): boolean;\n    find_among(v: Among[], v_size: number): number;\n    find_among_b(v: Among[], v_size: number): number;\n    replace_s(c_bra: number, c_ket: number, s: string): number;\n    slice_check(): void;\n    slice_from(s: string): void;\n    slice_del(): void;\n    insert(c_bra: number, c_ket: number, s: string): void;\n    slice_to(): string;\n    eq_v_b(s: string): boolean;\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search-language-de/src/german_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class GermanAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search-language-de/src/index.d.ts",
    "content": "import { GermanAnalyzer } from \"./german_analyzer\";\nexport { GermanAnalyzer };\nexport default GermanAnalyzer;\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search-language-en/src/english_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class EnglishAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/full-text-search-language-en/src/index.d.ts",
    "content": "import { EnglishAnalyzer } from \"./english_analyzer\";\nexport { EnglishAnalyzer };\nexport default EnglishAnalyzer;\n"
  },
  {
    "path": "dist/packages/fs-storage/types/indexed-storage/src/index.d.ts",
    "content": "import { IndexedStorage } from \"./indexed_storage\";\nexport { IndexedStorage };\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/fs-storage/types/indexed-storage/src/indexed_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * Loki persistence adapter class for indexedDb.\n *     This class fulfills abstract adapter interface which can be applied to other storage methods.\n *     Utilizes the included LokiCatalog app/key/value database for actual database persistence.\n *     IndexedDb storage is provided per-domain, so we implement app/key/value database to\n *     allow separate contexts for separate apps within a domain.\n */\nexport declare class IndexedStorage implements StorageAdapter {\n    private _appname;\n    private catalog;\n    /**\n     * Registers the indexed storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the indexed storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {string} [appname=loki] - Application name context can be used to distinguish subdomains, \"loki\" by default\n     */\n    constructor(appname?: string);\n    /**\n     * Retrieves a serialized db string from the catalog.\n     *\n     * @example\n     * // LOAD\n     * var idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * var db = new loki(\"test\", { adapter: idbAdapter });\n     *   db.base(function(result) {\n       *   console.log(\"done\");\n       * });\n     *\n     * @param {string} dbname - the name of the database to retrieve.\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<{}>;\n    /**\n     * Saves a serialized db to the catalog.\n     *\n     * @example\n     * // SAVE : will save App/Key/Val as \"finance\"/\"test\"/{serializedDb}\n     * let idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * let db = new loki(\"test\", { adapter: idbAdapter });\n     * let coll = db.addCollection(\"testColl\");\n     * coll.insert({test: \"val\"});\n     * db.saveDatabase();  // could pass callback if needed for async complete\n     *\n     * @param {string} dbname - the name to give the serialized database within the catalog.\n     * @param {string} dbstring - the serialized db string to save.\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a serialized db from the catalog.\n     *\n     * @example\n     * // DELETE DATABASE\n     * // delete \"finance\"/\"test\" value from catalog\n     * idbAdapter.deleteDatabase(\"test\", function {\n       *   // database deleted\n       * });\n     *\n     * @param {string} dbname - the name of the database to delete from the catalog.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n    /**\n     * Removes all database partitions and pages with the base filename passed in.\n     * This utility method does not (yet) guarantee async deletions will be completed before returning\n     *\n     * @param {string} dbname - the base filename which container, partitions, or pages are derived\n     */\n    deleteDatabasePartitions(dbname: string): void;\n    /**\n     * Retrieves object array of catalog entries for current app.\n     *\n     * @example\n     * idbAdapter.getDatabaseList(function(result) {\n       *   // result is array of string names for that appcontext (\"finance\")\n       *   result.forEach(function(str) {\n       *     console.log(str);\n       *   });\n       * });\n     *\n     * @param {function} callback - should accept array of database names in the catalog for current app.\n     */\n    getDatabaseList(callback: (names: string[]) => void): void;\n    /**\n     * Allows retrieval of list of all keys in catalog along with size\n     * @param {function} callback - (Optional) callback to accept result array.\n     */\n    getCatalogSummary(callback: (entry: Entry[]) => void): void;\n}\nexport interface Entry {\n    app: string;\n    key: string;\n    size: number;\n}\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/fs-storage/types/local-storage/src/index.d.ts",
    "content": "import { LocalStorage } from \"./local_storage\";\nexport { LocalStorage };\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/fs-storage/types/local-storage/src/local_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists to web browser's local storage object\n * @constructor LocalStorageAdapter\n */\nexport declare class LocalStorage implements StorageAdapter {\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * loadDatabase() - Load data from localstorage\n     * @param {string} dbname - the name of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * saveDatabase() - save data to localstorage, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was saved\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * deleteDatabase() - delete the database from localstorage, will throw an error if it\n     * can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/fs-storage/types/loki/src/avl_index.d.ts",
    "content": "import { IRangedIndex, IRangedIndexRequest } from \"./ranged_indexes\";\nimport { ILokiComparer } from \"./comparators\";\n/**\n * Treenode type for binary search tree (BST) implementation.\n *\n * To support duplicates, we may need to either repurpose parent to\n * point to 'elder' sibling or add a siblingId to point to owner of\n * node represented in tree.\n */\nexport declare type TreeNode<T> = {\n    id: number;\n    value: T;\n    parent: number | null;\n    balance: number;\n    height: number;\n    left: number | null;\n    right: number | null;\n    siblings: number[];\n};\nexport interface ITreeNodeHash<T> {\n    [id: number]: TreeNode<T>;\n}\n/**\n * LokiDB AVL Balanced Binary Tree Index implementation.\n * To support duplicates, we use siblings (array) in tree nodes.\n * Basic AVL components guided by William Fiset tutorials at :\n * https://github.com/williamfiset/data-structures/blob/master/com/williamfiset/datastructures/balancedtree/AVLTreeRecursive.java\n * https://www.youtube.com/watch?v=g4y2h70D6Nk&list=PLDV1Zeh2NRsD06x59fxczdWLhDDszUHKt\n */\nexport declare class AvlTreeIndex<T> implements IRangedIndex<T> {\n    name: string;\n    comparator: ILokiComparer<T>;\n    nodes: ITreeNodeHash<T>;\n    apex: number | null;\n    /**\n     * Initializes index with property name and a comparer function.\n     */\n    constructor(name: string, comparator: ILokiComparer<T>);\n    backup(): AvlTreeIndex<T>;\n    restore(tree: AvlTreeIndex<T>): void;\n    /**\n     * Used for inserting a new value into the BinaryTreeIndex\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val Value to be indexed and inserted into binary tree\n     */\n    insert(id: number, val: T): void;\n    /**\n     * Recursively inserts a treenode and re-balances if needed.\n     * @param current\n     * @param node\n     */\n    insertNode(current: TreeNode<T>, node: TreeNode<T>): number;\n    /**\n     * Updates height and balance (calculation) for tree node\n     * @param node\n     */\n    private updateBalance(node);\n    /**\n     * Balance the 'double left-heavy' condition\n     * @param node\n     */\n    private leftLeftCase(node);\n    /**\n     * Balance the '(parent) left heavy, (child) right heavy' condition\n     * @param node\n     */\n    private leftRightCase(node);\n    /**\n     * Balance the 'double right-heavy' condition\n     * @param node\n     */\n    private rightRightCase(node);\n    /**\n     * Balance the '(parent) right heavy, (child) left heavy' condition\n     * @param node\n     */\n    private rightLeftCase(node);\n    /**\n     * Left rotation of node. Swaps right child into current location.\n     * @param node\n     */\n    private rotateLeft(node);\n    /**\n     * Right rotation of node. Swaps left child into current location.\n     * @param node\n     */\n    private rotateRight(node);\n    /**\n     * Diagnostic method for examining tree contents and structure\n     * @param node\n     */\n    getValuesAsTree(node?: TreeNode<T>): any;\n    /**\n     * Updates a value, possibly relocating it, within binary tree\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val New value to be indexed within binary tree\n     */\n    update(id: number, val: T): void;\n    /**\n     * Removes a value from the binary tree index\n     * @param id\n     */\n    remove(id: number): void;\n    /**\n     * Recursive node removal and rebalancer\n     * @param node\n     * @param val\n     */\n    private removeNode(node, id);\n    /**\n     * Utility method for updating a parent's child link when it changes\n     * @param parentId\n     * @param oldChildId\n     * @param newChildId\n     */\n    private updateChildLink(parentId, oldChildId, newChildId);\n    /**\n     * When removing a parent with only child, this does simple remap of child to grandParent.\n     * @param grandParent New parent of 'child'.\n     * @param parent Node being removed.\n     * @param child Node to reparent to grandParent.\n     */\n    private promoteChild(parent, child);\n    /**\n     * Finds a successor to a node and replaces that node with it.\n     * @param node\n     */\n    private promoteSuccessor(node);\n    /**\n     * Utility method for finding In-Order predecessor to the provided node\n     * @param node Parent node to find leaf node of greatest 'value'\n    */\n    private findGreaterLeaf(node);\n    /**\n     * Utility method for finding In-Order successor to the provided node\n     * @param node Parent Node to find leaf node of least 'value'\n     */\n    private findLesserLeaf(node);\n    /**\n     *  Interface method to support ranged queries.  Results sorted by index property.\n     * @param range Options for ranged request.\n     */\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    /**\n     * Implements ranged request operations.\n     * @param node\n     * @param range\n     */\n    private collateRequest(node, range);\n    /**\n     * Used on a branch node to return an array of id within that branch, sorted by their value\n     * @param node\n     */\n    private collateIds(node);\n    /**\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    /**\n     * Inline/Non-recusive 'single value' ($eq) lookup.\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    private locate(node, val);\n    /**\n     * Index integrity check (IRangedIndex interface function)\n     */\n    validateIndex(): boolean;\n    /**\n     * Recursive Node validation routine\n     * @param node\n     */\n    private validateNode(node);\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/loki/src/clone.d.ts",
    "content": "export declare type CloneMethod = \"parse-stringify\" | \"deep\" | \"shallow\" | \"shallow-recurse\";\n/**\n * @hidden\n */\nexport declare function clone<T>(data: T, method?: CloneMethod): T;\n"
  },
  {
    "path": "dist/packages/fs-storage/types/loki/src/collection.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { UniqueIndex } from \"./unique_index\";\nimport { ResultSet } from \"./result_set\";\nimport { DynamicView } from \"./dynamic_view\";\nimport { IRangedIndex } from \"./ranged_indexes\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc, Dict } from \"../../common/types\";\nimport { FullTextSearch } from \"../../full-text-search/src/full_text_search\";\nimport { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\n/**\n * Collection class that handles documents of same type\n * @extends LokiEventEmitter\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class Collection<TData extends object = object, TNested extends object = object, T extends TData & TNested = TData & TNested> extends LokiEventEmitter {\n    name: string;\n    _data: Doc<T>[];\n    private _idIndex;\n    _rangedIndexes: {\n        [P in keyof T]?: Collection.RangedIndexMeta;\n    };\n    _lokimap: {\n        [$loki: number]: Doc<T>;\n    };\n    _unindexedSortComparator: string;\n    _defaultLokiOperatorPackage: string;\n    /**\n     * Unique constraints contain duplicate object references, so they are not persisted.\n     * We will keep track of properties which have unique constraints applied here, and regenerate on load.\n     */\n    _constraints: {\n        unique: {\n            [P in keyof T]?: UniqueIndex;\n        };\n    };\n    /**\n     * Transforms will be used to store frequently used query chains as a series of steps which itself can be stored along\n     * with the database.\n     */\n    _transforms: Dict<Collection.Transform<T>[]>;\n    /**\n     * In autosave scenarios we will use collection level dirty flags to determine whether save is needed.\n     * currently, if any collection is dirty we will autosave the whole database if autosave is configured.\n     * Defaulting to true since this is called from addCollection and adding a collection should trigger save.\n     */\n    _dirty: boolean;\n    private _cached;\n    /**\n     * Is collection transactional.\n     */\n    private _transactional;\n    /**\n     * Options to clone objects when inserting them.\n     */\n    _cloneObjects: boolean;\n    /**\n     * Default clone method (if enabled) is parse-stringify.\n     */\n    _cloneMethod: CloneMethod;\n    /**\n     * If set to true we will not maintain a meta property for a document.\n     */\n    private _disableMeta;\n    /**\n     * Disable track changes.\n     */\n    private _disableChangesApi;\n    /**\n     * Disable delta update object style on changes.\n     */\n    _disableDeltaChangesApi: boolean;\n    /**\n     * By default, if you insert a document with a Date value for an indexed property, we will convert that value to number.\n     */\n    private _serializableIndexes;\n    /**\n     * Name of path of used nested properties.\n     */\n    private _nestedProperties;\n    /**\n     * Option to activate a cleaner daemon - clears \"aged\" documents at set intervals.\n     */\n    _ttl: Collection.TTL;\n    private _maxId;\n    private _dynamicViews;\n    /**\n     * Changes are tracked by collection and aggregated by the db.\n     */\n    private _changes;\n    /**\n     * stages: a map of uniquely identified 'stages', which hold copies of objects to be\n     * manipulated without affecting the data in the original collection\n     */\n    private _stages;\n    private _commitLog;\n    _fullTextSearch: FullTextSearch;\n    /**\n     * @param {string} name - collection name\n     * @param {(object)} [options={}] - a configuration object\n     * @param {string[]} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {string[]} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {RangedIndexOptions} [options.rangedIndexes] - configuration object for ranged indexes\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are invoked asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes API\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {boolean} [options.serializableIndexes=true] - converts date values on binary indexed property values are serializable\n     * @param {string} [options.cloneMethod=\"deep\"] - the clone method\n     * @param {number} [options.transactional=false] - ?\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale.\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @param {string} [options.unindexedSortComparator=\"js\"] \"js\", \"abstract\", \"abstract-date\", \"loki\" or other registered comparator name\n     * @param {string} [options.defaultLokiOperatorPackage=\"js\"] \"js\", \"loki\", \"comparator\" (or user defined) query ops package\n     * @param {FullTextSearch.FieldOptions} [options.fullTextSearch=] - the full-text search options\n     * @see {@link Loki#addCollection} for normal creation of collections\n     */\n    constructor(name: string, options?: Collection.Options<TData, TNested>);\n    toJSON(): Collection.Serialized;\n    static fromJSONObject(obj: Collection.Serialized, options?: Collection.DeserializeOptions): Collection<any, object, any>;\n    /**\n     * Adds a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {array} transform - an array of transformation 'step' objects to save into the collection\n     */\n    addTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Retrieves a named transform from the collection.\n     * @param {string} name - name of the transform to lookup.\n     */\n    getTransform(name: string): Collection.Transform<T>[];\n    /**\n     * Updates a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {object} transform - a transformation object to save into collection\n     */\n    setTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Removes a named collection transform from the collection\n     * @param {string} name - name of collection transform to remove\n     */\n    removeTransform(name: string): void;\n    private setTTL(age, interval);\n    /**\n     * Create a row filter that covers all documents in the collection.\n     */\n    _prepareFullDocIndex(): number[];\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field\n     * @param indexTypeName\n     * @param comparatorName\n     */\n    ensureIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field Property to create an index on (need to look into contraining on keyof T)\n     * @param indexTypeName Name of IndexType factory within (global?) hashmap to create IRangedIndex from\n     * @param comparatorName Name of Comparator within (global?) hashmap\n     */\n    ensureRangedIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    ensureUniqueIndex(field: keyof T): UniqueIndex;\n    /**\n     * Quickly determine number of documents in collection (or query)\n     * @param {object} query - (optional) query object to count results of\n     * @returns {number} number of documents in the collection\n     */\n    count(query?: ResultSet.Query<Doc<T>>): number;\n    /**\n     * Rebuild idIndex\n     */\n    private _ensureId();\n    /**\n     * Add a dynamic view to the collection\n     * @param {string} name - name of dynamic view to add\n     * @param {object} options - (optional) options to configure dynamic view with\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=SortPriority.PASSIVE] - the sort priority\n     * @param {number} options.minRebuildInterval - minimum rebuild interval (need clarification to docs here)\n     * @returns {DynamicView} reference to the dynamic view added\n     **/\n    addDynamicView(name: string, options?: DynamicView.Options): DynamicView<T>;\n    /**\n     * Remove a dynamic view from the collection\n     * @param {string} name - name of dynamic view to remove\n     **/\n    removeDynamicView(name: string): void;\n    /**\n     * Look up dynamic view reference from within the collection\n     * @param {string} name - name of dynamic view to retrieve reference of\n     * @returns {DynamicView} A reference to the dynamic view with that name\n     **/\n    getDynamicView(name: string): DynamicView<T>;\n    /**\n     * Applies a 'mongo-like' find query object and passes all results to an update function.\n     * @param {object} filterObject - the 'mongo-like' query object\n     * @param {function} updateFunction - the update function\n     */\n    findAndUpdate(filterObject: ResultSet.Query<Doc<T>>, updateFunction: (obj: Doc<T>) => any): void;\n    /**\n     * Applies a 'mongo-like' find query object removes all documents which match that filter.\n     * @param {object} filterObject - 'mongo-like' query object\n     */\n    findAndRemove(filterObject: ResultSet.Query<Doc<T>>): void;\n    /**\n     * Adds object(s) to collection, ensure object(s) have meta properties, clone it if necessary, etc.\n     * @param {(object|array)} doc - the document (or array of documents) to be inserted\n     * @returns {(object|array)} document or documents inserted\n     */\n    insert(doc: TData): Doc<T>;\n    insert(doc: TData[]): Doc<T>[];\n    /**\n     * Adds a single object, ensures it has meta properties, clone it if necessary, etc.\n     * @param {object} doc - the document to be inserted\n     * @param {boolean} bulkInsert - quiet pre-insert and insert event emits\n     * @returns {object} document or 'undefined' if there was a problem inserting it\n     */\n    insertOne(doc: TData, bulkInsert?: boolean): Doc<T>;\n    /**\n     * Refers nested properties of an object to the root of it.\n     * @param {T} data - the object\n     * @returns {T & TNested} the object with nested properties\n     * @hidden\n     */\n    _defineNestedProperties<U extends TData>(data: U): U & TNested;\n    /**\n     * Empties the collection.\n     * @param {boolean} [removeIndices=false] - remove indices\n     */\n    clear({removeIndices: removeIndices}?: {\n        removeIndices?: boolean;\n    }): void;\n    /**\n     * Updates an object and notifies collection that the document has changed.\n     * @param {object} doc - document to update within the collection\n     */\n    update(doc: Doc<T> | Doc<T>[]): void;\n    /**\n     * Add object to collection\n     */\n    private _add(obj);\n    /**\n     * Applies a filter function and passes all results to an update function.\n     * @param {function} filterFunction - the filter function\n     * @param {function} updateFunction - the update function\n     */\n    updateWhere(filterFunction: (obj: Doc<T>) => boolean, updateFunction: (obj: Doc<T>) => Doc<T>): void;\n    /**\n     * Remove all documents matching supplied filter function.\n     * @param {function} filterFunction - the filter function\n     */\n    removeWhere(filterFunction: (obj: Doc<T>) => boolean): void;\n    removeDataOnly(): void;\n    /**\n     * Remove a document from the collection\n     * @param {number|object} doc - document to remove from collection\n     */\n    remove(doc: number | Doc<T> | Doc<T>[]): void;\n    /**\n     * Returns all changes.\n     * @returns {Collection.Change[]}\n     */\n    getChanges(): Collection.Change[];\n    /**\n     * Enables/disables changes api.\n     * @param {boolean} disableChangesApi\n     * @param {boolean} disableDeltaChangesApi\n     */\n    setChangesApi(disableChangesApi: boolean, disableDeltaChangesApi?: boolean): void;\n    /**\n     * Clears all the changes.\n     */\n    flushChanges(): void;\n    private _getObjectDelta(oldObject, newObject);\n    /**\n     * Compare changed object (which is a forced clone) with existing object and return the delta\n     */\n    private _getChangeDelta(obj, old);\n    /**\n     * Creates a clone of the current status of an object and associates operation and collection name,\n     * so the parent db can aggregate and generate a changes object for the entire db\n     */\n    private _createChange(name, op, obj, old?);\n    private _createInsertChange(obj);\n    private _createUpdateChange(obj, old);\n    private _insertMetaWithChange(obj);\n    private _updateMetaWithChange(obj, old);\n    private _insertMeta(obj);\n    private _updateMeta(obj);\n    /**\n     * Get by Id - faster than other methods because of the searching algorithm\n     * @param {int} id - $loki id of document you want to retrieve\n     * @param {boolean} returnPosition - if 'true' we will return [object, position]\n     * @returns {(object|array|null)} Object reference if document was found, null if not,\n     *     or an array if 'returnPosition' was passed.\n     */\n    get(id: number): Doc<T>;\n    get(id: number, returnPosition: boolean): Doc<T> | [Doc<T>, number];\n    /**\n     * Retrieve doc by Unique index\n     * @param {string} field - name of uniquely indexed property to use when doing lookup\n     * @param {any} value - unique value to search for\n     * @returns {object} document matching the value passed\n     */\n    by(field: keyof T, value: any): Doc<T>;\n    /**\n     * Find one object by index property, by property equal to value\n     * @param {object} query - query object used to perform search with\n     * @returns {(object|null)} First matching document, or null if none\n     */\n    findOne(query: ResultSet.Query<Doc<T>>): Doc<T>;\n    /**\n     * Chain method, used for beginning a series of chained find() and/or view() operations\n     * on a collection.\n     *\n     * @param {array} transform - Ordered array of transform step objects similar to chain\n     * @param {object} parameters - Object containing properties representing parameters to substitute\n     * @returns {ResultSet} (this) ResultSet, or data array if any map or join functions where called\n     */\n    chain(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Find method, api is similar to mongodb.\n     * for more complex queries use [chain()]{@link Collection#chain} or [where()]{@link Collection#where}.\n     * @example {@tutorial Query Examples}\n     * @param {object} query - 'mongo-like' query object\n     * @returns {array} Array of matching documents\n     */\n    find(query?: ResultSet.Query<Doc<T>>): Doc<T>[];\n    /**\n     * Find object by unindexed field by property equal to value,\n     * simply iterates and returns the first element matching the query\n     */\n    findOneUnindexed(prop: string, value: any): Doc<T>;\n    /**\n     * Transaction methods\n     */\n    /**\n     * start the transation\n     */\n    startTransaction(): void;\n    /**\n     * Commit the transaction.\n     */\n    commit(): void;\n    /**\n     * Rollback the transaction.\n     */\n    rollback(): void;\n    /**\n     * Query the collection by supplying a javascript filter function.\n     * @example\n     * let results = coll.where(function(obj) {\n       *   return obj.legs === 8;\n       * });\n     * @param {function} fun - filter function to run against all collection docs\n     * @returns {array} all documents which pass your filter function\n     */\n    where(fun: (obj: Doc<T>) => boolean): Doc<T>[];\n    /**\n     * Map Reduce operation\n     * @param {function} mapFunction - function to use as map function\n     * @param {function} reduceFunction - function to use as reduce function\n     * @returns {data} The result of your mapReduce operation\n     */\n    mapReduce<U1, U2>(mapFunction: (value: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Join two collections on specified properties\n     * @param {array} joinData - array of documents to 'join' to this collection\n     * @param {string} leftJoinProp - property name in collection\n     * @param {string} rightJoinProp - property name in joinData\n     * @param {function} mapFun - (Optional) map function to use\n     * @param dataOptions - options to data() before input to your map function\n     * @param [dataOptions.removeMeta] - allows removing meta before calling mapFun\n     * @param [dataOptions.forceClones] - forcing the return of cloned objects to your map object\n     * @param [dataOptions.forceCloneMethod] - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} Result of the mapping operation\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinProp: string | ((obj: any) => string), rightJoinProp: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * (Staging API) create a stage and/or retrieve it\n     */\n    getStage(name: string): any;\n    /**\n     * a collection of objects recording the changes applied through a commmitStage\n     */\n    /**\n     * (Staging API) create a copy of an object and insert it into a stage\n     */\n    stage<F extends TData>(stageName: string, obj: Doc<F>): F;\n    /**\n     * (Staging API) re-attach all objects to the original collection, so indexes and views can be rebuilt\n     * then create a message to be inserted in the commitlog\n     * @param {string} stageName - name of stage\n     * @param {string} message\n     */\n    commitStage(stageName: string, message: string): void;\n    /**\n     * Returns all values of a field.\n     * @param {string} field - the field name\n     * @return {any}: the array of values\n     */\n    extract(field: keyof T): any[];\n    /**\n     * Finds the minimum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the minimum value\n     */\n    min(field: keyof T): number;\n    /**\n     * Finds the maximum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the maximum value\n     */\n    max(field: keyof T): number;\n    /**\n     * Finds the minimum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    minRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Finds the maximum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    maxRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Returns all values of a field as numbers (if possible).\n     * @param {string} field - the field name\n     * @return {number[]} - the number array\n     */\n    extractNumerical(field: keyof T): number[];\n    /**\n     * Calculates the average numerical value of a field\n     * @param {string} field - the field name\n     * @returns {number} average of property in all docs in the collection\n     */\n    avg(field: keyof T): number;\n    /**\n     * Calculate the standard deviation of a field.\n     * @param {string} field - the field name\n     * @return {number} the standard deviation\n     */\n    stdDev(field: keyof T): number;\n    /**\n     * Calculates the mode of a field.\n     * @param {string} field - the field name\n     * @return {number} the mode\n     */\n    mode(field: keyof T): number;\n    /**\n     * Calculates the median of a field.\n     * @param {string} field - the field name\n     * @return {number} the median\n     */\n    median(field: keyof T): number;\n}\nexport declare namespace Collection {\n    interface Options<TData extends object, TNested extends object = {}, T extends object = TData & TNested> {\n        unique?: (keyof T)[];\n        unindexedSortComparator?: string;\n        defaultLokiOperatorPackage?: string;\n        rangedIndexes?: RangedIndexOptions;\n        serializableIndexes?: boolean;\n        asyncListeners?: boolean;\n        disableMeta?: boolean;\n        disableChangesApi?: boolean;\n        disableDeltaChangesApi?: boolean;\n        clone?: boolean;\n        serializableIndices?: boolean;\n        cloneMethod?: CloneMethod;\n        transactional?: boolean;\n        ttl?: number;\n        ttlInterval?: number;\n        nestedProperties?: (keyof TNested | {\n            name: keyof TNested;\n            path: string[];\n        })[];\n        fullTextSearch?: FullTextSearch.FieldOptions[];\n    }\n    interface RangedIndexOptions {\n        [prop: string]: RangedIndexMeta;\n    }\n    interface DeserializeOptions {\n        retainDirtyFlags?: boolean;\n        fullTextSearch?: Dict<Analyzer>;\n        [collName: string]: any | {\n            proto?: any;\n            inflate?: (src: object, dest?: object) => void;\n        };\n    }\n    interface BinaryIndex {\n        dirty: boolean;\n        values: any;\n    }\n    interface RangedIndexMeta {\n        index?: IRangedIndex<any>;\n        indexTypeName?: string;\n        comparatorName?: string;\n    }\n    interface Change {\n        name: string;\n        operation: string;\n        obj: any;\n    }\n    interface Serialized {\n        name: string;\n        unindexedSortComparator: string;\n        defaultLokiOperatorPackage: string;\n        _dynamicViews: DynamicView[];\n        _nestedProperties: {\n            name: string;\n            path: string[];\n        }[];\n        uniqueNames: string[];\n        transforms: Dict<Transform[]>;\n        rangedIndexes: RangedIndexOptions;\n        _data: Doc<any>[];\n        idIndex: number[];\n        maxId: number;\n        _dirty: boolean;\n        transactional: boolean;\n        asyncListeners: boolean;\n        disableMeta: boolean;\n        disableChangesApi: boolean;\n        disableDeltaChangesApi: boolean;\n        cloneObjects: boolean;\n        cloneMethod: CloneMethod;\n        changes: any;\n        _fullTextSearch: FullTextSearch;\n    }\n    interface CheckIndexOptions {\n        randomSampling?: boolean;\n        randomSamplingFactor?: number;\n        repair?: boolean;\n    }\n    type Transform<T extends object = object> = {\n        type: \"find\";\n        value: ResultSet.Query<Doc<T>> | string;\n    } | {\n        type: \"where\";\n        value: ((obj: Doc<T>) => boolean) | string;\n    } | {\n        type: \"simplesort\";\n        property: keyof T;\n        options?: boolean | ResultSet.SimpleSortOptions;\n    } | {\n        type: \"compoundsort\";\n        value: (keyof T | [keyof T, boolean])[];\n    } | {\n        type: \"sort\";\n        value: (a: Doc<T>, b: Doc<T>) => number;\n    } | {\n        type: \"sortByScoring\";\n        desc?: boolean;\n    } | {\n        type: \"limit\";\n        value: number;\n    } | {\n        type: \"offset\";\n        value: number;\n    } | {\n        type: \"map\";\n        value: (obj: Doc<T>, index: number, array: Doc<T>[]) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"eqJoin\";\n        joinData: Collection<any> | ResultSet<any>;\n        leftJoinKey: string | ((obj: any) => string);\n        rightJoinKey: string | ((obj: any) => string);\n        mapFun?: (left: any, right: any) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"mapReduce\";\n        mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => any;\n        reduceFunction: (array: any[]) => any;\n    } | {\n        type: \"update\";\n        value: (obj: Doc<T>) => any;\n    } | {\n        type: \"remove\";\n    };\n    interface TTL {\n        age: number;\n        ttlInterval: number;\n        daemon: any;\n    }\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/loki/src/comparators.d.ts",
    "content": "export interface ILokiComparer<T> {\n    (a: T, b: T): -1 | 0 | 1;\n}\nexport interface IComparatorMap {\n    [name: string]: ILokiComparer<any>;\n}\n/** Map/Register of named ILokiComparer functions returning -1, 0, 1 for lt/eq/gt assertions for two passed parameters */\nexport declare let ComparatorMap: IComparatorMap;\n/** Typescript-friendly factory for strongly typed 'js' comparators */\nexport declare function CreateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'abstract js' comparators */\nexport declare function CreateAbstractJavascriptComparator<T>(): ILokiComparer<T>;\n/**\n * Comparator which attempts to deal with deal with dates at comparator level.\n * Should work for dates in any of the object, string, and number formats\n */\nexport declare function CreateAbstractDateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'loki' comparators */\nexport declare function CreateLokiComparator(): ILokiComparer<any>;\n"
  },
  {
    "path": "dist/packages/fs-storage/types/loki/src/dynamic_view.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { ResultSet } from \"./result_set\";\nimport { Collection } from \"./collection\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\n/**\n * DynamicView class is a versatile 'live' view class which can have filters and sorts applied.\n *    Collection.addDynamicView(name) instantiates this DynamicView object and notifies it\n *    whenever documents are add/updated/removed so it can remain up-to-date. (chainable)\n *\n * @example\n * let mydv = mycollection.addDynamicView('test');  // default is non-persistent\n * mydv.applyFind({ 'doors' : 4 });\n * mydv.applyWhere(function(obj) { return obj.name === 'Toyota'; });\n * let results = mydv.data();\n *\n * @extends LokiEventEmitter\n\n * @see {@link Collection#addDynamicView} to construct instances of DynamicView\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class DynamicView<T extends object = object> extends LokiEventEmitter {\n    readonly name: string;\n    private _collection;\n    private _persistent;\n    private _sortPriority;\n    private _minRebuildInterval;\n    private _rebuildPending;\n    private _resultSet;\n    private _resultData;\n    private _resultDirty;\n    private _cachedResultSet;\n    private _filterPipeline;\n    private _sortFunction;\n    private _sortCriteria;\n    private _sortCriteriaSimple;\n    private _sortByScoring;\n    private _sortDirty;\n    /**\n     * Constructor.\n     * @param {Collection} collection - a reference to the collection to work agains\n     * @param {string} name - the name of this dynamic view\n     * @param {object} options - the options\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=\"passive\"] - the sort priority\n     * @param {number} [options.minRebuildInterval=1] - minimum rebuild interval (need clarification to docs here)\n     */\n    constructor(collection: Collection<T>, name: string, options?: DynamicView.Options);\n    /**\n     * Internally used immediately after deserialization (loading)\n     *    This will clear out and reapply filterPipeline ops, recreating the view.\n     *    Since where filters do not persist correctly, this method allows\n     *    restoring the view to state where user can re-apply those where filters.\n     *\n     * @param removeWhereFilters\n     * @returns {DynamicView} This dynamic view for further chained ops.\n     * @fires DynamicView.rebuild\n     */\n    private _rematerialize({removeWhereFilters});\n    /**\n     * Makes a copy of the internal ResultSet for branched queries.\n     * Unlike this dynamic view, the branched ResultSet will not be 'live' updated,\n     * so your branched query should be immediately resolved and not held for future evaluation.\n     * @param {(string|array=)} transform - Optional name of collection transform, or an array of transform steps\n     * @param {object} parameters - optional parameters (if optional transform requires them)\n     * @returns {ResultSet} A copy of the internal ResultSet for branched queries.\n     */\n    branchResultSet(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Override of toJSON to avoid circular references.\n     */\n    toJSON(): DynamicView.Serialized;\n    static fromJSONObject(collection: Collection, obj: DynamicView.Serialized): DynamicView;\n    /**\n     * Used to clear pipeline and reset dynamic view to initial state.\n     * Existing options should be retained.\n     * @param {boolean} queueSortPhase - (default: false) if true we will async rebuild view (maybe set default to true in future?)\n     */\n    removeFilters({queueSortPhase}?: {\n        queueSortPhase?: boolean;\n    }): void;\n    /**\n     * Used to apply a sort to the dynamic view\n     * @example\n     * dv.applySort(function(obj1, obj2) {\n       *   if (obj1.name === obj2.name) return 0;\n       *   if (obj1.name > obj2.name) return 1;\n       *   if (obj1.name < obj2.name) return -1;\n       * });\n     * @param {function} comparefun - a javascript compare function used for sorting\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applySort(comparefun: (lhs: Doc<T>, rhs: Doc<T>) => number): this;\n    /**\n     * Used to specify a property used for view translation.\n     * @param {string} field - the field name\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether we should sort descending.\n     * @param {boolean} [options.disableIndexIntersect=false] - whether we should explicity not use array intersection.\n     * @param {boolean} [options.forceIndexIntersect=false] - force array intersection (if binary index exists).\n     * @param {boolean} [options.useJavascriptSorting=false] - whether results are sorted via basic javascript sort.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     * @example\n     * dv.applySimpleSort(\"name\");\n     */\n    applySimpleSort(field: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @param {Array} criteria - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {DynamicView} Reference to this DynamicView, sorted, for future chain operations.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * dv.applySortCriteria(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * dv.applySortCriteria(['age', ['name', true]]);\n     * // to sort by age (descending) and then by name (descending)\n     * dv.applySortCriteria([['age', true], ['name', true]]);\n     */\n    applySortCriteria(criteria: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Used to apply a sort by the latest full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     */\n    applySortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Marks the beginning of a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    startTransaction(): this;\n    /**\n     * Commits a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    commit(): this;\n    /**\n     * Rolls back a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    rollback(): this;\n    /**\n     * Find the index of a filter in the pipeline, by that filter's ID.\n     * @param {(string|number)} uid - The unique ID of the filter.\n     * @returns {number}: index of the referenced filter in the pipeline; -1 if not found.\n     */\n    private _indexOfFilterWithId(uid);\n    /**\n     * Add the filter object to the end of view's filter pipeline and apply the filter to the ResultSet.\n     * @param {object} filter - The filter object. Refer to applyFilter() for extra details.\n     */\n    private _addFilter(filter);\n    /**\n     * Reapply all the filters in the current pipeline.\n     *\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    reapplyFilters(): this;\n    /**\n     * Adds or updates a filter in the DynamicView filter pipeline\n     * @param {object} filter - A filter object to add to the pipeline.\n     *    The object is in the format { 'type': filter_type, 'val', filter_param, 'uid', optional_filter_id }\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFilter(filter: DynamicView.Filter<T>): this;\n    /**\n     * applyFind() - Adds or updates a mongo-style query option in the DynamicView filter pipeline\n     *\n     * @param {object} query - A mongo-style query object to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFind(query: object, uid?: string | number): this;\n    /**\n     * Adds or updates a javascript filter function in the DynamicView filter pipeline\n     * @param {function} fun - A javascript filter function to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyWhere(fun: (obj: Doc<T>) => boolean, uid?: string | number): this;\n    /**\n     * Remove the specified filter from the DynamicView filter pipeline\n     * @param {(string|number)} uid - The unique ID of the filter to be removed.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    removeFilter(uid: string | number): this;\n    /**\n     * Returns the number of documents representing the current DynamicView contents.\n     * @returns {number} The number of documents representing the current DynamicView contents.\n     */\n    count(): number;\n    /**\n     * Resolves and pending filtering and sorting, then returns document array as result.\n     * @param {object} options - optional parameters to pass to ResultSet.data() if non-persistent\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values include 'parse-stringify', 'jquery-extend-deep', 'shallow', 'shallow-assign'\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} An array of documents representing the current DynamicView contents.\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * When the view is not sorted we may still wish to be notified of rebuild events.\n     * This event will throttle and queue a single rebuild event when batches of updates affect the view.\n     */\n    private _queueRebuildEvent();\n    /**\n     * If the view is sorted we will throttle sorting to either :\n     * (1) passive - when the user calls data(), or\n     * (2) active - once they stop updating and yield js thread control\n     */\n    private _queueSortPhase();\n    /**\n     * Invoked synchronously or asynchronously to perform final sort phase (if needed)\n     */\n    private _performSortPhase(options?);\n    /**\n     * (Re)evaluating document inclusion.\n     * Called by : collection.insert() and collection.update().\n     * @param {int} objIndex - index of document to (re)run through filter pipeline.\n     * @param {boolean} isNew - true if the document was just added to the collection.\n     * @hidden\n     */\n    _evaluateDocument(objIndex: number, isNew: boolean): void;\n    /**\n     * Internal function called on collection.delete().\n     * @hidden\n     */\n    _removeDocument(objIndex: number): void;\n    /**\n     * Data transformation via user supplied functions\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: T, index: number, array: T[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n}\nexport declare namespace DynamicView {\n    interface Options {\n        persistent?: boolean;\n        sortPriority?: SortPriority;\n        minRebuildInterval?: number;\n    }\n    type SortPriority = \"passive\" | \"active\";\n    interface Serialized {\n        name: string;\n        _persistent: boolean;\n        _sortPriority: SortPriority;\n        _minRebuildInterval: number;\n        _resultSet: ResultSet<any>;\n        _filterPipeline: Filter<any>[];\n        _sortCriteria: (string | [string, boolean])[];\n        _sortCriteriaSimple: {\n            field: string;\n            options: boolean | ResultSet.SimpleSortOptions;\n        };\n        _sortByScoring: boolean;\n        _sortDirty: boolean;\n    }\n    type Filter<T extends object = object> = {\n        type: \"find\";\n        val: ResultSet.Query<Doc<T>>;\n        uid: number | string;\n    } | {\n        type: \"where\";\n        val: (obj: Doc<T>) => boolean;\n        uid: number | string;\n    };\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/loki/src/event_emitter.d.ts",
    "content": "/**\n * LokiEventEmitter is a minimalist version of EventEmitter. It enables any\n * constructor that inherits EventEmitter to emit events and trigger\n * listeners that have been added to the event through the on(event, callback) method\n *\n * @constructor LokiEventEmitter\n */\nexport declare class LokiEventEmitter {\n    /**\n     * A map, with each property being an array of callbacks.\n     */\n    protected _events: object;\n    /**\n     * Determines whether or not the callbacks associated with each event should happen in an async fashion or not.\n     * Default is false, which means events are synchronous\n     */\n    protected _asyncListeners: boolean;\n    /**\n     * Adds a listener to the queue of callbacks associated to an event\n     * @param {string|string[]} eventName - the name(s) of the event(s) to listen to\n     * @param {function} listener - callback function of listener to attach\n     * @returns {int} the index of the callback in the array of listeners for a particular event\n     */\n    on(eventName: string | string[], listener: Function): Function;\n    /**\n     * Emits a particular event\n     * with the option of passing optional parameters which are going to be processed by the callback\n     * provided signatures match (i.e. if passing emit(event, arg0, arg1) the listener should take two parameters)\n     * @param {string} eventName - the name of the event\n     * @param {object} data - optional object passed with the event\n     */\n    protected emit(eventName: string, ...data: any[]): void;\n    /**\n     * Alias of EventEmitter.on().\n     */\n    addListener(eventName: string | string[], listener: Function): Function;\n    /**\n     * Removes the listener at position 'index' from the event 'eventName'\n     * @param {string|string[]} eventName - the name(s) of the event(s) which the listener is attached to\n     * @param {function} listener - the listener callback function to remove from emitter\n     */\n    removeListener(eventName: string | string[], listener: Function): void;\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/loki/src/index.d.ts",
    "content": "import { Loki } from \"./loki\";\nimport { Collection } from \"./collection\";\nexport { Loki, Collection };\nexport default Loki;\n"
  },
  {
    "path": "dist/packages/fs-storage/types/loki/src/loki.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { Collection } from \"./collection\";\nimport { Doc, StorageAdapter } from \"../../common/types\";\nimport { IComparatorMap } from \"./comparators\";\nimport { IRangedIndexFactoryMap } from \"./ranged_indexes\";\nimport { ILokiOperatorPackageMap } from \"./operator_packages\";\nexport declare class Loki extends LokiEventEmitter {\n    filename: string;\n    private databaseVersion;\n    private engineVersion;\n    _collections: Collection[];\n    private _env;\n    private _serializationMethod;\n    private _destructureDelimiter;\n    private _persistenceMethod;\n    private _persistenceAdapter;\n    private _throttledSaves;\n    private _throttledSaveRunning;\n    private _throttledSavePending;\n    private _autosave;\n    private _autosaveInterval;\n    private _autosaveRunning;\n    private _autosaveHandler;\n    /**\n     * Constructs the main database class.\n     * @param {string} filename - name of the file to be saved to\n     * @param {object} [options={}] - options\n     * @param {Loki.Environment} [options.env] - the javascript environment\n     * @param {Loki.SerializationMethod} [options.serializationMethod=NORMAL] - the serialization method\n     * @param {string} [options.destructureDelimiter=\"$<\\n\"] - string delimiter used for destructured serialization\n     * @param {IComparatorMap} [options.comparatorMap] allows injecting or overriding registered comparators\n     * @param {IRangedIndexFactoryMap} [options.rangedIndexFactoryMap] allows injecting or overriding registered ranged index factories\n     * @param {ILokiOperatorPackageMap} [options.lokiOperatorPackageMap] allows injecting or overriding registered loki operator packages\n     */\n    constructor(filename?: string, options?: Loki.Options);\n    /**\n     * configures options related to database persistence.\n     *\n     * @param {Loki.PersistenceOptions} [options={}] - options\n     * @param {adapter} [options.adapter=auto] - an instance of a loki persistence adapter\n     * @param {boolean} [options.autosave=false] - enables autosave\n     * @param {int} [options.autosaveInterval=5000] - time interval (in milliseconds) between saves (if dirty)\n     * @param {boolean} [options.autoload=false] - enables autoload on loki instantiation\n     * @param {object} options.inflate - options that are passed to loadDatabase if autoload enabled\n     * @param {boolean} [options.throttledSaves=true] - if true, it batches multiple calls to to saveDatabase reducing number of\n     *   disk I/O operations and guaranteeing proper serialization of the calls. Default value is true.\n     * @param {Loki.PersistenceMethod} options.persistenceMethod - a persistence method which should be used (FS_STORAGE, LOCAL_STORAGE...)\n     * @returns {Promise} a Promise that resolves after initialization and (if enabled) autoloading the database\n     */\n    initializePersistence(options?: Loki.PersistenceOptions): Promise<void>;\n    /**\n     * Copies 'this' database into a new Loki instance. Object references are shared to make lightweight.\n     * @param {object} options - options\n     * @param {boolean} options.removeNonSerializable - nulls properties not safe for serialization.\n     */\n    copy(options?: Loki.CopyOptions): Loki;\n    /**\n     * Adds a collection to the database.\n     * @param {string} name - name of collection to add\n     * @param {object} [options={}] - options to configure collection with.\n     * @param {array} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {array} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {array} [options.indices=[]] - array property names to define binary indexes for\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are called asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes Api\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {string} [options.cloneMethod=CloneMethod.DEEP] - the clone method\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @returns {Collection} a reference to the collection which was just added\n     */\n    addCollection<TData extends object = object, TNested extends object = object>(name: string, options?: Collection.Options<TData, TNested>): Collection<TData, TNested>;\n    loadCollection(collection: Collection): void;\n    /**\n     * Retrieves reference to a collection by name.\n     * @param {string} name - name of collection to look up\n     * @returns {Collection} Reference to collection in database by that name, or null if not found\n     */\n    getCollection<TData extends object = object, TNested extends object = object>(name: string): Collection<TData, TNested>;\n    /**\n     * Renames an existing loki collection\n     * @param {string} oldName - name of collection to rename\n     * @param {string} newName - new name of collection\n     * @returns {Collection} reference to the newly renamed collection\n     */\n    renameCollection<TData extends object = object, TNested extends object = object>(oldName: string, newName: string): Collection<TData, TNested>;\n    listCollections(): {\n        name: string;\n        count: number;\n    }[];\n    /**\n     * Removes a collection from the database.\n     * @param {string} collectionName - name of collection to remove\n     */\n    removeCollection(collectionName: string): void;\n    /**\n     * Serialize database to a string which can be loaded via {@link Loki#loadJSON}\n     *\n     * @returns {string} Stringified representation of the loki database.\n     */\n    serialize(options?: Loki.SerializeOptions): string | string[];\n    toJSON(): Loki.Serialized;\n    /**\n     * Database level destructured JSON serialization routine to allow alternate serialization methods.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {object} options - output format options for use externally to loki\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to only output an individual collection or db (-1)\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {string|Array} A custom, restructured aggregation of independent serializations.\n     */\n    serializeDestructured(options?: Loki.SerializeDestructuredOptions): string | string[];\n    /**\n     * Collection level utility method to serialize a collection in a 'destructured' format\n     *\n     * @param {object} options - used to determine output of method\n     * @param {int} options.delimited - whether to return single delimited string or an array\n     * @param {string} options.delimiter - (optional) if delimited, this is delimiter to use\n     * @param {int} options.collectionIndex -  specify which collection to serialize data for\n     *\n     * @returns {string|array} A custom, restructured aggregation of independent serializations for a single collection.\n     */\n    serializeCollection(options?: {\n        delimited?: boolean;\n        collectionIndex?: number;\n        delimiter?: string;\n    }): string | string[];\n    /**\n     * Database level destructured JSON deserialization routine to minimize memory overhead.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {string|array} destructuredSource - destructured json or array to deserialize from\n     * @param {object} options - source format options\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to deserialize only a single partition\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {object|array} An object representation of the deserialized database, not yet applied to 'this' db or document array\n     */\n    deserializeDestructured(destructuredSource: string | string[], options?: Loki.SerializeDestructuredOptions): any;\n    /**\n     * Collection level utility function to deserializes a destructured collection.\n     *\n     * @param {string|string[]} destructuredSource - destructured representation of collection to inflate\n     * @param {object} options - used to describe format of destructuredSource input\n     * @param {int} [options.delimited=false] - whether source is delimited string or an array\n     * @param {string} options.delimiter - if delimited, this is delimiter to use (if other than default)\n     *\n     * @returns {Array} an array of documents to attach to collection.data.\n     */\n    deserializeCollection<T extends object = object>(destructuredSource: string | string[], options?: Loki.DeserializeCollectionOptions): Doc<T>[];\n    /**\n     * Inflates a loki database from a serialized JSON string\n     *\n     * @param {string} serializedDb - a serialized loki database string\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSON(serializedDb: string | string[], options?: Collection.DeserializeOptions): void;\n    /**\n     * Inflates a loki database from a JS object\n     *\n     * @param {object} dbObject - a serialized loki database object\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSONObject(dbObject: Loki, options?: Collection.DeserializeOptions): void;\n    loadJSONObject(dbObject: Loki.Serialized, options?: Collection.DeserializeOptions): void;\n    /**\n     * Emits the close event. In autosave scenarios, if the database is dirty, this will save and disable timer.\n     * Does not actually destroy the db.\n     *\n     * @returns {Promise} a Promise that resolves after closing the database succeeded\n     */\n    close(): Promise<void>;\n    /**-------------------------+\n     | Changes API               |\n     +--------------------------*/\n    /**\n     * The Changes API enables the tracking the changes occurred in the collections since the beginning of the session,\n     * so it's possible to create a differential dataset for synchronization purposes (possibly to a remote db)\n     */\n    /**\n     * (Changes API) : takes all the changes stored in each\n     * collection and creates a single array for the entire database. If an array of names\n     * of collections is passed then only the included collections will be tracked.\n     *\n     * @param {Array} [arrayOfCollectionNames=] - array of collection names. No arg means all collections are processed.\n     * @returns {Array} array of changes\n     * @see private method _createChange() in Collection\n     */\n    generateChangesNotification(arrayOfCollectionNames?: string[]): Collection.Change[];\n    /**\n     * (Changes API) - stringify changes for network transmission\n     * @returns {string} string representation of the changes\n     */\n    serializeChanges(collectionNamesArray?: string[]): string;\n    /**\n     * (Changes API) : clears all the changes in all collections.\n     */\n    clearChanges(): void;\n    /**\n     * Wait for throttledSaves to complete and invoke your callback when drained or duration is met.\n     *\n     * @param {object} options - configuration options\n     * @param {boolean} [options.recursiveWait=true] - if after queue is drained, another save was kicked off, wait for it\n     * @param {boolean} [options.recursiveWaitLimit=false] - limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDuration=2000] - cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves when save queue is drained, it is passed a sucess parameter value\n     */\n    throttledSaveDrain(options?: Loki.ThrottledDrainOptions): Promise<void>;\n    /**\n     * Internal load logic, decoupled from throttling/contention logic\n     *\n     * @param {object} options - an object containing inflation options for each collection\n     * @param {boolean} ignore_not_found - does not raise an error if database is not found\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    private _loadDatabase(options?, ignore_not_found?);\n    /**\n     * Handles manually loading from an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *    To avoid contention with any throttledSaves, we will drain the save queue first.\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @param {object} [options={}] - if throttling saves and loads, this controls how we drain save queue before loading\n     * @param {boolean} [options.recursiveWait=true] wait recursively until no saves are queued\n     * @param {boolean} [options.recursiveWaitLimit=false] limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDelay=2000] cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    loadDatabase(options?: Loki.LoadDatabaseOptions): Promise<void>;\n    private _saveDatabase();\n    /**\n     * Handles manually saving to an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @returns {Promise} a Promise that resolves after the database is persisted\n     */\n    saveDatabase(): Promise<void>;\n    /**\n     * Handles deleting a database from the underlying storage adapter\n     *\n     * @returns {Promise} a Promise that resolves after the database is deleted\n     */\n    deleteDatabase(): Promise<void>;\n    /****************\n     * Autosave API\n     ****************/\n    /**\n     * Check whether any collections are \"dirty\" meaning we need to save the (entire) database\n     * @returns {boolean} - true if database has changed since last autosave, otherwise false\n     */\n    private _autosaveDirty();\n    /**\n     * Resets dirty flags on all collections.\n     */\n    private _autosaveClearFlags();\n    /**\n     * Starts periodically saves to the underlying storage adapter.\n     */\n    private _autosaveEnable();\n    /**\n     * Stops the autosave interval timer.\n     */\n    private _autosaveDisable();\n}\nexport declare namespace Loki {\n    interface Options {\n        env?: Environment;\n        serializationMethod?: SerializationMethod;\n        destructureDelimiter?: string;\n        comparatorMap?: IComparatorMap;\n        rangedIndexFactoryMap?: IRangedIndexFactoryMap;\n        lokiOperatorPackageMap?: ILokiOperatorPackageMap;\n    }\n    interface PersistenceOptions {\n        adapter?: StorageAdapter;\n        autosave?: boolean;\n        autosaveInterval?: number;\n        autoload?: boolean;\n        throttledSaves?: boolean;\n        persistenceMethod?: Loki.PersistenceMethod;\n        inflate?: any;\n    }\n    interface CopyOptions {\n        removeNonSerializable?: boolean;\n    }\n    interface SerializeOptions {\n        serializationMethod?: SerializationMethod;\n    }\n    interface SerializeDestructuredOptions {\n        partitioned?: boolean;\n        partition?: number;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface DeserializeCollectionOptions {\n        partitioned?: boolean;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface ThrottledDrainOptions {\n        recursiveWait?: boolean;\n        recursiveWaitLimit?: boolean;\n        recursiveWaitLimitDuration?: number;\n        started?: Date;\n    }\n    interface Serialized {\n        _env: Environment;\n        _serializationMethod: SerializationMethod;\n        _autosave: boolean;\n        _autosaveInterval: number;\n        _collections: Collection[];\n        databaseVersion: number;\n        engineVersion: number;\n        filename: string;\n        _persistenceAdapter: StorageAdapter;\n        _persistenceMethod: PersistenceMethod;\n        _throttledSaves: boolean;\n    }\n    type LoadDatabaseOptions = Collection.DeserializeOptions & ThrottledDrainOptions;\n    type SerializationMethod = \"normal\" | \"pretty\" | \"destructured\";\n    type PersistenceMethod = \"fs-storage\" | \"local-storage\" | \"indexed-storage\" | \"memory-storage\" | \"adapter\";\n    type Environment = \"NATIVESCRIPT\" | \"NODEJS\" | \"CORDOVA\" | \"BROWSER\" | \"MEMORY\";\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/loki/src/operator_packages.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\n/** Hash interface for named LokiOperatorPackage registration */\nexport interface ILokiOperatorPackageMap {\n    [name: string]: LokiOperatorPackage;\n}\n/**\n * Helper function for determining 'loki' abstract equality which is a little more abstract than ==\n *     aeqHelper(5, '5') === true\n *     aeqHelper(5.0, '5') === true\n *     aeqHelper(new Date(\"1/1/2011\"), new Date(\"1/1/2011\")) === true\n *     aeqHelper({a:1}, {z:4}) === true (all objects sorted equally)\n *     aeqHelper([1, 2, 3], [1, 3]) === false\n *     aeqHelper([1, 2, 3], [1, 2, 3]) === true\n *     aeqHelper(undefined, null) === true\n * @param {any} prop1\n * @param {any} prop2\n * @returns {boolean}\n * @hidden\n */\nexport declare function aeqHelper(prop1: any, prop2: any): boolean;\n/**\n * Helper function for determining 'less-than' conditions for ops, sorting, and binary indices.\n *     In the future we might want $lt and $gt ops to use their own functionality/helper.\n *     Since binary indices on a property might need to index [12, NaN, new Date(), Infinity], we\n *     need this function (as well as gtHelper) to always ensure one value is LT, GT, or EQ to another.\n * @hidden\n */\nexport declare function ltHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @hidden\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} equal\n * @returns {boolean}\n */\nexport declare function gtHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} descending\n * @returns {number}\n * @hidden\n */\nexport declare function sortHelper(prop1: any, prop2: any, descending: boolean): number;\n/**\n * Default implementation of LokiOperatorPackage, using fastest javascript comparison operators.\n */\nexport declare class LokiOperatorPackage {\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n    $in(a: any, b: any): boolean;\n    $nin(a: any, b: any): boolean;\n    $keyin(a: string, b: object): boolean;\n    $nkeyin(a: string, b: object): boolean;\n    $definedin(a: string, b: object): boolean;\n    $undefinedin(a: string, b: object): boolean;\n    $regex(a: string, b: RegExp): boolean;\n    $containsNone(a: any, b: any): boolean;\n    $containsAny(a: any, b: any): boolean;\n    $contains(a: any, b: any): boolean;\n    $type(a: any, b: any): boolean;\n    $finite(a: number, b: boolean): boolean;\n    $size(a: any, b: any): boolean;\n    $len(a: any, b: any): boolean;\n    $where(a: any, b: any): boolean;\n    $not(a: any, b: any): boolean;\n    $and(a: any, b: any): boolean;\n    $or(a: any, b: any): boolean;\n    private doQueryOp(val, op);\n    private containsCheckFn(a);\n}\n/**\n * LokiOperatorPackage which utilizes abstract 'loki' comparisons for basic relational equality op implementations.\n */\nexport declare class LokiAbstractOperatorPackage extends LokiOperatorPackage {\n    constructor();\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * LokiOperatorPackage which utilizes provided comparator for basic relational equality op implementations.\n */\nexport declare class ComparatorOperatorPackage<T> extends LokiOperatorPackage {\n    comparator: ILokiComparer<T>;\n    constructor(comparator: ILokiComparer<T>);\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * Map/Register of named LokiOperatorPackages which implement all unindexed query ops within 'find' query objects\n */\nexport declare let LokiOperatorPackageMap: ILokiOperatorPackageMap;\n"
  },
  {
    "path": "dist/packages/fs-storage/types/loki/src/ranged_indexes.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\nexport declare type RangedValueOperator = \"$gt\" | \"$gte\" | \"$lt\" | \"$lte\" | \"$eq\" | \"$neq\" | \"$between\";\nexport interface IRangedIndexRequest<T> {\n    op: RangedValueOperator;\n    val: T;\n    high?: T;\n}\n/** Defines interface which all loki ranged indexes need to implement */\nexport interface IRangedIndex<T> {\n    insert(id: number, val: T): void;\n    update(id: number, val: T): void;\n    remove(id: number): void;\n    restore(tree: any): void;\n    backup(): IRangedIndex<T>;\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    validateIndex(): boolean;\n}\n/** Hash Interface for global ranged index factory map*/\nexport interface IRangedIndexFactoryMap {\n    [name: string]: (name: string, comparator: ILokiComparer<any>) => IRangedIndex<any>;\n}\n/** Map/Register of named factory functions returning IRangedIndex instances */\nexport declare let RangedIndexFactoryMap: IRangedIndexFactoryMap;\n"
  },
  {
    "path": "dist/packages/fs-storage/types/loki/src/result_set.d.ts",
    "content": "import { Collection } from \"./collection\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\nimport { Query as FullTextSearchQuery } from \"../../full-text-search/src/query_types\";\n/**\n * ResultSet class allowing chainable queries.  Intended to be instanced internally.\n *    Collection.find(), Collection.where(), and Collection.chain() instantiate this.\n *\n * @example\n *    mycollection.chain()\n *      .find({ 'doors' : 4 })\n *      .where(function(obj) { return obj.name === 'Toyota' })\n *      .data();\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class ResultSet<T extends object = object> {\n    _collection: Collection<T>;\n    _filteredRows: number[];\n    _filterInitialized: boolean;\n    private _scoring;\n    /**\n     * Constructor.\n     * @param {Collection} collection - the collection which this ResultSet will query against\n     */\n    constructor(collection: Collection<T>);\n    /**\n     * Reset the ResultSet to its initial state.\n     * @returns {ResultSet} Reference to this ResultSet, for future chain operations.\n     */\n    reset(): this;\n    /**\n     * Override of toJSON to avoid circular references\n     */\n    toJSON(): ResultSet<T>;\n    /**\n     * Allows you to limit the number of documents passed to next chain operation.\n     * A ResultSet copy() is made to avoid altering original ResultSet.\n     * @param {int} qty - The number of documents to return.\n     * @returns {ResultSet} Returns a copy of the ResultSet, limited by qty, for subsequent chain ops.\n     */\n    limit(qty: number): this;\n    /**\n     * Used for skipping 'pos' number of documents in the ResultSet.\n     * @param {int} pos - Number of documents to skip; all preceding documents are filtered out.\n     * @returns {ResultSet} Returns a copy of the ResultSet, containing docs starting at 'pos' for subsequent chain ops.\n     */\n    offset(pos: number): this;\n    /**\n     * To support reuse of ResultSet in branched query situations.\n     * @returns {ResultSet} Returns a copy of the ResultSet (set) but the underlying document references will be the same.\n     */\n    copy(): ResultSet<T>;\n    /**\n     * Executes a named collection transform or raw array of transform steps against the ResultSet.\n     * @param {(string|array)} transform - name of collection transform or raw transform array\n     * @param {object} [parameters=] - object property hash of parameters, if the transform requires them.\n     * @returns {ResultSet} either (this) ResultSet or a clone of of this ResultSet (depending on steps)\n     */\n    transform(transform: string | Collection.Transform<T>[], parameters?: object): this;\n    /**\n     * User supplied compare function is provided two documents to compare. (chainable)\n     * @example\n     *    rslt.sort(function(obj1, obj2) {\n       *      if (obj1.name === obj2.name) return 0;\n       *      if (obj1.name > obj2.name) return 1;\n       *      if (obj1.name < obj2.name) return -1;\n       *    });\n     * @param {function} comparefun - A javascript compare function used for sorting.\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    sort(comparefun: (a: Doc<T>, b: Doc<T>) => number): this;\n    /**\n     * Simpler, loose evaluation for user to sort based on a property name. (chainable).\n     * Sorting based on the same lt/gt helper functions used for binary indices.\n     * @param {string} propname - name of property to sort by.\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether to sort descending\n     * @param {string} [options.sortComparator] override default with name of comparator registered in ComparatorMap\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    simplesort(propname: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * rs.compoundsort(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * rs.compoundsort(['age', ['name', true]);\n     * @param {array} properties - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    compoundsort(properties: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Helper function for compoundsort(), performing individual object comparisons\n     * @param {Array} properties - array of property names, in order, by which to evaluate sort order\n     * @param {object} obj1 - first object to compare\n     * @param {object} obj2 - second object to compare\n     * @returns {number} 0, -1, or 1 to designate if identical (sortwise) or which should be first\n     */\n    private _compoundeval(properties, obj1, obj2);\n    /**\n     * Sorts the ResultSet based on the last full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     * @returns {ResultSet}\n     */\n    sortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Oversee the operation of OR'ed query expressions.\n     * OR'ed expression evaluation runs each expression individually against the full collection,\n     * and finally does a set OR on each expression's results.\n     * Each evaluation can utilize a binary index to prevent multiple linear array scans.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findOr(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $or(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Oversee the operation of AND'ed query expressions.\n     * AND'ed expression evaluation runs each expression progressively against the full collection,\n     * internally utilizing existing chained ResultSet functionality.\n     * Only the first filter can utilize a binary index.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findAnd(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $and(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Used for querying via a mongo-style query object.\n     *\n     * @param {object} query - A mongo-style query object used for filtering current results.\n     * @param {boolean} firstOnly - (Optional) Used by collection.findOne() - flag if this was invoked via findOne()\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    find(query?: ResultSet.Query<Doc<T>>, firstOnly?: boolean): this;\n    /**\n     * Used for filtering via a javascript filter function.\n     * @param {function} fun - A javascript function used for filtering current results by.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    where(fun: (obj: Doc<T>) => boolean): this;\n    /**\n     * Returns the number of documents in the ResultSet.\n     * @returns {number} The number of documents in the ResultSet.\n     */\n    count(): number;\n    /**\n     * Terminates the chain and returns array of filtered documents\n     * @param {object} options\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values 'parse-stringify', 'deep', and 'shallow' and\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} Array of documents in the ResultSet\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * Used to run an update operation on all documents currently in the ResultSet.\n     * @param {function} updateFunction - User supplied updateFunction(obj) will be executed for each document object.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    update(updateFunction: (obj: Doc<T>) => Doc<T>): this;\n    /**\n     * Removes all document objects which are currently in ResultSet from collection (as well as ResultSet)\n     * @returns {ResultSet} this (empty) ResultSet for further chain ops.\n     */\n    remove(): this;\n    /**\n     * data transformation via user supplied functions\n     *\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns {value} The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Left joining two sets of data. Join keys can be defined or calculated properties\n     * eqJoin expects the right join key values to be unique.  Otherwise left data will be joined on the last joinData object with that key\n     * @param {Array|ResultSet|Collection} joinData - Data array to join to.\n     * @param {(string|function)} leftJoinKey - Property name in this result set to join on or a function to produce a value to join on\n     * @param {(string|function)} rightJoinKey - Property name in the joinData to join on or a function to produce a value to join on\n     * @param {function} [mapFun=] - a function that receives each matching pair and maps them into output objects - function(left,right){return joinedObject}\n     * @param {object} [dataOptions=] - optional options to apply to data() calls for left and right sides\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} A ResultSet with data in the format [{left: leftObj, right: rightObj}]\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinKey: string | ((obj: any) => string), rightJoinKey: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * Applies a map function into a new collection for further chaining.\n     * @param {function} mapFun - javascript map function\n     * @param {object} [dataOptions=] - options to data() before input to your map function\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - Allows overriding the default or collection specified cloning method\n     * @return {ResultSet}\n     */\n    map<U extends object>(mapFun: (obj: Doc<T>, index: number, array: Doc<T>[]) => U, dataOptions?: ResultSet.DataOptions): ResultSet<U>;\n}\nexport declare namespace ResultSet {\n    interface DataOptions {\n        forceClones?: boolean;\n        forceCloneMethod?: CloneMethod;\n        removeMeta?: boolean;\n    }\n    interface SimpleSortOptions {\n        desc?: boolean;\n        sortComparator?: string;\n    }\n    type ContainsHelperType<R> = R extends string ? string | string[] : R extends any[] ? R[number] | R[number][] : R extends object ? keyof R | (keyof R)[] : never;\n    type LokiOps<R> = {\n        $eq?: R;\n    } | {\n        $ne?: R;\n    } | {\n        $gt?: R;\n    } | {\n        $gte?: R;\n    } | {\n        $lt?: R;\n    } | {\n        $lte?: R;\n    } | {\n        $between?: [R, R];\n    } | {\n        $in?: R[];\n    } | {\n        $nin?: R[];\n    } | {\n        $keyin?: object;\n    } | {\n        $nkeyin?: object;\n    } | {\n        $definedin?: object;\n    } | {\n        $undefinedin?: object;\n    } | {\n        $regex?: RegExp | string | [string, string];\n    } | {\n        $containsNone?: ContainsHelperType<R>;\n    } | {\n        $containsAny?: ContainsHelperType<R>;\n    } | {\n        $contains?: ContainsHelperType<R>;\n    } | {\n        $type?: string;\n    } | {\n        $finite?: boolean;\n    } | {\n        $size?: number;\n    } | {\n        $len?: number;\n    } | {\n        $where?: (val?: R) => boolean;\n    };\n    type Query<T> = {\n        [P in keyof T]?: LokiOps<T[P]> | T[P];\n    } & {\n        $and?: Query<T>[];\n    } & {\n        $or?: Query<T>[];\n    } & {\n        $fts?: FullTextSearchQuery;\n    };\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/loki/src/unique_index.d.ts",
    "content": "export declare class UniqueIndex {\n    private _field;\n    private _lokiMap;\n    private _valMap;\n    /**\n     * Constructs an unique index object.\n     * @param {string} propertyField - the property field to index\n     */\n    constructor(propertyField: string);\n    /**\n     * Sets a document's unique index.\n     * @param {number} id loki id to associate with value\n     * @param {*} value  value to associate with id\n     */\n    set(id: number, value: any): void;\n    /**\n     * Returns the $loki id of an unique value.\n     * @param {*} value the value to retrieve a loki id match for\n     */\n    get(value: any): number;\n    /**\n     * Updates a document's unique index.\n     * @param {number} id (loki) id of document to update the value to\n     * @param {*} value value to associate with loki id\n     */\n    update(id: number, value: any): void;\n    /**\n     * Removes an unique index.\n     * @param {number} id (loki) id to remove from index\n     */\n    remove(id: number): void;\n    /**\n     * Clears the unique index.\n     */\n    clear(): void;\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/memory-storage/src/index.d.ts",
    "content": "import { MemoryStorage } from \"./memory_storage\";\nexport { MemoryStorage };\nexport default MemoryStorage;\n"
  },
  {
    "path": "dist/packages/fs-storage/types/memory-storage/src/memory_storage.d.ts",
    "content": "import { Dict, StorageAdapter } from \"../../common/types\";\n/**\n * An in-memory persistence adapter for an in-memory database.\n * This simple 'key/value' adapter is intended for unit testing and diagnostics.\n */\nexport declare class MemoryStorage implements StorageAdapter {\n    hashStore: Dict<{\n        savecount: number;\n        lastsave: Date;\n        value: string;\n    }>;\n    options: MemoryStorage.Options;\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} options - memory storage options\n     * @param {boolean} [options.asyncResponses=false] - whether callbacks are invoked asynchronously (default: false)\n     * @param {int} [options.asyncTimeout=50] - timeout in ms to queue callbacks (default: 50)\n     */\n    constructor(options?: MemoryStorage.Options);\n    /**\n     * Loads a serialized database from its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * Saves a serialized database to its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {string} dbstring - the database content\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a database from its in-memory store.\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport declare namespace MemoryStorage {\n    interface Options {\n        asyncResponses?: boolean;\n        asyncTimeout?: number;\n    }\n}\n"
  },
  {
    "path": "dist/packages/fs-storage/types/partitioning-adapter/src/index.d.ts",
    "content": "import { PartitioningAdapter } from \"./partitioning_adapter\";\nexport { PartitioningAdapter };\nexport default PartitioningAdapter;\n"
  },
  {
    "path": "dist/packages/fs-storage/types/partitioning-adapter/src/partitioning_adapter.d.ts",
    "content": "import { Loki } from \"../../loki/src/loki\";\nimport { StorageAdapter } from \"../../common/types\";\n/**\n * An adapter for adapters. Converts a non reference mode adapter into a reference mode adapter\n * which can perform destructuring and partitioning. Each collection will be stored in its own key/save and\n * only dirty collections will be saved. If you  turn on paging with default page size of 25megs and save\n * a 75 meg collection it should use up roughly 3 save slots (key/value pairs sent to inner adapter).\n * A dirty collection that spans three pages will save all three pages again\n * Paging mode was added mainly because Chrome has issues saving 'too large' of a string within a\n * single IndexedDB row. If a single document update causes the collection to be flagged as dirty, all\n * of that collection's pages will be written on next save.\n */\nexport declare class PartitioningAdapter implements StorageAdapter {\n    mode: string;\n    private _adapter;\n    private _dbref;\n    private _dbname;\n    private _pageIterator;\n    private _paging;\n    private _pageSize;\n    private _delimiter;\n    private _dirtyPartitions;\n    /**\n     * Registers the partitioning adapter as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the partitioning storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} adapter - reference to a 'non-reference' mode loki adapter instance.\n     * @param {boolean} paging - (default: false) set to true to enable paging collection data.\n     * @param {number} pageSize - (default : 25MB) you can use this to limit size of strings passed to inner adapter.\n     * @param {string} delimiter - allows you to override the default delimiter\n     */\n    constructor(adapter: StorageAdapter, {paging, pageSize, delimiter}?: {\n        paging?: boolean;\n        pageSize?: number;\n        delimiter?: string;\n    });\n    /**\n     * Loads a database which was partitioned into several key/value saves.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Used to sequentially load each collection partition, one at a time.\n     *\n     * @param {int} partition - ordinal collection position to load next\n     * @returns {Promise} a Promise that resolves after the next partition is loaded\n     */\n    private _loadNextPartition(partition);\n    /**\n     * Used to sequentially load the next page of collection partition, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next page is loaded\n     */\n    private _loadNextPage();\n    /**\n     * Saves a database by partioning into separate key/value saves.\n     * (Loki 'reference mode' persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {object} dbref - reference to database which we will partition and save.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     *\n     */\n    exportDatabase(dbname: string, dbref: Loki): Promise<void>;\n    /**\n     * Helper method used internally to save each dirty collection, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPartition();\n    /**\n     * Helper method used internally to generate and save the next page of the current (dirty) partition.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPage();\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/lokidb.full-text-search.js",
    "content": "(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"@lokidb/full-text-search\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"@lokidb/full-text-search\"] = factory();\n\telse\n\t\t{ root[\"@lokidb/full-text-search\"] = factory(); root[\"LokiFullTextSearch\"] = root[\"@lokidb/full-text-search\"].default; }\n})(typeof self !== 'undefined' ? self : this, function() {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// define __esModule on exports\n/******/ \t__webpack_require__.r = function(exports) {\n/******/ \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n/******/ \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n/******/ \t\t}\n/******/ \t\tObject.defineProperty(exports, '__esModule', { value: true });\n/******/ \t};\n/******/\n/******/ \t// create a fake namespace object\n/******/ \t// mode & 1: value is a module id, require it\n/******/ \t// mode & 2: merge all properties of value into the ns\n/******/ \t// mode & 4: return value when already ns object\n/******/ \t// mode & 8|1: behave like require\n/******/ \t__webpack_require__.t = function(value, mode) {\n/******/ \t\tif(mode & 1) value = __webpack_require__(value);\n/******/ \t\tif(mode & 8) return value;\n/******/ \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n/******/ \t\tvar ns = Object.create(null);\n/******/ \t\t__webpack_require__.r(ns);\n/******/ \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n/******/ \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n/******/ \t\treturn ns;\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 1);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return PLUGINS; });\nfunction getGlobal() {\n    let glob;\n    (function (global) {\n        glob = global;\n    })(global !== undefined && global || this);\n    return glob;\n}\nfunction create() {\n    const global = getGlobal();\n    const sym = Symbol.for(\"LOKI\");\n    if (global[sym] === undefined) {\n        global[sym] = {};\n    }\n    return global[sym];\n}\n/**\n * @hidden\n */\nconst PLUGINS = create();\n\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(2)))\n\n/***/ }),\n/* 1 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n\n// CONCATENATED MODULE: ./packages/full-text-search/src/analyzer/tokenizer.ts\n/**\n * Splits a string at whitespace characters into tokens.\n * @param {string} value - the string\n * @returns {string[]} - the tokens\n */\nfunction whitespaceTokenizer(value) {\n    return value.split(/[\\s]+/);\n}\n\n// CONCATENATED MODULE: ./packages/full-text-search/src/analyzer/token_filter.ts\n/**\n * Converts a token to lowercase.\n * @param {string} token - the token\n * @returns {string} - the lowercased token\n */\nfunction lowercaseTokenFilter(token) {\n    return token.toLowerCase();\n}\n/**\n * Converts a token to uppercase.\n * @param {string} token - the token\n * @returns {string} - the uppercased token\n */\nfunction uppercaseTokenFilter(token) {\n    return token.toUpperCase();\n}\n\n// CONCATENATED MODULE: ./packages/full-text-search/src/analyzer/analyzer.ts\n\n\n/**\n * Analyzes a given string.\n * @param {Analyzer} analyzer - the analyzer\n * @param {string} str - the string\n * @returns {string[]} - the tokens\n */\nfunction analyze(analyzer, str) {\n    if (analyzer.char_filter) {\n        for (let j = 0; j < analyzer.char_filter.length; j++) {\n            str = analyzer.char_filter[j](str);\n        }\n    }\n    const tokens = analyzer.tokenizer(str);\n    if (analyzer.token_filter) {\n        for (let i = 0; i < tokens.length; i++) {\n            for (let k = 0; k < analyzer.token_filter.length; k++) {\n                tokens[i] = analyzer.token_filter[k](tokens[i], i, tokens);\n            }\n        }\n    }\n    // Remove empty tokens.\n    return tokens.filter((token) => token);\n}\n/**\n * An analyzer with the whitespace tokenizer and the lowercase token filter.\n */\nclass analyzer_StandardAnalyzer {\n    constructor() {\n        this.tokenizer = whitespaceTokenizer;\n        this.token_filter = [lowercaseTokenFilter];\n    }\n}\n\n// CONCATENATED MODULE: ./packages/full-text-search/src/inverted_index.ts\n\n/**\n * Converts a string into an array of code points.\n * @param str - the string\n * @returns {number[]} to code points\n * @hidden\n */\nfunction toCodePoints(str) {\n    const r = [];\n    for (let i = 0; i < str.length;) {\n        const chr = str.charCodeAt(i++);\n        if (chr >= 0xD800 && chr <= 0xDBFF) {\n            // surrogate pair\n            const low = str.charCodeAt(i++);\n            r.push(0x10000 + ((chr - 0xD800) << 10) | (low - 0xDC00));\n        }\n        else {\n            // ordinary character\n            r.push(chr);\n        }\n    }\n    return r;\n}\n/**\n * Inverted index class handles featured text search for specific document fields.\n * @hidden\n */\nclass inverted_index_InvertedIndex {\n    /**\n     * @param {boolean} [options.store=true] - inverted index will be stored at serialization rather than rebuilt on load\n     * @param {boolean} [options.optimizeChanges=true] - flag to store additional metadata inside the index for better\n     *  performance if an existing field is updated or removed\n     * @param {Analyzer} [options.analyzer=] - the analyzer of this inverted index\n     */\n    constructor(options = {}) {\n        this.docCount = 0;\n        this.docStore = new Map();\n        this.totalFieldLength = 0;\n        this.root = new Map();\n        ({\n            store: this._store = true,\n            optimizeChanges: this._optimizeChanges = true,\n            analyzer: this.analyzer = new analyzer_StandardAnalyzer()\n        } = options);\n    }\n    /**\n     * Adds defined fields of a document to the inverted index.\n     * @param {string} field - the field to add\n     * @param {number} docId - the doc id of the field\n     */\n    insert(field, docId) {\n        if (this.docStore.has(docId)) {\n            throw Error(\"Field already added.\");\n        }\n        // Tokenize document field.\n        const fieldTokens = analyze(this.analyzer, field);\n        if (fieldTokens.length == 0) {\n            // Add empty field at least to document store for query 'exists'.\n            this.docStore.set(docId, { fieldLength: 0 });\n            return;\n        }\n        this.totalFieldLength += fieldTokens.length;\n        this.docCount += 1;\n        this.docStore.set(docId, { fieldLength: fieldTokens.length });\n        // Holds references to each index of a document.\n        const indexRef = [];\n        if (this._optimizeChanges) {\n            Object.defineProperties(this.docStore.get(docId), {\n                indexRef: { enumerable: false, configurable: true, writable: true, value: indexRef }\n            });\n        }\n        // Iterate over all unique field terms.\n        for (const token of new Set(fieldTokens)) {\n            // Calculate term frequency.\n            let tf = 0;\n            for (let j = 0; j < fieldTokens.length; j++) {\n                if (fieldTokens[j] === token) {\n                    ++tf;\n                }\n            }\n            // Add term to index tree.\n            let branch = this.root;\n            for (const c of toCodePoints(token)) {\n                let child = branch.get(c);\n                if (child === undefined) {\n                    child = new Map();\n                    if (this._optimizeChanges) {\n                        child.pa = branch;\n                    }\n                    branch.set(c, child);\n                }\n                branch = child;\n            }\n            // Add term info to index leaf.\n            if (branch.dc === undefined) {\n                branch.dc = new Map();\n                branch.df = 0;\n            }\n            branch.dc.set(docId, tf);\n            branch.df += 1;\n            // Store index leaf for deletion.\n            indexRef.push(branch);\n        }\n    }\n    /**\n     * Removes all relevant terms of a document from the inverted index.\n     * @param {number} docId - the document.\n     */\n    remove(docId) {\n        if (!this.docStore.has(docId)) {\n            return;\n        }\n        const docStore = this.docStore.get(docId);\n        // Remove document.\n        this.docStore.delete(docId);\n        if (docStore.fieldLength === 0) {\n            return;\n        }\n        this.docCount -= 1;\n        // Reduce total field length.\n        this.totalFieldLength -= docStore.fieldLength;\n        if (this._optimizeChanges) {\n            // Iterate over all term references.\n            // Remove docId from docs and decrement document frequency.\n            const indexRef = docStore.indexRef;\n            for (let j = 0; j < indexRef.length; j++) {\n                let index = indexRef[j];\n                index.df -= 1;\n                index.dc.delete(docId);\n                // Check if no document is left for current tree.\n                if (index.df === 0) {\n                    // Delete unused meta data of branch.\n                    delete index.df;\n                    delete index.dc;\n                    // Check for sub branches.\n                    if (index.size !== 0) {\n                        continue;\n                    }\n                    // Delete term branch if not used anymore.\n                    do {\n                        // Go tree upwards.\n                        const parent = index.pa;\n                        // Delete parent reference for preventing memory leak (cycle reference).\n                        delete index.pa;\n                        // Iterate over all children.\n                        for (const key of parent.keys()) {\n                            // Remove previous child form parent.\n                            if (parent.get(key) === index) {\n                                parent.delete(key);\n                                break;\n                            }\n                        }\n                        index = parent;\n                    } while (index.pa !== undefined && index.size === 0 && index.df === undefined);\n                }\n            }\n        }\n        else {\n            this._remove(this.root, docId);\n        }\n    }\n    /**\n     * Gets the term index of a term.\n     * @param {string} term - the term\n     * @param {object} root - the term index to start from\n     * @param {number} start - the position of the term string to start from\n     * @return {object} - The term index or null if the term is not in the term tree.\n     */\n    static getTermIndex(term, root, start = 0) {\n        if (start >= term.length) {\n            return null;\n        }\n        for (let i = start; i < term.length; i++) {\n            let child = root.get(term[i]);\n            if (child === undefined) {\n                return null;\n            }\n            root = child;\n        }\n        return root;\n    }\n    /**\n     * Extends a term index to all available term leafs.\n     * @param {object} idx - the term index to start from\n     * @param {number[]} [term=[]] - the current term\n     * @param {Array} termIndices - all extended indices with their term\n     * @returns {Array} - Array with term indices and extension\n     */\n    static extendTermIndex(idx, term = [], termIndices = []) {\n        if (idx.df !== undefined) {\n            termIndices.push({ index: idx, term: term.slice() });\n        }\n        term.push(0);\n        for (const child of idx) {\n            term[term.length - 1] = child[0];\n            inverted_index_InvertedIndex.extendTermIndex(child[1], term, termIndices);\n        }\n        term.pop();\n        return termIndices;\n    }\n    /**\n     * Serialize the inverted index.\n     * @returns {{docStore: *, _fields: *, index: *}}\n     */\n    toJSON() {\n        if (this._store) {\n            return {\n                _store: true,\n                _optimizeChanges: this._optimizeChanges,\n                docCount: this.docCount,\n                docStore: [...this.docStore],\n                totalFieldLength: this.totalFieldLength,\n                root: inverted_index_InvertedIndex._serializeIndex(this.root)\n            };\n        }\n        return {\n            _store: false,\n            _optimizeChanges: this._optimizeChanges,\n        };\n    }\n    /**\n     * Deserialize the inverted index.\n     * @param {{docStore: *, _fields: *, index: *}} serialized - The serialized inverted index.\n     * @param {Analyzer} analyzer[undefined] - an analyzer\n     */\n    static fromJSONObject(serialized, analyzer) {\n        const invIdx = new inverted_index_InvertedIndex({\n            store: serialized._store,\n            optimizeChanges: serialized._optimizeChanges,\n            analyzer: analyzer\n        });\n        if (serialized._store) {\n            invIdx.docCount = serialized.docCount;\n            invIdx.docStore = new Map(serialized.docStore);\n            invIdx.totalFieldLength = serialized.totalFieldLength;\n            invIdx.root = inverted_index_InvertedIndex._deserializeIndex(serialized.root);\n        }\n        if (invIdx._optimizeChanges) {\n            invIdx._regenerate(invIdx.root, null);\n        }\n        return invIdx;\n    }\n    static _serializeIndex(idx) {\n        const serialized = {};\n        if (idx.dc !== undefined) {\n            serialized.d = { df: idx.df, dc: [...idx.dc] };\n        }\n        if (idx.size === 0) {\n            return serialized;\n        }\n        const keys = [];\n        const values = [];\n        for (const child of idx) {\n            keys.push(child[0]);\n            values.push(inverted_index_InvertedIndex._serializeIndex(child[1]));\n        }\n        serialized.k = keys;\n        serialized.v = values;\n        return serialized;\n    }\n    static _deserializeIndex(serialized) {\n        const idx = new Map();\n        if (serialized.k !== undefined) {\n            for (let i = 0; i < serialized.k.length; i++) {\n                idx.set(serialized.k[i], inverted_index_InvertedIndex._deserializeIndex(serialized.v[i]));\n            }\n        }\n        if (serialized.d !== undefined) {\n            idx.df = serialized.d.df;\n            idx.dc = new Map(serialized.d.dc);\n        }\n        return idx;\n    }\n    /**\n     * Set parent of to each index and regenerate the indexRef.\n     * @param {Index} index - the index\n     * @param {Index} parent - the parent\n     */\n    _regenerate(index, parent) {\n        // Set parent.\n        if (parent !== null) {\n            index.pa = parent;\n        }\n        // Iterate over subtree.\n        for (const child of index.values()) {\n            this._regenerate(child, index);\n        }\n        if (index.dc !== undefined) {\n            // Get documents of term.\n            for (const docId of index.dc.keys()) {\n                // Get document store at specific document/field.\n                const ref = this.docStore.get(docId);\n                if (ref.indexRef === undefined) {\n                    Object.defineProperties(ref, {\n                        indexRef: { enumerable: false, configurable: true, writable: true, value: [] }\n                    });\n                }\n                // Set reference to term index.\n                ref.indexRef.push(index);\n            }\n        }\n    }\n    /**\n     * Iterate over the whole inverted index and remove the document.\n     * Delete branch if not needed anymore.\n     * Function is needed if index is used without optimization.\n     * @param {Index} idx - the index\n     * @param {number} docId - the doc id\n     * @returns {boolean} true if index is empty\n     */\n    _remove(idx, docId) {\n        for (const child of idx) {\n            // Checkout branch.\n            if (this._remove(child[1], docId)) {\n                idx.delete(child[0]);\n            }\n        }\n        // Remove docId from docs and decrement document frequency.\n        if (idx.df !== undefined) {\n            if (idx.dc.has(docId)) {\n                idx.df -= 1;\n                idx.dc.delete(docId);\n                // Delete unused meta data of branch.\n                if (idx.df === 0) {\n                    delete idx.df;\n                    delete idx.dc;\n                }\n            }\n        }\n        return idx.size === 0 && idx.dc === undefined;\n    }\n}\n\n// CONCATENATED MODULE: ./packages/full-text-search/src/scorer.ts\n/**\n * @hidden\n */\nclass Scorer {\n    constructor(invIdxs) {\n        this._cache = {};\n        this._invIdxs = invIdxs;\n    }\n    setDirty() {\n        this._cache = {};\n    }\n    score(fieldName, boost, termIdx, doScoring, queryResults, term, df = 0) {\n        if (termIdx === null || termIdx.dc === undefined) {\n            return;\n        }\n        const idf = this._idf(fieldName, df || termIdx.df);\n        for (const [docId, tf] of termIdx.dc) {\n            if (!queryResults.has(docId)) {\n                queryResults.set(docId, []);\n            }\n            if (doScoring === true) {\n                // BM25 scoring.\n                queryResults.get(docId).push({ tf, idf, boost, fieldName, term });\n            }\n            else if (doScoring === false) {\n                // Constant scoring.\n                queryResults.set(docId, [{ boost }]);\n            }\n            else {\n                // Zero scoring.\n                queryResults.set(docId, [{ boost: 0 }]);\n            }\n        }\n    }\n    scoreConstant(boost, docId, queryResults) {\n        if (!queryResults.has(docId)) {\n            queryResults.set(docId, []);\n        }\n        queryResults.get(docId).push({ boost });\n        return queryResults;\n    }\n    finalScore(query, queryResults) {\n        const finalResult = {};\n        const k1 = query.bm25 !== undefined ? query.bm25.k1 : 1.2;\n        const b = query.bm25 !== undefined ? query.bm25.b : 0.75;\n        const explain = query.explain !== undefined ? query.explain : false;\n        for (const [docId, result] of queryResults) {\n            let docScore = 0;\n            let docExplanation = [];\n            for (let i = 0; i < result.length; i++) {\n                const queryResult = result[i];\n                let score = 0;\n                if (queryResult.tf !== undefined) {\n                    // BM25 scoring.\n                    const tf = queryResult.tf;\n                    const fieldLength = Scorer._calculateFieldLength(this._invIdxs[queryResult.fieldName].docStore.get(docId)\n                        .fieldLength);\n                    const avgFieldLength = this._avgFieldLength(queryResult.fieldName);\n                    const tfNorm = (tf * (k1 + 1)) / (tf + k1 * (1 - b + b * (fieldLength / avgFieldLength)));\n                    score = queryResult.idf * tfNorm * queryResult.boost;\n                    if (explain) {\n                        docExplanation.push({\n                            boost: queryResult.boost,\n                            score: score,\n                            docID: docId,\n                            fieldName: queryResult.fieldName,\n                            index: String.fromCharCode(...queryResult.term),\n                            idf: queryResult.idf,\n                            tfNorm: tfNorm,\n                            tf: tf,\n                            fieldLength: fieldLength,\n                            avgFieldLength: avgFieldLength,\n                        });\n                    }\n                }\n                else {\n                    // Constant scoring.\n                    score = queryResult.boost;\n                    if (explain) {\n                        docExplanation.push({\n                            boost: queryResult.boost,\n                            score: score\n                        });\n                    }\n                }\n                docScore += score;\n            }\n            if (explain) {\n                finalResult[docId] = {\n                    score: docScore,\n                    explanation: docExplanation\n                };\n            }\n            else {\n                finalResult[docId] = {\n                    score: docScore\n                };\n            }\n        }\n        return finalResult;\n    }\n    static _calculateFieldLength(fieldLength) {\n        // Dummy function to be compatible to lucene in unit tests.\n        return fieldLength;\n    }\n    _getCache(fieldName) {\n        if (this._cache[fieldName] === undefined) {\n            const avgFieldLength = this._invIdxs[fieldName].totalFieldLength / this._invIdxs[fieldName].docCount;\n            this._cache[fieldName] = { idfs: {}, avgFieldLength };\n        }\n        return this._cache[fieldName];\n    }\n    /**\n     * Returns the idf by either calculate it or use a cached one.\n     * @param {string} fieldName - the name of the field\n     * @param {number} docFreq - the doc frequency of the term\n     * @returns {number} the idf\n     * @private\n     */\n    _idf(fieldName, docFreq) {\n        const cache = this._getCache(fieldName);\n        if (cache.idfs[docFreq] !== undefined) {\n            return cache.idfs[docFreq];\n        }\n        return cache.idfs[docFreq] = Math.log(1 + (this._invIdxs[fieldName].docCount - docFreq + 0.5) / (docFreq + 0.5));\n    }\n    _avgFieldLength(fieldName) {\n        return this._getCache(fieldName).avgFieldLength;\n    }\n}\n\n// CONCATENATED MODULE: ./packages/full-text-search/src/fuzzy/run_automaton.ts\n/**\n * From org/apache/lucene/util/automaton/RunAutomaton.java\n * @hidden\n */\nclass RunAutomaton {\n    constructor(automaton) {\n        const size = automaton.getNumStates();\n        this._points = automaton.getStartPoints();\n        this._accept = new Array(size);\n        this._transitions = new Array(size * this._points.length);\n        for (let n = 0; n < size; n++) {\n            this._accept[n] = automaton.isAccept(n);\n            for (let c = 0; c < this._points.length; c++) {\n                // assert dest === -1 || dest < size;\n                this._transitions[n * this._points.length + c] = automaton.step(n, this._points[c]);\n            }\n        }\n        this._classmap = new Array(256 /* alphaSize */);\n        for (let i = 0, j = 0; j < this._classmap.length; j++) {\n            if (i + 1 < this._points.length && j === this._points[i + 1]) {\n                i++;\n            }\n            this._classmap[j] = i;\n        }\n    }\n    getCharClass(c) {\n        // binary search\n        let a = 0;\n        let b = this._points.length;\n        while (b - a > 1) {\n            const d = (a + b) >>> 1;\n            if (this._points[d] > c) {\n                b = d;\n            }\n            else if (this._points[d] < c) {\n                a = d;\n            }\n            else {\n                return d;\n            }\n        }\n        return a;\n    }\n    step(state, c) {\n        if (c >= this._classmap.length) {\n            return this._transitions[state * this._points.length + this.getCharClass(c)];\n        }\n        else {\n            return this._transitions[state * this._points.length + this._classmap[c]];\n        }\n    }\n    isAccept(state) {\n        return this._accept[state];\n    }\n}\n\n// CONCATENATED MODULE: ./packages/full-text-search/src/fuzzy/automaton.ts\n/**\n * @type {number}\n * @hidden\n */\nconst MIN_CODE_POINT = 0;\n/**\n * @type {number}\n * @hidden\n */\nconst MAX_CODE_POINT = 1114111;\nfunction sortByDestMinMax(a, b) {\n    if (a[0] < b[0]) {\n        return -1;\n    }\n    else if (a[0] > b[0]) {\n        return 1;\n    }\n    if (a[1] < b[1]) {\n        return -1;\n    }\n    else if (a[1] > b[1]) {\n        return 1;\n    }\n    if (a[2] < b[2]) {\n        return -1;\n    }\n    else if (a[2] > b[2]) {\n        return 1;\n    }\n    return 0;\n}\nfunction sortByMinMaxDest(a, b) {\n    if (a[1] < b[1]) {\n        return -1;\n    }\n    else if (a[1] > b[1]) {\n        return 1;\n    }\n    if (a[2] < b[2]) {\n        return -1;\n    }\n    else if (a[2] > b[2]) {\n        return 1;\n    }\n    if (a[0] < b[0]) {\n        return -1;\n    }\n    else if (a[0] > b[0]) {\n        return 1;\n    }\n    return 0;\n}\n/**\n * From org/apache/lucene/util/automaton/Automaton.java\n * @hidden\n */\nclass Automaton {\n    constructor() {\n        this._stateTransitions = [];\n        this._stateTransitions = [];\n        this._accept = new Set();\n        this._nextState = 0;\n        this._currState = -1;\n        // this.deterministic = true;\n        this._transitions = {};\n    }\n    isAccept(n) {\n        return this._accept.has(n);\n    }\n    createState() {\n        return this._nextState++;\n    }\n    setAccept(state, accept) {\n        if (accept) {\n            this._accept.add(state);\n        }\n        else {\n            this._accept.delete(state);\n        }\n    }\n    finishState() {\n        if (this._currState !== -1) {\n            this._finishCurrentState();\n            this._currState = -1;\n        }\n    }\n    _finishCurrentState() {\n        // Sort all transitions.\n        this._stateTransitions.sort(sortByDestMinMax);\n        let upto = 0;\n        let p = [-1, -1, -1];\n        for (let i = 0, len = this._stateTransitions.length; i < len; i++) {\n            let t = this._stateTransitions[i];\n            if (p[0] === t[0]) {\n                if (t[1] <= p[2] + 1) {\n                    if (t[2] > p[2]) {\n                        p[2] = t[2];\n                    }\n                }\n                else {\n                    if (p[0] !== -1) {\n                        this._stateTransitions[upto][0] = p[0];\n                        this._stateTransitions[upto][1] = p[1];\n                        this._stateTransitions[upto][2] = p[2];\n                        upto++;\n                    }\n                    p[1] = t[1];\n                    p[2] = t[2];\n                }\n            }\n            else {\n                if (p[0] !== -1) {\n                    this._stateTransitions[upto][0] = p[0];\n                    this._stateTransitions[upto][1] = p[1];\n                    this._stateTransitions[upto][2] = p[2];\n                    upto++;\n                }\n                p[0] = t[0];\n                p[1] = t[1];\n                p[2] = t[2];\n            }\n        }\n        if (p[0] !== -1) {\n            // Last transition\n            this._stateTransitions[upto][0] = p[0];\n            this._stateTransitions[upto][1] = p[1];\n            this._stateTransitions[upto][2] = p[2];\n            upto++;\n        }\n        this._transitions[this._currState] = this._stateTransitions.slice(0, upto).sort(sortByMinMaxDest);\n        // if (this.deterministic && upto > 1) {\n        //   let lastMax = this.stateTransitions[0][2];\n        //   for (let i = 1; i < upto; i++) {\n        //     let min = this.stateTransitions[i][1];\n        //     if (min <= lastMax) {\n        //       this.deterministic = false;\n        //       break;\n        //     }\n        //     lastMax = this.stateTransitions[i][2];\n        //   }\n        // }\n        this._stateTransitions = [];\n    }\n    getStartPoints() {\n        const pointset = new Set();\n        pointset.add(MIN_CODE_POINT);\n        const states = Object.keys(this._transitions);\n        for (let i = 0; i < states.length; i++) {\n            let trans = this._transitions[states[i]];\n            for (let j = 0; j < trans.length; j++) {\n                let tran = trans[j];\n                pointset.add(tran[1]);\n                if (tran[2] < MAX_CODE_POINT) {\n                    pointset.add(tran[2] + 1);\n                }\n            }\n        }\n        return Array.from(pointset).sort((a, b) => a - b);\n    }\n    step(state, label) {\n        let trans = this._transitions[state];\n        if (trans) {\n            for (let i = 0; i < trans.length; i++) {\n                let tran = trans[i];\n                if (tran[1] <= label && label <= tran[2]) {\n                    return tran[0];\n                }\n            }\n        }\n        return -1;\n    }\n    getNumStates() {\n        return this._nextState;\n    }\n    addTransition(source, dest, min, max) {\n        if (this._currState !== source) {\n            if (this._currState !== -1) {\n                this._finishCurrentState();\n            }\n            this._currState = source;\n        }\n        this._stateTransitions.push([dest, min, max]);\n    }\n}\n\n// CONCATENATED MODULE: ./packages/full-text-search/src/fuzzy/long.ts\n/**\n * Class supports 64Bit integer operations.\n * A cut-down version of dcodeIO/long.js.\n * @hidden\n */\nclass Long {\n    constructor(low = 0, high = 0) {\n        this._low = low;\n        this._high = high;\n    }\n    /**\n     * Returns this long with bits arithmetically shifted to the right by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftRight(numBits) {\n        if ((numBits &= 63) === 0)\n            return this;\n        else if (numBits < 32)\n            return new Long((this._low >>> numBits) | (this._high << (32 - numBits)), this._high >> numBits);\n        else\n            return new Long((this._high >> (numBits - 32)), this._high >= 0 ? 0 : -1);\n    }\n    /**\n     * Returns this long with bits arithmetically shifted to the left by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftLeft(numBits) {\n        if ((numBits &= 63) === 0)\n            return this;\n        else if (numBits < 32)\n            return new Long(this._low << numBits, (this._high << numBits) | (this._low >>> (32 - numBits)));\n        else\n            return new Long(0, this._low << (numBits - 32));\n    }\n    /**\n     * Returns the bitwise AND of this Long and the specified.\n     * @param {Long} other - the other Long\n     * @returns {Long} the long\n     */\n    and(other) {\n        return new Long(this._low & other._low, this._high & other._high);\n    }\n    /**\n     * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.\n     * @returns {number}\n     */\n    toInt() {\n        return this._low;\n    }\n}\n\n// CONCATENATED MODULE: ./packages/full-text-search/src/fuzzy/parametric_description.ts\n\nconst MASKS = [new Long(0x1), new Long(0x3), new Long(0x7), new Long(0xf),\n    new Long(0x1f), new Long(0x3f), new Long(0x7f), new Long(0xff),\n    new Long(0x1ff), new Long(0x3ff), new Long(0x7ff), new Long(0xfff),\n    new Long(0x1fff), new Long(0x3fff), new Long(0x7fff), new Long(0xffff),\n    new Long(0xf, 0x1fff), new Long(0xf, 0x3fff), new Long(0xf, 0x7fff), new Long(0xf, 0xffff),\n    new Long(0xff, 0x1fff), new Long(0xff, 0x3fff), new Long(0xff, 0x7fff), new Long(0xff, 0xffff),\n    new Long(0xfff, 0x1fff), new Long(0xfff, 0x3fff), new Long(0xfff, 0x7fff), new Long(0xfff, 0xffff),\n    new Long(0xffff, 0x1fff), new Long(0xffff, 0x3fff), new Long(0xffff, 0x7fff), new Long(0xffff, 0xffff),\n    new Long(0xfffff, 0x1fff), new Long(0xfffff, 0x3fff), new Long(0xfffff, 0x7fff), new Long(0xfffff, 0xffff),\n    new Long(0xffffff, 0x1fff), new Long(0xffffff, 0x3fff), new Long(0xffffff, 0x7fff), new Long(0xffffff, 0xffff),\n    new Long(0xfffffff, 0x1fff), new Long(0xfffffff, 0x3fff), new Long(0xfffffff, 0x7fff), new Long(0xfffffff, 0xffff),\n    new Long(0xffffffff, 0x1fff), new Long(0xffffffff, 0x3fff), new Long(0xffffffff, 0x7fff), new Long(0xffffffff, 0xffff),\n    new Long(0xfffffffff, 0x1fff), new Long(0xfffffffff, 0x3fff), new Long(0xfffffffff, 0x7fff), new Long(0xfffffffff, 0xffff),\n    new Long(0xffffffffff, 0x1fff), new Long(0xffffffffff, 0x3fff), new Long(0xffffffffff, 0x7fff), new Long(0xffffffffff, 0xffff),\n    new Long(0xfffffffffff, 0x1fff), new Long(0xfffffffffff, 0x3fff), new Long(0xfffffffffff, 0x7fff), new Long(0xfffffffffff, 0xffff),\n    new Long(0xffffffffffff, 0x1fff), new Long(0xffffffffffff, 0x3fff), new Long(0xffffffffffff, 0x7fff)];\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java#ParametricDescription\n * @hidden\n */\nclass ParametricDescription {\n    constructor(w, n, minErrors) {\n        this._w = w;\n        this._n = n;\n        this._minErrors = minErrors;\n    }\n    /**\n     * Return the number of states needed to compute a Levenshtein DFA\n     */\n    size() {\n        return this._minErrors.length * (this._w + 1);\n    }\n    /**\n     * Returns true if the <code>state</code> in any Levenshtein DFA is an accept state (final state).\n     */\n    isAccept(absState) {\n        // decode absState -> state, offset\n        let state = Math.floor(absState / (this._w + 1));\n        let offset = absState % (this._w + 1);\n        //assert offset >= 0;\n        return this._w - offset + this._minErrors[state] <= this._n;\n    }\n    /**\n     * Returns the position in the input word for a given <code>state</code>.\n     * This is the minimal boundary for the state.\n     */\n    getPosition(absState) {\n        return absState % (this._w + 1);\n    }\n    static unpack(data, index, bitsPerValue) {\n        const bitLoc = bitsPerValue * index;\n        const dataLoc = (bitLoc >> 6);\n        const bitStart = (bitLoc & 63);\n        if (bitStart + bitsPerValue <= 64) {\n            // not split\n            return data[dataLoc].shiftRight(bitStart).and(MASKS[bitsPerValue - 1]).toInt();\n        }\n        else {\n            // split\n            const part = 64 - bitStart;\n            return (data[dataLoc].shiftRight(bitStart).and(MASKS[part - 1])).toInt()\n                + (data[1 + dataLoc].and(MASKS[bitsPerValue - part - 1]).shiftLeft(part)).toInt();\n        }\n    }\n}\n\n// CONCATENATED MODULE: ./packages/full-text-search/src/fuzzy/lev1t_parametric_description.ts\n\n\n// 1 vectors; 2 states per vector; array length = 2\nconst toStates0 = [new Long(0x2)];\nconst offsetIncrs0 = [new Long(0x0)];\n// 2 vectors; 3 states per vector; array length = 6\nconst toStates1 = [new Long(0xa43)];\nconst offsetIncrs1 = [new Long(0x38)];\n// 4 vectors; 6 states per vector; array length = 24\nconst toStates2 = [new Long(0x82140003, 0x34534914), new Long(0x6d)];\nconst offsetIncrs2 = [new Long(0x55a20000, 0x5555)];\n// 8 vectors; 6 states per vector; array length = 48\nconst toStates3 = [new Long(0x900C0003, 0x21520854), new Long(0x4534916d, 0x5b4d19a2), new Long(0xda34)];\nconst offsetIncrs3 = [new Long(0x20fc0000, 0x5555ae0a), new Long(0x55555555)];\n// state map\n//   0 -> [(0, 0)]\n//   1 -> [(0, 1)]\n//   2 -> [(0, 1), (1, 1)]\n//   3 -> [(0, 1), (2, 1)]\n//   4 -> [t(0, 1), (0, 1), (1, 1), (2, 1)]\n//   5 -> [(0, 1), (1, 1), (2, 1)]\n/**\n * From org/apache/lucene/util/automaton/Lev1TParametricDescription.java\n * @hidden\n */\nclass lev1t_parametric_description_Lev1TParametricDescription extends ParametricDescription {\n    constructor(w) {\n        super(w, 1, [0, 1, 0, -1, -1, -1]);\n    }\n    transition(absState, position, vector) {\n        // null absState should never be passed in\n        //assert absState != -1;\n        // decode absState -> state, offset\n        let state = Math.floor(absState / (this._w + 1));\n        let offset = absState % (this._w + 1);\n        //assert offset >= 0;\n        if (position === this._w) {\n            if (state < 2) {\n                const loc = vector * 2 + state;\n                offset += ParametricDescription.unpack(offsetIncrs0, loc, 1);\n                state = ParametricDescription.unpack(toStates0, loc, 2) - 1;\n            }\n        }\n        else if (position === this._w - 1) {\n            if (state < 3) {\n                const loc = vector * 3 + state;\n                offset += ParametricDescription.unpack(offsetIncrs1, loc, 1);\n                state = ParametricDescription.unpack(toStates1, loc, 2) - 1;\n            }\n        }\n        else if (position === this._w - 2) {\n            if (state < 6) {\n                const loc = vector * 6 + state;\n                offset += ParametricDescription.unpack(offsetIncrs2, loc, 2);\n                state = ParametricDescription.unpack(toStates2, loc, 3) - 1;\n            }\n        }\n        else {\n            if (state < 6) {\n                const loc = vector * 6 + state;\n                offset += ParametricDescription.unpack(offsetIncrs3, loc, 2);\n                state = ParametricDescription.unpack(toStates3, loc, 3) - 1;\n            }\n        }\n        if (state === -1) {\n            // null state\n            return -1;\n        }\n        else {\n            // translate back to abs\n            return state * (this._w + 1) + offset;\n        }\n    }\n}\n\n// CONCATENATED MODULE: ./packages/full-text-search/src/fuzzy/lev2t_parametric_description.ts\n\n\n// 1 vectors; 3 states per vector; array length = 3\nconst lev2t_parametric_description_toStates0 = /*2 bits per value */ [\n    new Long(0x23)\n];\nconst lev2t_parametric_description_offsetIncrs0 = /*1 bits per value */ [\n    new Long(0x0)\n];\n// 2 vectors; 5 states per vector; array length = 10\nconst lev2t_parametric_description_toStates1 = /*3 bits per value */ [\n    new Long(0x13688b44)\n];\nconst lev2t_parametric_description_offsetIncrs1 = /*1 bits per value */ [\n    new Long(0x3e0)\n];\n// 4 vectors; 13 states per vector; array length = 52\nconst lev2t_parametric_description_toStates2 = /*4 bits per value */ [\n    new Long(0x5200b504, 0x60dbb0b0), new Long(0x27062227, 0x52332176), new Long(0x14323235, 0x23555432), new Long(0x4354)\n];\nconst lev2t_parametric_description_offsetIncrs2 = /*2 bits per value */ [\n    new Long(0x00002000, 0x555080a8), new Long(0x55555555, 0x55)\n];\n// 8 vectors; 28 states per vector; array length = 224\nconst lev2t_parametric_description_toStates3 = /*5 bits per value */ [\n    new Long(0x40059404, 0xe701c029), new Long(0x00a50000, 0xa0101620), new Long(0xa1416288, 0xb02c8c40), new Long(0x310858c0, 0xa821032),\n    new Long(0x0d28b201, 0x31442398), new Long(0x847788e0, 0x5281e528), new Long(0x08c2280e, 0xa23980d3), new Long(0xa962278c, 0x1e3294b1),\n    new Long(0x2288e528, 0x8c41309e), new Long(0x021aca21, 0x11444409), new Long(0x86b1086b, 0x11a46248), new Long(0x1d6240c4, 0x2a625894),\n    new Long(0x489074ad, 0x5024a50b), new Long(0x520c411a, 0x14821aca), new Long(0x0b594a44, 0x5888b589), new Long(0xc411a465, 0x941d6520),\n    new Long(0xad6a62d4, 0x8b589075), new Long(0x1a5055a4)\n];\nconst lev2t_parametric_description_offsetIncrs3 = /*2 bits per value */ [\n    new Long(0x00002000, 0x30c302), new Long(0xc3fc333c, 0x2a0030f3), new Long(0x8282a820, 0x233a0032), new Long(0x32b283a8, 0x55555555),\n    new Long(0x55555555, 0x55555555), new Long(0x55555555, 0x55555555), new Long(0x55555555, 0x55555555)\n];\n// 16 vectors; 45 states per vector; array length = 720\nconst toStates4 = /*6 bits per value */ [\n    new Long(0x002c5004, 0x3801450), new Long(0x00000e38, 0xc500014b), new Long(0x51401402, 0x514), new Long(0x0),\n    new Long(0x14010000, 0x518000b), new Long(0x28e20230, 0x9f1c208), new Long(0x830a70c2, 0x219f0df0), new Long(0x08208200, 0x82000082),\n    new Long(0x60800800, 0x8050501), new Long(0x02602643, 0x30820986), new Long(0x50508064, 0x45640142), new Long(0x20000831, 0x8500514),\n    new Long(0x85002082, 0x41405820), new Long(0x0990c201, 0x45618098), new Long(0x50a01051, 0x8316d0c), new Long(0x050df0e0, 0x21451420),\n    new Long(0x14508214, 0xd142140), new Long(0x50821c60, 0x3c21c018), new Long(0xcb142087, 0x1cb1403), new Long(0x1851822c, 0x80082145),\n    new Long(0x20800020, 0x200208), new Long(0x87180345, 0xd0061820), new Long(0x24976b09, 0xcb0a81cb), new Long(0x624709d1, 0x8b1a60e),\n    new Long(0x82249089, 0x2490820), new Long(0x00d2c024, 0xc31421c6), new Long(0x15454423, 0x3c314515), new Long(0xc21cb140, 0x31853c22),\n    new Long(0x2c208214, 0x4514500b), new Long(0x508b0051, 0x8718034), new Long(0x5108f0c5, 0xb2cb4551), new Long(0x1cb0a810, 0xe824715d),\n    new Long(0x908b0e60, 0x1422cb14), new Long(0xc02cb145, 0x30812c22), new Long(0x0cb1420c, 0x84202202), new Long(0x20ce0850, 0x5c20ce08),\n    new Long(0x8b0d70c2, 0x20820820), new Long(0x14214208, 0x42085082), new Long(0x50830c20, 0x9208340), new Long(0x13653592, 0xc6134dc6),\n    new Long(0x6dc4db4d, 0xd309341c), new Long(0x54d34d34, 0x6424d908), new Long(0x030814c2, 0x92072c22), new Long(0x24a30930, 0x4220724b),\n    new Long(0x25c920e2, 0x2470d720), new Long(0x975c9082, 0x92c92d70), new Long(0x04924e08, 0xcb0880c2), new Long(0xc24c2481, 0x45739728),\n    new Long(0xda6174da, 0xc6da4db5), new Long(0x5d30971d, 0x4b5d35d7), new Long(0x93825ce2, 0x1030815c), new Long(0x020cb145, 0x51442051),\n    new Long(0x2c220e2c, 0xc538210e), new Long(0x52cb0d70, 0x8514214), new Long(0x85145142, 0x204b0850), new Long(0x4051440c, 0x92156083),\n    new Long(0xa60e6595, 0x4d660e4d), new Long(0x1c6dc658, 0x94d914e4), new Long(0x1454d365, 0x82642659), new Long(0x51030813, 0x2892072c),\n    new Long(0xcb2ca30b, 0xe2c22072), new Long(0x20538910, 0x452c70d7), new Long(0x708e3891, 0x8b2cb2d), new Long(0xc204b24e, 0x81cb1440),\n    new Long(0x28c2ca24, 0xda44e38e), new Long(0x85d660e4, 0x1dc6da65), new Long(0x8e5d914e, 0xe2cb5d33), new Long(0x38938238)\n];\nconst offsetIncrs4 = /*3 bits per value */ [\n    new Long(0x00080000, 0x30020000), new Long(0x20c060), new Long(0x04000000, 0x81490000), new Long(0x10824824, 0x40249241),\n    new Long(0x60002082, 0xdb6030c3), new Long(0x301b0d80, 0x6c36c06c), new Long(0x000db0db, 0xb01861b0), new Long(0x9188e06d, 0x1b703620),\n    new Long(0x06d86db7, 0x8009200), new Long(0x02402490, 0x4920c24), new Long(0x08249009, 0x490002), new Long(0x28124804, 0x49081281),\n    new Long(0x124a44a2, 0x34800104), new Long(0x0d24020c, 0xc3093090), new Long(0x24c24d24, 0x40009a09), new Long(0x9201061a, 0x4984a06),\n    new Long(0x71269262, 0x494d0492), new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249),\n    new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924),\n    new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492),\n    new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249),\n    new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x2492)\n];\n// 32 vectors; 45 states per vector; array length = 1440\nconst toStates5 = /*6 bits per value */ [\n    new Long(0x002c5004, 0x3801450), new Long(0x00000e38, 0xc500014b), new Long(0x51401402, 0x514), new Long(0x0),\n    new Long(0x14010000, 0x514000b), new Long(0x038e00e0, 0x550000), new Long(0x0600b180, 0x26451850), new Long(0x08208208, 0x82082082),\n    new Long(0x40820820, 0x2c500), new Long(0x808c0146, 0x70820a38), new Long(0x9c30827c, 0xc37c20c2), new Long(0x20800867, 0x208208),\n    new Long(0x02002080, 0xb1401020), new Long(0x00518000, 0x828e2023), new Long(0x209f1c20, 0x830a70c), new Long(0x853df0df, 0x51451450),\n    new Long(0x14508214, 0x16142142), new Long(0x30805050, 0x60260264), new Long(0x43082098, 0x25050806), new Long(0x14564014, 0x42000083),\n    new Long(0x20850051, 0x8500208), new Long(0x14140582, 0x80990c20), new Long(0x08261809, 0x82019202), new Long(0x90060941, 0x8920519),\n    new Long(0xc22cb242, 0x22492492), new Long(0x0162492c, 0x43080505), new Long(0x86026026, 0x80414515), new Long(0xc5b43142, 0x37c38020),\n    new Long(0x14508014, 0x42085085), new Long(0x50850051, 0x1414058), new Long(0x980990c2, 0x51456180), new Long(0x0c50a010, 0xe008316d),\n    new Long(0x508b21f0, 0x2c52cb2c), new Long(0xc22cb249, 0x600d2c92), new Long(0x1850821c, 0x873c21c0), new Long(0x03cb1420, 0x2c01cb14),\n    new Long(0x45185182, 0x20800821), new Long(0x08208000, 0x45002002), new Long(0x20871803, 0x8700614), new Long(0x050821cf, 0x740500f5),\n    new Long(0x18609000, 0x934d9646), new Long(0x30824d30, 0x4c24d34d), new Long(0xc600d642, 0x1860821), new Long(0x25dac274, 0xc2a072c9),\n    new Long(0x91c27472, 0x2c698398), new Long(0x89242242, 0x92420820), new Long(0x34b00900, 0x82087180), new Long(0xb09d0061, 0x1cb24976),\n    new Long(0x9d1cb0a8, 0x60e62470), new Long(0x1574ce3e, 0xd31455d7), new Long(0x25c25d74, 0x1c600d38), new Long(0x423c3142, 0x51515454),\n    new Long(0x1403c314, 0xc22c21cb), new Long(0x21431853, 0xb2c208), new Long(0x05145145, 0x34508b0), new Long(0x0c508718, 0x5515108f),\n    new Long(0xf2051454, 0x8740500), new Long(0x0618f090, 0xe2534d92), new Long(0x6592c238, 0x49382659), new Long(0x21c600d6, 0x4423c314),\n    new Long(0xcb2d1545, 0x72c2a042), new Long(0xa091c574, 0x422c3983), new Long(0x508b2c52, 0xb2c514), new Long(0x8034b08b, 0xf0c50871),\n    new Long(0x45515108, 0xa810b2cb), new Long(0x715d1cb0, 0x2260e824), new Long(0x8e2d74ce, 0xe6592c53), new Long(0x38938238, 0x420c3081),\n    new Long(0x22020cb1, 0x8508420), new Long(0xce0820ce, 0x70c25c20), new Long(0x08208b0d, 0x42082082), new Long(0x50821421, 0xc204208),\n    new Long(0x832c5083, 0x21080880), new Long(0x0838c214, 0xa5083882), new Long(0xa9c39430, 0xaaaaaaaa), new Long(0x9fa9faaa, 0x1aaa7eaa),\n    new Long(0x1420c308, 0x824820d0), new Long(0x84d94d64, 0x7184d371), new Long(0x1b7136d3, 0x34c24d07), new Long(0x1534d34d, 0x99093642),\n    new Long(0x30c20530, 0x8340508), new Long(0x53592092, 0x34dc6136), new Long(0x4db4dc61, 0xa479c6dc), new Long(0x4924924a, 0x920a9f92),\n    new Long(0x8192a82a, 0x72c22030), new Long(0x30930920, 0x724b24a), new Long(0x920e2422, 0xd72025c), new Long(0xc9082247, 0x92d70975),\n    new Long(0x24e0892c, 0x880c2049), new Long(0xc2481cb0, 0x2c928c24), new Long(0x89088749, 0x80a52488), new Long(0xaac74394, 0x6a861b2a),\n    new Long(0xab27b278, 0x81b2ca6), new Long(0x072c2203, 0xa3093092), new Long(0x6915ce5c, 0xd76985d3), new Long(0x771b6936, 0x5d74c25c),\n    new Long(0x892d74d7, 0x724e0973), new Long(0x0880c205, 0x4c2481cb), new Long(0x739728c2, 0x6174da45), new Long(0xda4db5da, 0x4aa175c6),\n    new Long(0x86486186, 0x6a869b27), new Long(0x308186ca, 0xcb14510), new Long(0x44205102, 0x220e2c51), new Long(0x38210e2c, 0xcb0d70c5),\n    new Long(0x51421452, 0x14514208), new Long(0x4b085085, 0x51440c20), new Long(0x1440832c, 0xcb145108), new Long(0x488b0888, 0x94316208),\n    new Long(0x9f7e79c3, 0xfaaa7dfa), new Long(0x7ea7df7d, 0x30819ea), new Long(0x20d01451, 0x65648558), new Long(0x93698399, 0x96135983),\n    new Long(0x39071b71, 0xd9653645), new Long(0x96451534, 0x4e09909), new Long(0x051440c2, 0x21560834), new Long(0x60e65959, 0xd660e4da),\n    new Long(0xc6dc6584, 0x9207e979), new Long(0xdf924820, 0xa82a8207), new Long(0x103081a6, 0x892072c5), new Long(0xb2ca30b2, 0x2c22072c),\n    new Long(0x0538910e, 0x52c70d72), new Long(0x08e38914, 0x8b2cb2d7), new Long(0x204b24e0, 0x1cb1440c), new Long(0x8c2ca248, 0x874b2cb2),\n    new Long(0x24488b08, 0x43948162), new Long(0x9b1f7e77, 0x9e786aa6), new Long(0xeca6a9e7, 0x51030819), new Long(0x2892072c, 0x8e38a30b),\n    new Long(0x83936913, 0x69961759), new Long(0x4538771b, 0x74ce3976), new Long(0x08e38b2d, 0xc204e24e), new Long(0x81cb1440, 0x28c2ca24),\n    new Long(0xda44e38e, 0x85d660e4), new Long(0x75c6da65, 0x698607e9), new Long(0x99e7864a, 0xa6ca6aa6)\n];\nconst offsetIncrs5 = /*3 bits per value */ [\n    new Long(0x00080000, 0x30020000), new Long(0x20c060), new Long(0x04000000, 0x1000000), new Long(0x50603018, 0xdb6db6db),\n    new Long(0x00002db6, 0xa4800002), new Long(0x41241240, 0x12492088), new Long(0x00104120, 0x40000100), new Long(0x92092052, 0x2492c420),\n    new Long(0x096592d9, 0xc30d800), new Long(0xc36036d8, 0xb01b0c06), new Long(0x6c36db0d, 0x186c0003), new Long(0xb01b6c06, 0xad860361),\n    new Long(0x5b6dd6dd, 0x360001b7), new Long(0x0db6030c, 0xc412311c), new Long(0xb6e36e06, 0xdb0d), new Long(0xdb01861b, 0x9188e06),\n    new Long(0x71b72b62, 0x6dd6db), new Long(0x00800920, 0x40240249), new Long(0x904920c2, 0x20824900), new Long(0x40049000, 0x12012480),\n    new Long(0xa4906120, 0x5524ad4a), new Long(0x02480015, 0x40924020), new Long(0x48409409, 0x92522512), new Long(0x24000820, 0x49201001),\n    new Long(0x204a04a0, 0x29128924), new Long(0x00055549, 0x900830d2), new Long(0x24c24034, 0x934930c), new Long(0x02682493, 0x4186900),\n    new Long(0x61201a48, 0x9a498612), new Long(0x355249d4, 0xc348001), new Long(0x940d2402, 0x24c40930), new Long(0x0924e24d, 0x1a40009a),\n    new Long(0x06920106, 0x6204984a), new Long(0x92712692, 0x92494d54), new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924),\n    new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492),\n    new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249),\n    new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924),\n    new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492),\n    new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249),\n    new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924),\n    new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492),\n    new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492), new Long(0x24924924)\n];\n// state map\n//   0 -> [(0, 0)]\n//   1 -> [(0, 2)]\n//   2 -> [(0, 1)]\n//   3 -> [(0, 1), (1, 1)]\n//   4 -> [(0, 2), (1, 2)]\n//   5 -> [t(0, 2), (0, 2), (1, 2), (2, 2)]\n//   6 -> [(0, 2), (2, 1)]\n//   7 -> [(0, 1), (2, 2)]\n//   8 -> [(0, 2), (2, 2)]\n//   9 -> [(0, 1), (1, 1), (2, 1)]\n//   10 -> [(0, 2), (1, 2), (2, 2)]\n//   11 -> [(0, 1), (2, 1)]\n//   12 -> [t(0, 1), (0, 1), (1, 1), (2, 1)]\n//   13 -> [(0, 2), (1, 2), (2, 2), (3, 2)]\n//   14 -> [t(0, 2), (0, 2), (1, 2), (2, 2), (3, 2)]\n//   15 -> [(0, 2), t(1, 2), (1, 2), (2, 2), (3, 2)]\n//   16 -> [(0, 2), (2, 1), (3, 1)]\n//   17 -> [(0, 1), t(1, 2), (2, 2), (3, 2)]\n//   18 -> [(0, 2), (3, 2)]\n//   19 -> [(0, 2), (1, 2), t(1, 2), (2, 2), (3, 2)]\n//   20 -> [t(0, 2), (0, 2), (1, 2), (3, 1)]\n//   21 -> [(0, 1), (1, 1), (3, 2)]\n//   22 -> [(0, 2), (2, 2), (3, 2)]\n//   23 -> [(0, 2), (1, 2), (3, 1)]\n//   24 -> [(0, 2), (1, 2), (3, 2)]\n//   25 -> [(0, 1), (2, 2), (3, 2)]\n//   26 -> [(0, 2), (3, 1)]\n//   27 -> [(0, 1), (3, 2)]\n//   28 -> [(0, 2), (2, 1), (4, 2)]\n//   29 -> [(0, 2), t(1, 2), (1, 2), (2, 2), (3, 2), (4, 2)]\n//   30 -> [(0, 2), (1, 2), (4, 2)]\n//   31 -> [(0, 2), (1, 2), (3, 2), (4, 2)]\n//   32 -> [(0, 2), (2, 2), (3, 2), (4, 2)]\n//   33 -> [(0, 2), (1, 2), t(2, 2), (2, 2), (3, 2), (4, 2)]\n//   34 -> [(0, 2), (1, 2), (2, 2), t(2, 2), (3, 2), (4, 2)]\n//   35 -> [(0, 2), (3, 2), (4, 2)]\n//   36 -> [(0, 2), t(2, 2), (2, 2), (3, 2), (4, 2)]\n//   37 -> [t(0, 2), (0, 2), (1, 2), (2, 2), (4, 2)]\n//   38 -> [(0, 2), (1, 2), (2, 2), (4, 2)]\n//   39 -> [t(0, 2), (0, 2), (1, 2), (2, 2), (3, 2), (4, 2)]\n//   40 -> [(0, 2), (1, 2), (2, 2), (3, 2), (4, 2)]\n//   41 -> [(0, 2), (4, 2)]\n//   42 -> [t(0, 2), (0, 2), (1, 2), (2, 2), t(2, 2), (3, 2), (4, 2)]\n//   43 -> [(0, 2), (2, 2), (4, 2)]\n//   44 -> [(0, 2), (1, 2), t(1, 2), (2, 2), (3, 2), (4, 2)]\n/**\n * From org/apache/lucene/util/automaton/Lev2TParametricDescription.java\n * @hidden\n */\nclass lev2t_parametric_description_Lev2TParametricDescription extends ParametricDescription {\n    constructor(w) {\n        super(w, 2, [0, 2, 1, 0, 1, 0, -1, 0, 0, -1, 0, -1, -1, -1, -1, -1, -2, -1, -1, -1, -2, -1, -1, -2, -1, -1, -2, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2]);\n    }\n    transition(absState, position, vector) {\n        // null absState should never be passed in\n        // assert absState != -1;\n        // decode absState -> state, offset\n        let state = Math.floor(absState / (this._w + 1));\n        let offset = absState % (this._w + 1);\n        // assert offset >= 0;\n        if (position === this._w) {\n            if (state < 3) {\n                const loc = vector * 3 + state;\n                offset += ParametricDescription.unpack(lev2t_parametric_description_offsetIncrs0, loc, 1);\n                state = ParametricDescription.unpack(lev2t_parametric_description_toStates0, loc, 2) - 1;\n            }\n        }\n        else if (position === this._w - 1) {\n            if (state < 5) {\n                const loc = vector * 5 + state;\n                offset += ParametricDescription.unpack(lev2t_parametric_description_offsetIncrs1, loc, 1);\n                state = ParametricDescription.unpack(lev2t_parametric_description_toStates1, loc, 3) - 1;\n            }\n        }\n        else if (position === this._w - 2) {\n            if (state < 13) {\n                const loc = vector * 13 + state;\n                offset += ParametricDescription.unpack(lev2t_parametric_description_offsetIncrs2, loc, 2);\n                state = ParametricDescription.unpack(lev2t_parametric_description_toStates2, loc, 4) - 1;\n            }\n        }\n        else if (position === this._w - 3) {\n            if (state < 28) {\n                const loc = vector * 28 + state;\n                offset += ParametricDescription.unpack(lev2t_parametric_description_offsetIncrs3, loc, 2);\n                state = ParametricDescription.unpack(lev2t_parametric_description_toStates3, loc, 5) - 1;\n            }\n        }\n        else if (position === this._w - 4) {\n            if (state < 45) {\n                const loc = vector * 45 + state;\n                offset += ParametricDescription.unpack(offsetIncrs4, loc, 3);\n                state = ParametricDescription.unpack(toStates4, loc, 6) - 1;\n            }\n        }\n        else {\n            if (state < 45) {\n                const loc = vector * 45 + state;\n                offset += ParametricDescription.unpack(offsetIncrs5, loc, 3);\n                state = ParametricDescription.unpack(toStates5, loc, 6) - 1;\n            }\n        }\n        if (state === -1) {\n            // null state\n            return -1;\n        }\n        else {\n            // translate back to abs\n            return state * (this._w + 1) + offset;\n        }\n    }\n}\n\n// CONCATENATED MODULE: ./packages/full-text-search/src/fuzzy/levenshtein_automata.ts\n\n\n\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java\n * @hidden\n */\nclass levenshtein_automata_LevenshteinAutomata {\n    constructor(input, editDistance) {\n        this._word = input;\n        this._editDistance = editDistance;\n        this._alphabet = [...new Set(this._word)].sort((a, b) => a - b);\n        this._numRanges = 0;\n        this._rangeLower = new Array(this._alphabet.length + 2);\n        this._rangeUpper = new Array(this._alphabet.length + 2);\n        // calculate the unicode range intervals that exclude the alphabet\n        // these are the ranges for all unicode characters not in the alphabet\n        let lower = 0;\n        for (let i = 0; i < this._alphabet.length; i++) {\n            const higher = this._alphabet[i];\n            if (higher > lower) {\n                this._rangeLower[this._numRanges] = lower;\n                this._rangeUpper[this._numRanges] = higher - 1;\n                this._numRanges++;\n            }\n            lower = higher + 1;\n        }\n        /* add the final endpoint */\n        if (lower <= MAX_CODE_POINT) {\n            this._rangeLower[this._numRanges] = lower;\n            this._rangeUpper[this._numRanges] = MAX_CODE_POINT;\n            this._numRanges++;\n        }\n        if (editDistance === 1) {\n            this._description = new lev1t_parametric_description_Lev1TParametricDescription(input.length);\n        }\n        else {\n            this._description = new lev2t_parametric_description_Lev2TParametricDescription(input.length);\n        }\n    }\n    /**\n     * Transforms the NDFA to a DFA.\n     * @returns {Automaton}\n     */\n    toAutomaton() {\n        let automat = new Automaton();\n        const range = 2 * this._editDistance + 1;\n        // the number of states is based on the length of the word and the edit distance\n        const numStates = this._description.size();\n        // Prefix is not needed to be handled by the automaton.\n        // stateOffset = 0;\n        automat.createState();\n        // create all states, and mark as accept states if appropriate\n        for (let i = 1; i < numStates; i++) {\n            let state = automat.createState();\n            automat.setAccept(state, this._description.isAccept(i));\n        }\n        for (let k = 0; k < numStates; k++) {\n            const xpos = this._description.getPosition(k);\n            if (xpos < 0) {\n                continue;\n            }\n            const end = xpos + Math.min(this._word.length - xpos, range);\n            for (let x = 0; x < this._alphabet.length; x++) {\n                const ch = this._alphabet[x];\n                const cvec = this._getVector(ch, xpos, end);\n                const dest = this._description.transition(k, xpos, cvec);\n                if (dest >= 0) {\n                    automat.addTransition(k, dest, ch, ch);\n                }\n            }\n            const dest = this._description.transition(k, xpos, 0);\n            if (dest >= 0) {\n                for (let r = 0; r < this._numRanges; r++) {\n                    automat.addTransition(k, dest, this._rangeLower[r], this._rangeUpper[r]);\n                }\n            }\n        }\n        // assert automat.deterministic;\n        automat.finishState();\n        return automat;\n    }\n    _getVector(x, pos, end) {\n        let vector = 0;\n        for (let i = pos; i < end; i++) {\n            vector <<= 1;\n            if (this._word[i] === x) {\n                vector |= 1;\n            }\n        }\n        return vector;\n    }\n}\n\n// CONCATENATED MODULE: ./packages/full-text-search/src/index_searcher.ts\n\n\n\n\n\nfunction calculateMinShouldMatch(optionalClauseCount, spec) {\n    if (spec === undefined) {\n        return 1;\n    }\n    if (typeof spec === \"number\") {\n        return (spec < 0) ? optionalClauseCount + spec : spec;\n    }\n    let result = optionalClauseCount;\n    if (spec.includes(\"<\")) {\n        // Parse conditional minimumShouldMatch.;\n        for (const s of spec.split(\" \")) {\n            const parts = s.split(\"<\");\n            const upperBound = parseInt(parts[0]);\n            if (optionalClauseCount <= upperBound) {\n                return result;\n            }\n            else {\n                result = calculateMinShouldMatch(optionalClauseCount, parts[1]);\n            }\n        }\n        return result;\n    }\n    if (spec.includes(\"%\")) {\n        // Parse percentage.\n        const percent = parseInt(spec.slice(0, -1));\n        const calc = (result * percent) * (1 / 100);\n        result = (calc < 0) ? result + Math.ceil(calc) : Math.floor(calc);\n    }\n    else {\n        const calc = parseInt(spec);\n        result = (calc < 0) ? result + calc : calc;\n    }\n    return (result < 1) ? 1 : result;\n}\n/**\n * @hidden\n */\nclass index_searcher_IndexSearcher {\n    /**\n     * Constructs an index searcher.\n     * @param {Dict<InvertedIndex>} invIdxs - the inverted indexes\n     * @param {Set<number>} docs - the ids of the documents\n     */\n    constructor(invIdxs, docs) {\n        this._invIdxs = invIdxs;\n        this._docs = docs;\n        this._scorer = new Scorer(this._invIdxs);\n    }\n    search(query) {\n        let queryResults = this._recursive(query.query, true);\n        // Do final scoring.\n        if (query.calculate_scoring !== undefined ? query.calculate_scoring : true) {\n            return this._scorer.finalScore(query, queryResults);\n        }\n        const result = {};\n        for (const key of queryResults.keys()) {\n            result[key] = { score: 1 };\n        }\n        return result;\n    }\n    setDirty() {\n        this._scorer.setDirty();\n    }\n    _recursive(query, doScoring) {\n        let queryResults = new Map();\n        const boost = query.boost !== undefined ? query.boost : 1;\n        const fieldName = query.field !== undefined ? query.field : null;\n        let root = null;\n        let analyzer = null;\n        if (this._invIdxs[fieldName] !== undefined) {\n            root = this._invIdxs[fieldName].root;\n            analyzer = this._invIdxs[fieldName].analyzer;\n        }\n        switch (query.type) {\n            case \"bool\": {\n                queryResults = null;\n                if (query.must !== undefined) {\n                    queryResults = this._getUnique(query.must, doScoring, queryResults);\n                }\n                if (query.filter !== undefined) {\n                    queryResults = this._getUnique(query.filter, null, queryResults);\n                }\n                if (query.should !== undefined) {\n                    const shouldDocs = this._getAll(query.should, doScoring);\n                    let empty = false;\n                    if (queryResults === null) {\n                        empty = true;\n                        queryResults = new Map();\n                    }\n                    const msm = Math.max(1, calculateMinShouldMatch(query.should.length, query.minimum_should_match));\n                    if (empty && msm === 1) {\n                        // Take all documents.\n                        queryResults = shouldDocs;\n                    }\n                    else {\n                        // Remove documents with fewer matches.\n                        for (const [docId, res] of shouldDocs) {\n                            if (res.length >= msm) {\n                                if (queryResults.has(docId)) {\n                                    queryResults.get(docId).push(...res);\n                                }\n                                else if (empty) {\n                                    queryResults.set(docId, res);\n                                }\n                                else {\n                                    queryResults.delete(docId);\n                                }\n                            }\n                        }\n                    }\n                }\n                // Match all documents if must/filter/should is not defined.\n                if (queryResults === null) {\n                    queryResults = this._recursive({ type: \"match_all\" }, false);\n                }\n                if (query.not !== undefined) {\n                    let notDocs = this._getAll(query.not, null);\n                    // Remove all matching documents.\n                    for (const docId of notDocs.keys()) {\n                        if (queryResults.has(docId)) {\n                            queryResults.delete(docId);\n                        }\n                    }\n                }\n                // Boost query results afterwards.\n                if (boost !== 1) {\n                    for (const [_, result] of queryResults) {\n                        for (let i = 0; i < result.length; i++) {\n                            result[i].boost *= boost;\n                        }\n                    }\n                }\n                break;\n            }\n            case \"term\": {\n                const cps = toCodePoints(query.value);\n                let termIdx = inverted_index_InvertedIndex.getTermIndex(cps, root);\n                this._scorer.score(fieldName, boost, termIdx, doScoring, queryResults, cps);\n                break;\n            }\n            case \"terms\": {\n                for (let i = 0; i < query.value.length; i++) {\n                    const cps = toCodePoints(query.value[i]);\n                    let termIdx = inverted_index_InvertedIndex.getTermIndex(cps, root);\n                    this._scorer.score(fieldName, boost, termIdx, doScoring, queryResults, cps);\n                }\n                break;\n            }\n            case \"fuzzy\": {\n                const [f, idf] = fuzzySearch(query, root);\n                for (let i = 0; i < f.length; i++) {\n                    this._scorer.score(fieldName, boost * f[i].boost, f[i].index, doScoring, queryResults, f[i].term, idf);\n                }\n                break;\n            }\n            case \"wildcard\": {\n                const enableScoring = query.enable_scoring !== undefined ? query.enable_scoring : false;\n                const w = wildcardSearch(query, root);\n                for (let i = 0; i < w.length; i++) {\n                    this._scorer.score(fieldName, boost, w[i].index, doScoring && enableScoring, queryResults, w[i].term);\n                }\n                break;\n            }\n            case \"match_all\": {\n                for (let docId of this._docs) {\n                    this._scorer.scoreConstant(boost, docId, queryResults);\n                }\n                break;\n            }\n            case \"constant_score\": {\n                let tmpQueryResults = this._getAll(query.filter, false);\n                // Add to each document a constant score.\n                for (const docId of tmpQueryResults.keys()) {\n                    this._scorer.scoreConstant(boost, docId, queryResults);\n                }\n                break;\n            }\n            case \"prefix\": {\n                const enableScoring = query.enable_scoring !== undefined ? query.enable_scoring : false;\n                const cps = toCodePoints(query.value);\n                const termIdx = inverted_index_InvertedIndex.getTermIndex(cps, root);\n                if (termIdx !== null) {\n                    const termIdxs = inverted_index_InvertedIndex.extendTermIndex(termIdx);\n                    for (let i = 0; i < termIdxs.length; i++) {\n                        this._scorer.score(fieldName, boost, termIdxs[i].index, doScoring && enableScoring, queryResults, [...cps, ...termIdxs[i].term]);\n                    }\n                }\n                break;\n            }\n            case \"exists\": {\n                if (root !== null) {\n                    for (const docId of this._invIdxs[fieldName].docStore.keys()) {\n                        this._scorer.scoreConstant(boost, docId, queryResults);\n                    }\n                }\n                break;\n            }\n            case \"match\": {\n                const terms = analyze(analyzer, query.value);\n                const operator = query.operator !== undefined ? query.operator : \"or\";\n                const boolQuery = { type: \"bool\" };\n                const subQueries = [];\n                if (operator === \"or\") {\n                    if (query.minimum_should_match !== undefined) {\n                        boolQuery.minimum_should_match = query.minimum_should_match;\n                    }\n                    // Create a should query.\n                    boolQuery.should = subQueries;\n                }\n                else {\n                    // Create a must query.\n                    boolQuery.must = subQueries;\n                }\n                boolQuery.boost = boost;\n                if (query.fuzziness !== undefined) {\n                    let prefixLength = query.prefix_length !== undefined ? query.prefix_length : 2;\n                    let extended = query.extended !== undefined ? query.extended : false;\n                    // Add each fuzzy.\n                    for (let i = 0; i < terms.length; i++) {\n                        subQueries.push({\n                            type: \"fuzzy\", field: fieldName, value: terms[i], fuzziness: query.fuzziness,\n                            prefix_length: prefixLength, extended: extended\n                        });\n                    }\n                }\n                else {\n                    // Add each term.\n                    for (let i = 0; i < terms.length; i++) {\n                        subQueries.push({ type: \"term\", field: fieldName, value: terms[i] });\n                    }\n                }\n                queryResults = this._recursive(boolQuery, doScoring);\n                break;\n            }\n            default:\n                break;\n        }\n        return queryResults;\n    }\n    _getUnique(queries, doScoring, queryResults) {\n        if (queries.length === 0) {\n            return queryResults;\n        }\n        for (let i = 0; i < queries.length; i++) {\n            let currDocs = this._recursive(queries[i], doScoring);\n            if (queryResults === null) {\n                queryResults = this._recursive(queries[0], doScoring);\n                continue;\n            }\n            for (const docId of queryResults.keys()) {\n                if (!currDocs.has(docId)) {\n                    queryResults.delete(docId);\n                }\n                else {\n                    queryResults.get(docId).push(...currDocs.get(docId));\n                }\n            }\n        }\n        return queryResults;\n    }\n    _getAll(queries, doScoring, queryResults = new Map()) {\n        for (let i = 0; i < queries.length; i++) {\n            let currDocs = this._recursive(queries[i], doScoring);\n            for (const docId of currDocs.keys()) {\n                if (!queryResults.has(docId)) {\n                    queryResults.set(docId, currDocs.get(docId));\n                }\n                else {\n                    queryResults.get(docId).push(...currDocs.get(docId));\n                }\n            }\n        }\n        return queryResults;\n    }\n}\n/**\n * Calculates the levenshtein distance. Specialized version.\n * Copyright Kigiri: https://github.com/kigiri\n *           Milot Mirdita: https://github.com/milot-mirdita\n *           Toni Neubert:  https://github.com/Viatorus/\n * @param {string} a - a string\n * @param {string} b - a string\n */\nfunction calculateLevenshteinDistance(a, b) {\n    let i;\n    let j;\n    let prev;\n    let val;\n    const row = Array(a.length + 1);\n    // init the row\n    for (i = 0; i <= a.length; i++) {\n        row[i] = i;\n    }\n    // fill in the rest\n    for (i = 1; i <= b.length; i++) {\n        prev = i;\n        for (j = 1; j <= a.length; j++) {\n            if (b[i - 1] === a[j - 1]) { // match\n                val = row[j - 1];\n            }\n            else {\n                val = Math.min(row[j - 1] + 1, // substitution\n                Math.min(prev + 1, // insertion\n                row[j] + 1)); // deletion\n                // transposition\n                if (i > 1 && j > 1 && b[i - 2] === a[j - 1] && a[j - 2] === b[i - 1]) {\n                    val = Math.min(val, row[j - 1] - (a[j - 1] === b[i - 1] ? 1 : 0));\n                }\n            }\n            row[j - 1] = prev;\n            prev = val;\n        }\n        row[a.length] = prev;\n    }\n    return row[a.length];\n}\n/**\n * Performs a fuzzy search.\n * @param {FuzzyQuery} query - the fuzzy query\n * @param {Index} root - the root index\n * @returns {[FuzzyResult, number]} - the fuzzy results and the maximum df\n */\nfunction fuzzySearch(query, root) {\n    let value = toCodePoints(query.value);\n    let fuzziness = query.fuzziness !== undefined ? query.fuzziness : \"AUTO\";\n    if (fuzziness === \"AUTO\") {\n        if (value.length <= 2) {\n            fuzziness = 0;\n        }\n        else if (value.length <= 5) {\n            fuzziness = 1;\n        }\n        else {\n            fuzziness = 2;\n        }\n    }\n    let prefixLength = query.prefix_length !== undefined ? query.prefix_length : 0;\n    let extended = query.extended !== undefined ? query.extended : false;\n    // Do just a prefix search if zero fuzziness.\n    if (fuzziness === 0) {\n        prefixLength = value.length;\n    }\n    let result = [];\n    let startIdx = root;\n    let prefix = value.slice(0, prefixLength);\n    let fuzzy = value;\n    let df = 0;\n    // Perform a prefix search.\n    if (prefixLength !== 0) {\n        startIdx = inverted_index_InvertedIndex.getTermIndex(prefix, startIdx);\n        fuzzy = fuzzy.slice(prefixLength);\n    }\n    // No startIdx found.\n    if (startIdx === null) {\n        return [result, df];\n    }\n    // Fuzzy is not necessary anymore, because prefix search includes the whole query value.\n    if (fuzzy.length === 0) {\n        if (extended) {\n            // Add all terms down the index.\n            const all = inverted_index_InvertedIndex.extendTermIndex(startIdx);\n            for (let i = 0; i < all.length; i++) {\n                result.push({ index: all[i].index, term: all[i].term, boost: 1 });\n                df = Math.max(df, all[i].index.df);\n            }\n        }\n        else if (startIdx.dc !== undefined) {\n            // Add prefix search result.\n            result.push({ index: startIdx, term: value, boost: 1 });\n            df = startIdx.df;\n        }\n        return [result, df];\n    }\n    // The matching term.\n    const term = [0];\n    // Create an automaton from the fuzzy.\n    const automaton = new RunAutomaton(new levenshtein_automata_LevenshteinAutomata(fuzzy, fuzziness).toAutomaton());\n    function determineEditDistance(state, term, fuzzy) {\n        // Check how many edits this fuzzy can still do.\n        let ed = 0;\n        state = automaton.step(state, 0);\n        if (state !== -1 && automaton.isAccept(state)) {\n            ed++;\n            state = automaton.step(state, 0);\n            if (state !== -1 && automaton.isAccept(state)) {\n                ed++;\n            }\n            // Special handling for smaller terms.\n            if (term.length < fuzzy.length) {\n                if (ed !== fuzziness) {\n                    return calculateLevenshteinDistance(term, fuzzy);\n                }\n                // Include the term and fuzzy length.\n                ed -= fuzzy.length - term.length;\n            }\n        }\n        return fuzziness - ed;\n    }\n    function recursive(state, key, idx) {\n        term[term.length - 1] = key;\n        // Check the current key of term with the automaton.\n        state = automaton.step(state, key);\n        if (state === -1) {\n            return;\n        }\n        if (automaton.isAccept(state)) {\n            if (extended) {\n                // Add all terms down the index.\n                const all = inverted_index_InvertedIndex.extendTermIndex(idx);\n                for (let i = 0; i < all.length; i++) {\n                    result.push({ index: all[i].index, term: all[i].term, boost: 1 });\n                    df = Math.max(df, all[i].index.df);\n                }\n                return;\n            }\n            else if (idx.df !== undefined) {\n                // Calculate boost.\n                const distance = determineEditDistance(state, term, fuzzy);\n                const boost = Math.max(0, 1 - distance / Math.min(prefix.length + term.length, value.length));\n                result.push({ index: idx, term: [...prefix, ...term], boost });\n                df = Math.max(df, idx.df);\n            }\n        }\n        term.push(0);\n        for (const child of idx) {\n            recursive(state, child[0], child[1]);\n        }\n        term.pop();\n    }\n    for (const child of startIdx) {\n        recursive(0, child[0], child[1]);\n    }\n    return [result, df];\n}\n/**\n * Performs a wildcard search.\n * @param {WildcardQuery} query - the wildcard query\n * @param {Index} root - the root index\n * @returns {Array} - the results\n */\nfunction wildcardSearch(query, root) {\n    let wildcard = toCodePoints(query.value);\n    let result = [];\n    function recursive(index, idx = 0, term = [], escaped = false) {\n        if (index === null) {\n            return;\n        }\n        if (idx === wildcard.length) {\n            if (index.df !== undefined) {\n                result.push({ index: index, term: term.slice() });\n            }\n            return;\n        }\n        // Escaped character.\n        if (!escaped && wildcard[idx] === 92 /* \\ */) {\n            recursive(index, idx + 1, term, true);\n        }\n        else if (!escaped && wildcard[idx] === 63 /* ? */) {\n            for (const child of index) {\n                recursive(child[1], idx + 1, [...term, child[0]]);\n            }\n        }\n        else if (!escaped && wildcard[idx] === 42 /* * */) {\n            // Check if asterisk is last wildcard character\n            if (idx + 1 === wildcard.length) {\n                const all = inverted_index_InvertedIndex.extendTermIndex(index);\n                for (let i = 0; i < all.length; i++) {\n                    recursive(all[i].index, idx + 1, [...term, ...all[i].term]);\n                }\n            }\n            else {\n                // Iterate over the whole tree.\n                recursive(index, idx + 1, term, false);\n                const indices = [{ index: index, term: [] }];\n                do {\n                    const index = indices.pop();\n                    for (const child of index.index) {\n                        recursive(child[1], idx + 1, [...term, ...index.term, child[0]]);\n                        indices.push({ index: child[1], term: [...index.term, child[0]] });\n                    }\n                } while (indices.length !== 0);\n            }\n        }\n        else {\n            recursive(inverted_index_InvertedIndex.getTermIndex([wildcard[idx]], index), idx + 1, [...term, wildcard[idx]]);\n        }\n    }\n    recursive(root);\n    return result;\n}\n\n// EXTERNAL MODULE: ./packages/common/plugin.ts\nvar common_plugin = __webpack_require__(0);\n\n// CONCATENATED MODULE: ./packages/full-text-search/src/full_text_search.ts\n\n\n\nclass full_text_search_FullTextSearch {\n    /**\n     * Initialize the full-text search for the given fields.\n     * @param {object[]} fieldOptions - the field options\n     * @param {string} fieldOptions.field - the name of the property field\n     * @param {boolean=true} fieldOptions.store - flag to indicate if the full-text search should be stored on serialization or\n     *  rebuild on deserialization\n     * @param {boolean=true} fieldOptions.optimizeChanges - flag to optimize updating and deleting of documents\n     *    (requires more memory but performs faster)\n     * @param {Analyzer} fieldOptions.analyzer - an analyzer for the field\n     * @param {string} [id] - the property name of the document index\n     */\n    constructor(fieldOptions = [], id) {\n        this._invIdxs = {};\n        // Create an inverted index for each field.\n        for (let i = 0; i < fieldOptions.length; i++) {\n            let fieldOption = fieldOptions[i];\n            this._invIdxs[fieldOption.field] = new inverted_index_InvertedIndex(fieldOption);\n        }\n        this._id = id;\n        this._docs = new Set();\n        this._idxSearcher = new index_searcher_IndexSearcher(this._invIdxs, this._docs);\n    }\n    /**\n     * Registers the full-text search as plugin.\n     */\n    static register() {\n        common_plugin[\"a\" /* PLUGINS */][\"FullTextSearch\"] = full_text_search_FullTextSearch;\n    }\n    addDocument(doc, id = doc[this._id]) {\n        let fieldNames = Object.keys(this._invIdxs);\n        for (let i = 0, fieldName; i < fieldNames.length, fieldName = fieldNames[i]; i++) {\n            let field = doc[fieldName];\n            // Skip null and undefined.\n            if (field === null || field === undefined) {\n                continue;\n            }\n            if (typeof field !== \"string\") {\n                // Convert number to string.\n                if (typeof field === \"number\") {\n                    field = field.toString();\n                }\n                else {\n                    throw TypeError(\"Unsupported field type for full text search.\");\n                }\n            }\n            this._invIdxs[fieldName].insert(field, id);\n        }\n        this._docs.add(id);\n        this._idxSearcher.setDirty();\n    }\n    removeDocument(doc, id = doc[this._id]) {\n        let fieldNames = Object.keys(this._invIdxs);\n        for (let i = 0; i < fieldNames.length; i++) {\n            this._invIdxs[fieldNames[i]].remove(id);\n        }\n        this._docs.delete(id);\n        this._idxSearcher.setDirty();\n    }\n    updateDocument(doc, id = doc[this._id]) {\n        this.removeDocument(doc, id);\n        this.addDocument(doc, id);\n    }\n    clear() {\n        for (let id of this._docs) {\n            this.removeDocument(null, id);\n        }\n    }\n    search(query) {\n        return this._idxSearcher.search(query);\n    }\n    toJSON() {\n        let serialized = { id: this._id, ii: {} };\n        let fieldNames = Object.keys(this._invIdxs);\n        for (let i = 0; i < fieldNames.length; i++) {\n            const fieldName = fieldNames[i];\n            serialized.ii[fieldName] = this._invIdxs[fieldName].toJSON();\n        }\n        return serialized;\n    }\n    static fromJSONObject(serialized, analyzers = {}) {\n        let fts = new full_text_search_FullTextSearch([], serialized.id);\n        let fieldNames = Object.keys(serialized.ii);\n        for (let i = 0; i < fieldNames.length; i++) {\n            const fieldName = fieldNames[i];\n            fts._invIdxs[fieldName] = inverted_index_InvertedIndex.fromJSONObject(serialized.ii[fieldName], analyzers[fieldName]);\n        }\n        return fts;\n    }\n}\n\n// CONCATENATED MODULE: ./packages/full-text-search/src/index.ts\n/* concated harmony reexport */__webpack_require__.d(__webpack_exports__, \"FullTextSearch\", function() { return full_text_search_FullTextSearch; });\n/* concated harmony reexport */__webpack_require__.d(__webpack_exports__, \"analyze\", function() { return analyze; });\n/* concated harmony reexport */__webpack_require__.d(__webpack_exports__, \"StandardAnalyzer\", function() { return analyzer_StandardAnalyzer; });\n/* concated harmony reexport */__webpack_require__.d(__webpack_exports__, \"whitespaceTokenizer\", function() { return whitespaceTokenizer; });\n/* concated harmony reexport */__webpack_require__.d(__webpack_exports__, \"lowercaseTokenFilter\", function() { return lowercaseTokenFilter; });\n/* concated harmony reexport */__webpack_require__.d(__webpack_exports__, \"uppercaseTokenFilter\", function() { return uppercaseTokenFilter; });\n\n\n\n\nfull_text_search_FullTextSearch[\"Analyzer\"] = {};\nfull_text_search_FullTextSearch[\"Analyzer\"][\"analyze\"] = analyze;\nfull_text_search_FullTextSearch[\"Analyzer\"][\"StandardAnalyzer\"] = analyzer_StandardAnalyzer;\nfull_text_search_FullTextSearch[\"Tokenizer\"] = {};\nfull_text_search_FullTextSearch[\"Tokenizer\"][\"whitespaceTokenizer\"] = whitespaceTokenizer;\nfull_text_search_FullTextSearch[\"TokenFilter\"] = {};\nfull_text_search_FullTextSearch[\"TokenFilter\"][\"lowercaseTokenFilter\"] = lowercaseTokenFilter;\nfull_text_search_FullTextSearch[\"TokenFilter\"][\"uppercaseTokenFilter\"] = uppercaseTokenFilter;\n\n/* harmony default export */ var src = __webpack_exports__[\"default\"] = (full_text_search_FullTextSearch);\n\n\n/***/ }),\n/* 2 */\n/***/ (function(module, exports) {\n\nvar g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || Function(\"return this\")() || (1, eval)(\"this\");\n} catch (e) {\n\t// This works if the window reference is available\n\tif (typeof window === \"object\") g = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n\n\n/***/ })\n/******/ ]);\n});\n//# sourceMappingURL=lokidb.full-text-search.js.map"
  },
  {
    "path": "dist/packages/full-text-search/types/common/plugin.d.ts",
    "content": "/**\n * @hidden\n */\nexport declare const PLUGINS: void;\n"
  },
  {
    "path": "dist/packages/full-text-search/types/common/types.d.ts",
    "content": "/**\n * @hidden\n */\nimport { Loki } from \"../loki/src/loki\";\nexport interface StorageAdapter {\n    loadDatabase(dbname: string): Promise<any>;\n    saveDatabase?(dbname: string, serialization: string): Promise<void>;\n    deleteDatabase?(dbname: string): Promise<void>;\n    mode?: string;\n    exportDatabase?(dbname: string, dbref: Loki): Promise<void>;\n}\nexport declare type Doc<T extends object = object> = T & {\n    $loki: number;\n    meta?: {\n        created: number;\n        revision: number;\n        version: number;\n        updated?: number;\n    };\n};\nexport interface Dict<T> {\n    [index: string]: T;\n    [index: number]: T;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/fs-storage/src/fs_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists using node fs module.\n */\nexport declare class FSStorage implements StorageAdapter {\n    /**\n     * Registers the fs storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the fs storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * Load data from file, will throw an error if the file does not exist\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Save data to file, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Delete the database file, will throw an error if the\n     * file can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/fs-storage/src/index.d.ts",
    "content": "import { FSStorage } from \"./fs_storage\";\nexport { FSStorage };\nexport default FSStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search/src/analyzer/analyzer.d.ts",
    "content": "import { CharacterFilter } from \"./character_filter\";\nimport { Tokenizer, whitespaceTokenizer } from \"./tokenizer\";\nimport { lowercaseTokenFilter, TokenFilter } from \"./token_filter\";\n/**\n * A analyzer converts a string into tokens which are added to the inverted index for searching.\n */\nexport interface Analyzer {\n    /**\n     * The character filters of the analyzer.\n     */\n    char_filter?: CharacterFilter[];\n    /**\n     * The tokenizer of the analyzer.\n     */\n    tokenizer: Tokenizer;\n    /**\n     * The token filters of the analyzer.\n     */\n    token_filter?: TokenFilter[];\n}\n/**\n * Analyzes a given string.\n * @param {Analyzer} analyzer - the analyzer\n * @param {string} str - the string\n * @returns {string[]} - the tokens\n */\nexport declare function analyze(analyzer: Analyzer, str: string): string[];\n/**\n * An analyzer with the whitespace tokenizer and the lowercase token filter.\n */\nexport declare class StandardAnalyzer implements Analyzer {\n    tokenizer: typeof whitespaceTokenizer;\n    token_filter: (typeof lowercaseTokenFilter)[];\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search/src/analyzer/character_filter.d.ts",
    "content": "/**\n * A character filter is used to preprocess a string before it is passed to a tokenizer.\n */\nexport declare type CharacterFilter = (value: string) => string;\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search/src/analyzer/token_filter.d.ts",
    "content": "/**\n * A token filter takes tokens from a tokenizer and modify, delete or add tokens.\n */\nexport declare type TokenFilter = (value: string, index: number, array: string[]) => string;\n/**\n * Converts a token to lowercase.\n * @param {string} token - the token\n * @returns {string} - the lowercased token\n */\nexport declare function lowercaseTokenFilter(token: string): string;\n/**\n * Converts a token to uppercase.\n * @param {string} token - the token\n * @returns {string} - the uppercased token\n */\nexport declare function uppercaseTokenFilter(token: string): string;\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search/src/analyzer/tokenizer.d.ts",
    "content": "/**\n * A tokenizer splits a string into individual tokens.\n */\nexport declare type Tokenizer = (value: string) => string[];\n/**\n * Splits a string at whitespace characters into tokens.\n * @param {string} value - the string\n * @returns {string[]} - the tokens\n */\nexport declare function whitespaceTokenizer(value: string): string[];\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search/src/full_text_search.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\nimport { Scorer } from \"./scorer\";\nimport { Analyzer } from \"./analyzer/analyzer\";\nexport declare class FullTextSearch {\n    private _id;\n    private _docs;\n    private _idxSearcher;\n    private _invIdxs;\n    /**\n     * Registers the full-text search as plugin.\n     */\n    static register(): void;\n    /**\n     * Initialize the full-text search for the given fields.\n     * @param {object[]} fieldOptions - the field options\n     * @param {string} fieldOptions.field - the name of the property field\n     * @param {boolean=true} fieldOptions.store - flag to indicate if the full-text search should be stored on serialization or\n     *  rebuild on deserialization\n     * @param {boolean=true} fieldOptions.optimizeChanges - flag to optimize updating and deleting of documents\n     *    (requires more memory but performs faster)\n     * @param {Analyzer} fieldOptions.analyzer - an analyzer for the field\n     * @param {string} [id] - the property name of the document index\n     */\n    constructor(fieldOptions?: FullTextSearch.FieldOptions[], id?: string);\n    addDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    removeDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    updateDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    clear(): void;\n    search(query: Query): Scorer.ScoreResults;\n    toJSON(): FullTextSearch.Serialization;\n    static fromJSONObject(serialized: FullTextSearch.Serialization, analyzers?: Dict<Analyzer>): FullTextSearch;\n}\nexport declare namespace FullTextSearch {\n    interface FieldOptions extends InvertedIndex.FieldOptions {\n        field: string;\n    }\n    interface Serialization {\n        id: string;\n        ii: Dict<InvertedIndex.Serialization>;\n    }\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search/src/fuzzy/automaton.d.ts",
    "content": "/**\n * Transition with dest, min and max.\n * @hidden\n */\nexport declare type Transition = [number, number, number];\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MIN_CODE_POINT = 0;\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MAX_CODE_POINT = 1114111;\n/**\n * From org/apache/lucene/util/automaton/Automaton.java\n * @hidden\n */\nexport declare class Automaton {\n    private _stateTransitions;\n    private _accept;\n    private _nextState;\n    private _currState;\n    private _transitions;\n    constructor();\n    isAccept(n: number): boolean;\n    createState(): number;\n    setAccept(state: number, accept: boolean): void;\n    finishState(): void;\n    private _finishCurrentState();\n    getStartPoints(): number[];\n    step(state: number, label: number): number;\n    getNumStates(): number;\n    addTransition(source: number, dest: number, min: number, max: number): void;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search/src/fuzzy/lev1t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev1TParametricDescription.java\n * @hidden\n */\nexport declare class Lev1TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search/src/fuzzy/lev2t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev2TParametricDescription.java\n * @hidden\n */\nexport declare class Lev2TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search/src/fuzzy/levenshtein_automata.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java\n * @hidden\n */\nexport declare class LevenshteinAutomata {\n    private _word;\n    private _numRanges;\n    private _rangeLower;\n    private _rangeUpper;\n    private _description;\n    private _alphabet;\n    private _editDistance;\n    constructor(input: number[], editDistance: number);\n    /**\n     * Transforms the NDFA to a DFA.\n     * @returns {Automaton}\n     */\n    toAutomaton(): Automaton;\n    private _getVector(x, pos, end);\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search/src/fuzzy/long.d.ts",
    "content": "/**\n * Class supports 64Bit integer operations.\n * A cut-down version of dcodeIO/long.js.\n * @hidden\n */\nexport declare class Long {\n    private _low;\n    private _high;\n    constructor(low?: number, high?: number);\n    /**\n     * Returns this long with bits arithmetically shifted to the right by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftRight(numBits: number): Long;\n    /**\n     * Returns this long with bits arithmetically shifted to the left by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftLeft(numBits: number): Long;\n    /**\n     * Returns the bitwise AND of this Long and the specified.\n     * @param {Long} other - the other Long\n     * @returns {Long} the long\n     */\n    and(other: Long): Long;\n    /**\n     * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.\n     * @returns {number}\n     */\n    toInt(): number;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search/src/fuzzy/parametric_description.d.ts",
    "content": "import { Long } from \"./long\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java#ParametricDescription\n * @hidden\n */\nexport declare class ParametricDescription {\n    protected _w: number;\n    private _n;\n    private _minErrors;\n    constructor(w: number, n: number, minErrors: number[]);\n    /**\n     * Return the number of states needed to compute a Levenshtein DFA\n     */\n    size(): number;\n    /**\n     * Returns true if the <code>state</code> in any Levenshtein DFA is an accept state (final state).\n     */\n    isAccept(absState: number): boolean;\n    /**\n     * Returns the position in the input word for a given <code>state</code>.\n     * This is the minimal boundary for the state.\n     */\n    getPosition(absState: number): number;\n    static unpack(data: Long[], index: number, bitsPerValue: number): number;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search/src/fuzzy/run_automaton.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/RunAutomaton.java\n * @hidden\n */\nexport declare class RunAutomaton {\n    private _points;\n    private _accept;\n    private _transitions;\n    private _classmap;\n    constructor(automaton: Automaton);\n    getCharClass(c: number): number;\n    step(state: number, c: number): number;\n    isAccept(state: number): boolean;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search/src/index.d.ts",
    "content": "import { FullTextSearch } from \"./full_text_search\";\nimport { analyze, StandardAnalyzer } from \"./analyzer/analyzer\";\nimport { whitespaceTokenizer } from \"./analyzer/tokenizer\";\nimport { lowercaseTokenFilter, uppercaseTokenFilter } from \"./analyzer/token_filter\";\nexport { FullTextSearch, analyze, StandardAnalyzer, whitespaceTokenizer, lowercaseTokenFilter, uppercaseTokenFilter };\nexport default FullTextSearch;\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search/src/index_searcher.d.ts",
    "content": "import { Scorer } from \"./scorer\";\nimport { InvertedIndex } from \"./inverted_index\";\nimport { Query } from \"./query_types\";\nimport { Dict } from \"../../common/types\";\n/**\n * @hidden\n */\nexport declare class IndexSearcher {\n    private _invIdxs;\n    private _docs;\n    private _scorer;\n    /**\n     * Constructs an index searcher.\n     * @param {Dict<InvertedIndex>} invIdxs - the inverted indexes\n     * @param {Set<number>} docs - the ids of the documents\n     */\n    constructor(invIdxs: Dict<InvertedIndex>, docs: Set<InvertedIndex.DocumentIndex>);\n    search(query: Query): Scorer.ScoreResults;\n    setDirty(): void;\n    private _recursive(query, doScoring);\n    private _getUnique(queries, doScoring, queryResults);\n    private _getAll(queries, doScoring, queryResults?);\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search/src/inverted_index.d.ts",
    "content": "import { Analyzer } from \"./analyzer/analyzer\";\n/**\n * Converts a string into an array of code points.\n * @param str - the string\n * @returns {number[]} to code points\n * @hidden\n */\nexport declare function toCodePoints(str: string): number[];\n/**\n * Inverted index class handles featured text search for specific document fields.\n * @hidden\n */\nexport declare class InvertedIndex {\n    analyzer: Analyzer;\n    docCount: number;\n    docStore: Map<InvertedIndex.DocumentIndex, InvertedIndex.DocStore>;\n    totalFieldLength: number;\n    root: InvertedIndex.Index;\n    private _store;\n    private _optimizeChanges;\n    /**\n     * @param {boolean} [options.store=true] - inverted index will be stored at serialization rather than rebuilt on load\n     * @param {boolean} [options.optimizeChanges=true] - flag to store additional metadata inside the index for better\n     *  performance if an existing field is updated or removed\n     * @param {Analyzer} [options.analyzer=] - the analyzer of this inverted index\n     */\n    constructor(options?: InvertedIndex.FieldOptions);\n    /**\n     * Adds defined fields of a document to the inverted index.\n     * @param {string} field - the field to add\n     * @param {number} docId - the doc id of the field\n     */\n    insert(field: string, docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Removes all relevant terms of a document from the inverted index.\n     * @param {number} docId - the document.\n     */\n    remove(docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Gets the term index of a term.\n     * @param {string} term - the term\n     * @param {object} root - the term index to start from\n     * @param {number} start - the position of the term string to start from\n     * @return {object} - The term index or null if the term is not in the term tree.\n     */\n    static getTermIndex(term: number[], root: InvertedIndex.Index, start?: number): InvertedIndex.Index;\n    /**\n     * Extends a term index to all available term leafs.\n     * @param {object} idx - the term index to start from\n     * @param {number[]} [term=[]] - the current term\n     * @param {Array} termIndices - all extended indices with their term\n     * @returns {Array} - Array with term indices and extension\n     */\n    static extendTermIndex(idx: InvertedIndex.Index, term?: number[], termIndices?: InvertedIndex.IndexTerm[]): InvertedIndex.IndexTerm[];\n    /**\n     * Serialize the inverted index.\n     * @returns {{docStore: *, _fields: *, index: *}}\n     */\n    toJSON(): InvertedIndex.Serialization;\n    /**\n     * Deserialize the inverted index.\n     * @param {{docStore: *, _fields: *, index: *}} serialized - The serialized inverted index.\n     * @param {Analyzer} analyzer[undefined] - an analyzer\n     */\n    static fromJSONObject(serialized: InvertedIndex.Serialization, analyzer?: Analyzer): InvertedIndex;\n    private static _serializeIndex(idx);\n    private static _deserializeIndex(serialized);\n    /**\n     * Set parent of to each index and regenerate the indexRef.\n     * @param {Index} index - the index\n     * @param {Index} parent - the parent\n     */\n    private _regenerate(index, parent);\n    /**\n     * Iterate over the whole inverted index and remove the document.\n     * Delete branch if not needed anymore.\n     * Function is needed if index is used without optimization.\n     * @param {Index} idx - the index\n     * @param {number} docId - the doc id\n     * @returns {boolean} true if index is empty\n     */\n    private _remove(idx, docId);\n}\nexport declare namespace InvertedIndex {\n    interface FieldOptions {\n        store?: boolean;\n        optimizeChanges?: boolean;\n        analyzer?: Analyzer;\n    }\n    type Index = Map<number, any> & {\n        dc?: Map<DocumentIndex, number>;\n        df?: number;\n        pa?: Index;\n    };\n    type IndexTerm = {\n        index: Index;\n        term: number[];\n    };\n    interface SerializedIndex {\n        d?: {\n            df: number;\n            dc: [DocumentIndex, number][];\n        };\n        k?: number[];\n        v?: SerializedIndex[];\n    }\n    type Serialization = SpareSerialization | FullSerialization;\n    type SpareSerialization = {\n        _store: false;\n        _optimizeChanges: boolean;\n    };\n    type FullSerialization = {\n        _store: true;\n        _optimizeChanges: boolean;\n        docCount: number;\n        docStore: [DocumentIndex, DocStore][];\n        totalFieldLength: number;\n        root: SerializedIndex;\n    };\n    interface DocStore {\n        fieldLength?: number;\n        indexRef?: Index[];\n    }\n    type DocumentIndex = number | string;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search/src/query_types.d.ts",
    "content": "/**\n * Base query to enable boost to a query type.\n */\nexport interface BaseQuery<Type> {\n    type: Type;\n    boost?: number;\n}\n/**\n * A query which finds documents where a document field contains a term.\n */\nexport interface TermQuery extends BaseQuery<\"term\"> {\n    field: string;\n    value: string;\n}\n/**\n * A query which finds documents where a document field contains any of the terms.\n */\nexport interface TermsQuery extends BaseQuery<\"terms\"> {\n    field: string;\n    value: string[];\n}\n/**\n * A query which finds documents where the wildcard term can be applied at an existing document field term.\n */\nexport interface WildcardQuery extends BaseQuery<\"wildcard\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which finds documents where the fuzzy term can be transformed into an existing document field term within a\n * given edit distance.\n */\nexport interface FuzzyQuery extends BaseQuery<\"fuzzy\"> {\n    field: string;\n    value: string;\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query which matches documents containing the prefix of a term inside a field.\n */\nexport interface PrefixQuery extends BaseQuery<\"prefix\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which matches all documents with a given field.\n */\nexport interface ExistsQuery extends BaseQuery<\"exists\"> {\n    field: string;\n}\n/**\n * A query which tokenizes the given text into tokens and performs a sub query for each token. The results are combined\n * using a boolean operator.\n */\nexport interface MatchQuery extends BaseQuery<\"match\"> {\n    field: string;\n    value: string;\n    minimum_should_match?: number | string;\n    operator?: \"and\" | \"or\";\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query that matches all documents and giving them a constant score equal to the query boost.\n*/\nexport interface MatchQueryAll extends BaseQuery<\"match_all\"> {\n}\n/**\n * A query that wraps sub queries and returns a constant score equal to the query boost for every document in the filter.\n */\nexport interface ConstantScoreQuery extends BaseQuery<\"constant_score\"> {\n    filter: QueryTypes[];\n}\n/**\n * A query that matches documents matching boolean combinations of sub queries.\n */\nexport interface BoolQuery extends BaseQuery<\"bool\"> {\n    must?: QueryTypes[];\n    filter?: QueryTypes[];\n    should?: QueryTypes[];\n    not?: QueryTypes[];\n    minimum_should_match?: number | string;\n}\n/**\n * Union type of possible query types.\n */\nexport declare type QueryTypes = BoolQuery | ConstantScoreQuery | TermQuery | TermsQuery | WildcardQuery | FuzzyQuery | MatchQuery | MatchQueryAll | PrefixQuery | ExistsQuery;\n/**\n * The main query with the actually full-text search query and the scoring parameters.\n */\nexport interface Query {\n    query: QueryTypes;\n    calculate_scoring?: boolean;\n    explain?: boolean;\n    bm25?: {\n        k1: number;\n        b: number;\n    };\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search/src/scorer.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\n/**\n * @hidden\n */\nexport declare class Scorer {\n    private _invIdxs;\n    private _cache;\n    constructor(invIdxs: Dict<InvertedIndex>);\n    setDirty(): void;\n    score(fieldName: string, boost: number, termIdx: InvertedIndex.Index, doScoring: boolean | null, queryResults: Scorer.QueryResults, term: number[], df?: number): void;\n    scoreConstant(boost: number, docId: InvertedIndex.DocumentIndex, queryResults: Scorer.QueryResults): Scorer.QueryResults;\n    finalScore(query: Query, queryResults: Scorer.QueryResults): Scorer.ScoreResults;\n    private static _calculateFieldLength(fieldLength);\n    private _getCache(fieldName);\n    /**\n     * Returns the idf by either calculate it or use a cached one.\n     * @param {string} fieldName - the name of the field\n     * @param {number} docFreq - the doc frequency of the term\n     * @returns {number} the idf\n     * @private\n     */\n    private _idf(fieldName, docFreq);\n    private _avgFieldLength(fieldName);\n}\nexport declare namespace Scorer {\n    interface IDFCache {\n        idfs: Dict<number>;\n        avgFieldLength: number;\n    }\n    interface QueryResult {\n        tf?: number;\n        idf?: number;\n        boost: number;\n        fieldName?: string;\n        term?: number[];\n    }\n    type QueryResults = Map<InvertedIndex.DocumentIndex, QueryResult[]>;\n    interface BM25Explanation {\n        boost: number;\n        score: number;\n        docID: number;\n        fieldName: string;\n        index: string;\n        idf: number;\n        tfNorm: number;\n        tf: number;\n        fieldLength: number;\n        avgFieldLength: number;\n    }\n    interface ConstantExplanation {\n        boost: number;\n        score: number;\n    }\n    type ScoreExplanation = BM25Explanation | ConstantExplanation;\n    type ScoreResult = {\n        score: number;\n        explanation?: ScoreExplanation[];\n    };\n    type ScoreResults = Dict<ScoreResult>;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search-language/src/index.d.ts",
    "content": "export { generateStopWordFilter, generateTrimmer, Among, SnowballProgram } from \"./language\";\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search-language/src/language.d.ts",
    "content": "export declare function generateTrimmer(wordCharacters: string): (token: string) => string;\nexport declare function generateStopWordFilter(stopWords: string[]): (token: string) => string;\nexport declare class Among {\n    s_size: number;\n    s: number[];\n    substring_i: number;\n    result: number;\n    method: any;\n    constructor(s: string, substring_i: number, result: number, method?: any);\n}\nexport declare class SnowballProgram {\n    current: string;\n    bra: number;\n    ket: number;\n    limit: number;\n    cursor: number;\n    limit_backward: number;\n    constructor();\n    setCurrent(word: string): void;\n    getCurrent(): string;\n    in_grouping(s: number[], min: number, max: number): boolean;\n    in_grouping_b(s: number[], min: number, max: number): boolean;\n    out_grouping(s: number[], min: number, max: number): boolean;\n    out_grouping_b(s: number[], min: number, max: number): boolean;\n    eq_s(s_size: number, s: string): boolean;\n    eq_s_b(s_size: number, s: string): boolean;\n    find_among(v: Among[], v_size: number): number;\n    find_among_b(v: Among[], v_size: number): number;\n    replace_s(c_bra: number, c_ket: number, s: string): number;\n    slice_check(): void;\n    slice_from(s: string): void;\n    slice_del(): void;\n    insert(c_bra: number, c_ket: number, s: string): void;\n    slice_to(): string;\n    eq_v_b(s: string): boolean;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search-language-de/src/german_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class GermanAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search-language-de/src/index.d.ts",
    "content": "import { GermanAnalyzer } from \"./german_analyzer\";\nexport { GermanAnalyzer };\nexport default GermanAnalyzer;\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search-language-en/src/english_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class EnglishAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/full-text-search-language-en/src/index.d.ts",
    "content": "import { EnglishAnalyzer } from \"./english_analyzer\";\nexport { EnglishAnalyzer };\nexport default EnglishAnalyzer;\n"
  },
  {
    "path": "dist/packages/full-text-search/types/indexed-storage/src/index.d.ts",
    "content": "import { IndexedStorage } from \"./indexed_storage\";\nexport { IndexedStorage };\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search/types/indexed-storage/src/indexed_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * Loki persistence adapter class for indexedDb.\n *     This class fulfills abstract adapter interface which can be applied to other storage methods.\n *     Utilizes the included LokiCatalog app/key/value database for actual database persistence.\n *     IndexedDb storage is provided per-domain, so we implement app/key/value database to\n *     allow separate contexts for separate apps within a domain.\n */\nexport declare class IndexedStorage implements StorageAdapter {\n    private _appname;\n    private catalog;\n    /**\n     * Registers the indexed storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the indexed storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {string} [appname=loki] - Application name context can be used to distinguish subdomains, \"loki\" by default\n     */\n    constructor(appname?: string);\n    /**\n     * Retrieves a serialized db string from the catalog.\n     *\n     * @example\n     * // LOAD\n     * var idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * var db = new loki(\"test\", { adapter: idbAdapter });\n     *   db.base(function(result) {\n       *   console.log(\"done\");\n       * });\n     *\n     * @param {string} dbname - the name of the database to retrieve.\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<{}>;\n    /**\n     * Saves a serialized db to the catalog.\n     *\n     * @example\n     * // SAVE : will save App/Key/Val as \"finance\"/\"test\"/{serializedDb}\n     * let idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * let db = new loki(\"test\", { adapter: idbAdapter });\n     * let coll = db.addCollection(\"testColl\");\n     * coll.insert({test: \"val\"});\n     * db.saveDatabase();  // could pass callback if needed for async complete\n     *\n     * @param {string} dbname - the name to give the serialized database within the catalog.\n     * @param {string} dbstring - the serialized db string to save.\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a serialized db from the catalog.\n     *\n     * @example\n     * // DELETE DATABASE\n     * // delete \"finance\"/\"test\" value from catalog\n     * idbAdapter.deleteDatabase(\"test\", function {\n       *   // database deleted\n       * });\n     *\n     * @param {string} dbname - the name of the database to delete from the catalog.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n    /**\n     * Removes all database partitions and pages with the base filename passed in.\n     * This utility method does not (yet) guarantee async deletions will be completed before returning\n     *\n     * @param {string} dbname - the base filename which container, partitions, or pages are derived\n     */\n    deleteDatabasePartitions(dbname: string): void;\n    /**\n     * Retrieves object array of catalog entries for current app.\n     *\n     * @example\n     * idbAdapter.getDatabaseList(function(result) {\n       *   // result is array of string names for that appcontext (\"finance\")\n       *   result.forEach(function(str) {\n       *     console.log(str);\n       *   });\n       * });\n     *\n     * @param {function} callback - should accept array of database names in the catalog for current app.\n     */\n    getDatabaseList(callback: (names: string[]) => void): void;\n    /**\n     * Allows retrieval of list of all keys in catalog along with size\n     * @param {function} callback - (Optional) callback to accept result array.\n     */\n    getCatalogSummary(callback: (entry: Entry[]) => void): void;\n}\nexport interface Entry {\n    app: string;\n    key: string;\n    size: number;\n}\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search/types/local-storage/src/index.d.ts",
    "content": "import { LocalStorage } from \"./local_storage\";\nexport { LocalStorage };\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search/types/local-storage/src/local_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists to web browser's local storage object\n * @constructor LocalStorageAdapter\n */\nexport declare class LocalStorage implements StorageAdapter {\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * loadDatabase() - Load data from localstorage\n     * @param {string} dbname - the name of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * saveDatabase() - save data to localstorage, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was saved\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * deleteDatabase() - delete the database from localstorage, will throw an error if it\n     * can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search/types/loki/src/avl_index.d.ts",
    "content": "import { IRangedIndex, IRangedIndexRequest } from \"./ranged_indexes\";\nimport { ILokiComparer } from \"./comparators\";\n/**\n * Treenode type for binary search tree (BST) implementation.\n *\n * To support duplicates, we may need to either repurpose parent to\n * point to 'elder' sibling or add a siblingId to point to owner of\n * node represented in tree.\n */\nexport declare type TreeNode<T> = {\n    id: number;\n    value: T;\n    parent: number | null;\n    balance: number;\n    height: number;\n    left: number | null;\n    right: number | null;\n    siblings: number[];\n};\nexport interface ITreeNodeHash<T> {\n    [id: number]: TreeNode<T>;\n}\n/**\n * LokiDB AVL Balanced Binary Tree Index implementation.\n * To support duplicates, we use siblings (array) in tree nodes.\n * Basic AVL components guided by William Fiset tutorials at :\n * https://github.com/williamfiset/data-structures/blob/master/com/williamfiset/datastructures/balancedtree/AVLTreeRecursive.java\n * https://www.youtube.com/watch?v=g4y2h70D6Nk&list=PLDV1Zeh2NRsD06x59fxczdWLhDDszUHKt\n */\nexport declare class AvlTreeIndex<T> implements IRangedIndex<T> {\n    name: string;\n    comparator: ILokiComparer<T>;\n    nodes: ITreeNodeHash<T>;\n    apex: number | null;\n    /**\n     * Initializes index with property name and a comparer function.\n     */\n    constructor(name: string, comparator: ILokiComparer<T>);\n    backup(): AvlTreeIndex<T>;\n    restore(tree: AvlTreeIndex<T>): void;\n    /**\n     * Used for inserting a new value into the BinaryTreeIndex\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val Value to be indexed and inserted into binary tree\n     */\n    insert(id: number, val: T): void;\n    /**\n     * Recursively inserts a treenode and re-balances if needed.\n     * @param current\n     * @param node\n     */\n    insertNode(current: TreeNode<T>, node: TreeNode<T>): number;\n    /**\n     * Updates height and balance (calculation) for tree node\n     * @param node\n     */\n    private updateBalance(node);\n    /**\n     * Balance the 'double left-heavy' condition\n     * @param node\n     */\n    private leftLeftCase(node);\n    /**\n     * Balance the '(parent) left heavy, (child) right heavy' condition\n     * @param node\n     */\n    private leftRightCase(node);\n    /**\n     * Balance the 'double right-heavy' condition\n     * @param node\n     */\n    private rightRightCase(node);\n    /**\n     * Balance the '(parent) right heavy, (child) left heavy' condition\n     * @param node\n     */\n    private rightLeftCase(node);\n    /**\n     * Left rotation of node. Swaps right child into current location.\n     * @param node\n     */\n    private rotateLeft(node);\n    /**\n     * Right rotation of node. Swaps left child into current location.\n     * @param node\n     */\n    private rotateRight(node);\n    /**\n     * Diagnostic method for examining tree contents and structure\n     * @param node\n     */\n    getValuesAsTree(node?: TreeNode<T>): any;\n    /**\n     * Updates a value, possibly relocating it, within binary tree\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val New value to be indexed within binary tree\n     */\n    update(id: number, val: T): void;\n    /**\n     * Removes a value from the binary tree index\n     * @param id\n     */\n    remove(id: number): void;\n    /**\n     * Recursive node removal and rebalancer\n     * @param node\n     * @param val\n     */\n    private removeNode(node, id);\n    /**\n     * Utility method for updating a parent's child link when it changes\n     * @param parentId\n     * @param oldChildId\n     * @param newChildId\n     */\n    private updateChildLink(parentId, oldChildId, newChildId);\n    /**\n     * When removing a parent with only child, this does simple remap of child to grandParent.\n     * @param grandParent New parent of 'child'.\n     * @param parent Node being removed.\n     * @param child Node to reparent to grandParent.\n     */\n    private promoteChild(parent, child);\n    /**\n     * Finds a successor to a node and replaces that node with it.\n     * @param node\n     */\n    private promoteSuccessor(node);\n    /**\n     * Utility method for finding In-Order predecessor to the provided node\n     * @param node Parent node to find leaf node of greatest 'value'\n    */\n    private findGreaterLeaf(node);\n    /**\n     * Utility method for finding In-Order successor to the provided node\n     * @param node Parent Node to find leaf node of least 'value'\n     */\n    private findLesserLeaf(node);\n    /**\n     *  Interface method to support ranged queries.  Results sorted by index property.\n     * @param range Options for ranged request.\n     */\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    /**\n     * Implements ranged request operations.\n     * @param node\n     * @param range\n     */\n    private collateRequest(node, range);\n    /**\n     * Used on a branch node to return an array of id within that branch, sorted by their value\n     * @param node\n     */\n    private collateIds(node);\n    /**\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    /**\n     * Inline/Non-recusive 'single value' ($eq) lookup.\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    private locate(node, val);\n    /**\n     * Index integrity check (IRangedIndex interface function)\n     */\n    validateIndex(): boolean;\n    /**\n     * Recursive Node validation routine\n     * @param node\n     */\n    private validateNode(node);\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/loki/src/clone.d.ts",
    "content": "export declare type CloneMethod = \"parse-stringify\" | \"deep\" | \"shallow\" | \"shallow-recurse\";\n/**\n * @hidden\n */\nexport declare function clone<T>(data: T, method?: CloneMethod): T;\n"
  },
  {
    "path": "dist/packages/full-text-search/types/loki/src/collection.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { UniqueIndex } from \"./unique_index\";\nimport { ResultSet } from \"./result_set\";\nimport { DynamicView } from \"./dynamic_view\";\nimport { IRangedIndex } from \"./ranged_indexes\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc, Dict } from \"../../common/types\";\nimport { FullTextSearch } from \"../../full-text-search/src/full_text_search\";\nimport { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\n/**\n * Collection class that handles documents of same type\n * @extends LokiEventEmitter\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class Collection<TData extends object = object, TNested extends object = object, T extends TData & TNested = TData & TNested> extends LokiEventEmitter {\n    name: string;\n    _data: Doc<T>[];\n    private _idIndex;\n    _rangedIndexes: {\n        [P in keyof T]?: Collection.RangedIndexMeta;\n    };\n    _lokimap: {\n        [$loki: number]: Doc<T>;\n    };\n    _unindexedSortComparator: string;\n    _defaultLokiOperatorPackage: string;\n    /**\n     * Unique constraints contain duplicate object references, so they are not persisted.\n     * We will keep track of properties which have unique constraints applied here, and regenerate on load.\n     */\n    _constraints: {\n        unique: {\n            [P in keyof T]?: UniqueIndex;\n        };\n    };\n    /**\n     * Transforms will be used to store frequently used query chains as a series of steps which itself can be stored along\n     * with the database.\n     */\n    _transforms: Dict<Collection.Transform<T>[]>;\n    /**\n     * In autosave scenarios we will use collection level dirty flags to determine whether save is needed.\n     * currently, if any collection is dirty we will autosave the whole database if autosave is configured.\n     * Defaulting to true since this is called from addCollection and adding a collection should trigger save.\n     */\n    _dirty: boolean;\n    private _cached;\n    /**\n     * Is collection transactional.\n     */\n    private _transactional;\n    /**\n     * Options to clone objects when inserting them.\n     */\n    _cloneObjects: boolean;\n    /**\n     * Default clone method (if enabled) is parse-stringify.\n     */\n    _cloneMethod: CloneMethod;\n    /**\n     * If set to true we will not maintain a meta property for a document.\n     */\n    private _disableMeta;\n    /**\n     * Disable track changes.\n     */\n    private _disableChangesApi;\n    /**\n     * Disable delta update object style on changes.\n     */\n    _disableDeltaChangesApi: boolean;\n    /**\n     * By default, if you insert a document with a Date value for an indexed property, we will convert that value to number.\n     */\n    private _serializableIndexes;\n    /**\n     * Name of path of used nested properties.\n     */\n    private _nestedProperties;\n    /**\n     * Option to activate a cleaner daemon - clears \"aged\" documents at set intervals.\n     */\n    _ttl: Collection.TTL;\n    private _maxId;\n    private _dynamicViews;\n    /**\n     * Changes are tracked by collection and aggregated by the db.\n     */\n    private _changes;\n    /**\n     * stages: a map of uniquely identified 'stages', which hold copies of objects to be\n     * manipulated without affecting the data in the original collection\n     */\n    private _stages;\n    private _commitLog;\n    _fullTextSearch: FullTextSearch;\n    /**\n     * @param {string} name - collection name\n     * @param {(object)} [options={}] - a configuration object\n     * @param {string[]} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {string[]} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {RangedIndexOptions} [options.rangedIndexes] - configuration object for ranged indexes\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are invoked asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes API\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {boolean} [options.serializableIndexes=true] - converts date values on binary indexed property values are serializable\n     * @param {string} [options.cloneMethod=\"deep\"] - the clone method\n     * @param {number} [options.transactional=false] - ?\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale.\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @param {string} [options.unindexedSortComparator=\"js\"] \"js\", \"abstract\", \"abstract-date\", \"loki\" or other registered comparator name\n     * @param {string} [options.defaultLokiOperatorPackage=\"js\"] \"js\", \"loki\", \"comparator\" (or user defined) query ops package\n     * @param {FullTextSearch.FieldOptions} [options.fullTextSearch=] - the full-text search options\n     * @see {@link Loki#addCollection} for normal creation of collections\n     */\n    constructor(name: string, options?: Collection.Options<TData, TNested>);\n    toJSON(): Collection.Serialized;\n    static fromJSONObject(obj: Collection.Serialized, options?: Collection.DeserializeOptions): Collection<any, object, any>;\n    /**\n     * Adds a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {array} transform - an array of transformation 'step' objects to save into the collection\n     */\n    addTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Retrieves a named transform from the collection.\n     * @param {string} name - name of the transform to lookup.\n     */\n    getTransform(name: string): Collection.Transform<T>[];\n    /**\n     * Updates a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {object} transform - a transformation object to save into collection\n     */\n    setTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Removes a named collection transform from the collection\n     * @param {string} name - name of collection transform to remove\n     */\n    removeTransform(name: string): void;\n    private setTTL(age, interval);\n    /**\n     * Create a row filter that covers all documents in the collection.\n     */\n    _prepareFullDocIndex(): number[];\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field\n     * @param indexTypeName\n     * @param comparatorName\n     */\n    ensureIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field Property to create an index on (need to look into contraining on keyof T)\n     * @param indexTypeName Name of IndexType factory within (global?) hashmap to create IRangedIndex from\n     * @param comparatorName Name of Comparator within (global?) hashmap\n     */\n    ensureRangedIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    ensureUniqueIndex(field: keyof T): UniqueIndex;\n    /**\n     * Quickly determine number of documents in collection (or query)\n     * @param {object} query - (optional) query object to count results of\n     * @returns {number} number of documents in the collection\n     */\n    count(query?: ResultSet.Query<Doc<T>>): number;\n    /**\n     * Rebuild idIndex\n     */\n    private _ensureId();\n    /**\n     * Add a dynamic view to the collection\n     * @param {string} name - name of dynamic view to add\n     * @param {object} options - (optional) options to configure dynamic view with\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=SortPriority.PASSIVE] - the sort priority\n     * @param {number} options.minRebuildInterval - minimum rebuild interval (need clarification to docs here)\n     * @returns {DynamicView} reference to the dynamic view added\n     **/\n    addDynamicView(name: string, options?: DynamicView.Options): DynamicView<T>;\n    /**\n     * Remove a dynamic view from the collection\n     * @param {string} name - name of dynamic view to remove\n     **/\n    removeDynamicView(name: string): void;\n    /**\n     * Look up dynamic view reference from within the collection\n     * @param {string} name - name of dynamic view to retrieve reference of\n     * @returns {DynamicView} A reference to the dynamic view with that name\n     **/\n    getDynamicView(name: string): DynamicView<T>;\n    /**\n     * Applies a 'mongo-like' find query object and passes all results to an update function.\n     * @param {object} filterObject - the 'mongo-like' query object\n     * @param {function} updateFunction - the update function\n     */\n    findAndUpdate(filterObject: ResultSet.Query<Doc<T>>, updateFunction: (obj: Doc<T>) => any): void;\n    /**\n     * Applies a 'mongo-like' find query object removes all documents which match that filter.\n     * @param {object} filterObject - 'mongo-like' query object\n     */\n    findAndRemove(filterObject: ResultSet.Query<Doc<T>>): void;\n    /**\n     * Adds object(s) to collection, ensure object(s) have meta properties, clone it if necessary, etc.\n     * @param {(object|array)} doc - the document (or array of documents) to be inserted\n     * @returns {(object|array)} document or documents inserted\n     */\n    insert(doc: TData): Doc<T>;\n    insert(doc: TData[]): Doc<T>[];\n    /**\n     * Adds a single object, ensures it has meta properties, clone it if necessary, etc.\n     * @param {object} doc - the document to be inserted\n     * @param {boolean} bulkInsert - quiet pre-insert and insert event emits\n     * @returns {object} document or 'undefined' if there was a problem inserting it\n     */\n    insertOne(doc: TData, bulkInsert?: boolean): Doc<T>;\n    /**\n     * Refers nested properties of an object to the root of it.\n     * @param {T} data - the object\n     * @returns {T & TNested} the object with nested properties\n     * @hidden\n     */\n    _defineNestedProperties<U extends TData>(data: U): U & TNested;\n    /**\n     * Empties the collection.\n     * @param {boolean} [removeIndices=false] - remove indices\n     */\n    clear({removeIndices: removeIndices}?: {\n        removeIndices?: boolean;\n    }): void;\n    /**\n     * Updates an object and notifies collection that the document has changed.\n     * @param {object} doc - document to update within the collection\n     */\n    update(doc: Doc<T> | Doc<T>[]): void;\n    /**\n     * Add object to collection\n     */\n    private _add(obj);\n    /**\n     * Applies a filter function and passes all results to an update function.\n     * @param {function} filterFunction - the filter function\n     * @param {function} updateFunction - the update function\n     */\n    updateWhere(filterFunction: (obj: Doc<T>) => boolean, updateFunction: (obj: Doc<T>) => Doc<T>): void;\n    /**\n     * Remove all documents matching supplied filter function.\n     * @param {function} filterFunction - the filter function\n     */\n    removeWhere(filterFunction: (obj: Doc<T>) => boolean): void;\n    removeDataOnly(): void;\n    /**\n     * Remove a document from the collection\n     * @param {number|object} doc - document to remove from collection\n     */\n    remove(doc: number | Doc<T> | Doc<T>[]): void;\n    /**\n     * Returns all changes.\n     * @returns {Collection.Change[]}\n     */\n    getChanges(): Collection.Change[];\n    /**\n     * Enables/disables changes api.\n     * @param {boolean} disableChangesApi\n     * @param {boolean} disableDeltaChangesApi\n     */\n    setChangesApi(disableChangesApi: boolean, disableDeltaChangesApi?: boolean): void;\n    /**\n     * Clears all the changes.\n     */\n    flushChanges(): void;\n    private _getObjectDelta(oldObject, newObject);\n    /**\n     * Compare changed object (which is a forced clone) with existing object and return the delta\n     */\n    private _getChangeDelta(obj, old);\n    /**\n     * Creates a clone of the current status of an object and associates operation and collection name,\n     * so the parent db can aggregate and generate a changes object for the entire db\n     */\n    private _createChange(name, op, obj, old?);\n    private _createInsertChange(obj);\n    private _createUpdateChange(obj, old);\n    private _insertMetaWithChange(obj);\n    private _updateMetaWithChange(obj, old);\n    private _insertMeta(obj);\n    private _updateMeta(obj);\n    /**\n     * Get by Id - faster than other methods because of the searching algorithm\n     * @param {int} id - $loki id of document you want to retrieve\n     * @param {boolean} returnPosition - if 'true' we will return [object, position]\n     * @returns {(object|array|null)} Object reference if document was found, null if not,\n     *     or an array if 'returnPosition' was passed.\n     */\n    get(id: number): Doc<T>;\n    get(id: number, returnPosition: boolean): Doc<T> | [Doc<T>, number];\n    /**\n     * Retrieve doc by Unique index\n     * @param {string} field - name of uniquely indexed property to use when doing lookup\n     * @param {any} value - unique value to search for\n     * @returns {object} document matching the value passed\n     */\n    by(field: keyof T, value: any): Doc<T>;\n    /**\n     * Find one object by index property, by property equal to value\n     * @param {object} query - query object used to perform search with\n     * @returns {(object|null)} First matching document, or null if none\n     */\n    findOne(query: ResultSet.Query<Doc<T>>): Doc<T>;\n    /**\n     * Chain method, used for beginning a series of chained find() and/or view() operations\n     * on a collection.\n     *\n     * @param {array} transform - Ordered array of transform step objects similar to chain\n     * @param {object} parameters - Object containing properties representing parameters to substitute\n     * @returns {ResultSet} (this) ResultSet, or data array if any map or join functions where called\n     */\n    chain(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Find method, api is similar to mongodb.\n     * for more complex queries use [chain()]{@link Collection#chain} or [where()]{@link Collection#where}.\n     * @example {@tutorial Query Examples}\n     * @param {object} query - 'mongo-like' query object\n     * @returns {array} Array of matching documents\n     */\n    find(query?: ResultSet.Query<Doc<T>>): Doc<T>[];\n    /**\n     * Find object by unindexed field by property equal to value,\n     * simply iterates and returns the first element matching the query\n     */\n    findOneUnindexed(prop: string, value: any): Doc<T>;\n    /**\n     * Transaction methods\n     */\n    /**\n     * start the transation\n     */\n    startTransaction(): void;\n    /**\n     * Commit the transaction.\n     */\n    commit(): void;\n    /**\n     * Rollback the transaction.\n     */\n    rollback(): void;\n    /**\n     * Query the collection by supplying a javascript filter function.\n     * @example\n     * let results = coll.where(function(obj) {\n       *   return obj.legs === 8;\n       * });\n     * @param {function} fun - filter function to run against all collection docs\n     * @returns {array} all documents which pass your filter function\n     */\n    where(fun: (obj: Doc<T>) => boolean): Doc<T>[];\n    /**\n     * Map Reduce operation\n     * @param {function} mapFunction - function to use as map function\n     * @param {function} reduceFunction - function to use as reduce function\n     * @returns {data} The result of your mapReduce operation\n     */\n    mapReduce<U1, U2>(mapFunction: (value: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Join two collections on specified properties\n     * @param {array} joinData - array of documents to 'join' to this collection\n     * @param {string} leftJoinProp - property name in collection\n     * @param {string} rightJoinProp - property name in joinData\n     * @param {function} mapFun - (Optional) map function to use\n     * @param dataOptions - options to data() before input to your map function\n     * @param [dataOptions.removeMeta] - allows removing meta before calling mapFun\n     * @param [dataOptions.forceClones] - forcing the return of cloned objects to your map object\n     * @param [dataOptions.forceCloneMethod] - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} Result of the mapping operation\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinProp: string | ((obj: any) => string), rightJoinProp: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * (Staging API) create a stage and/or retrieve it\n     */\n    getStage(name: string): any;\n    /**\n     * a collection of objects recording the changes applied through a commmitStage\n     */\n    /**\n     * (Staging API) create a copy of an object and insert it into a stage\n     */\n    stage<F extends TData>(stageName: string, obj: Doc<F>): F;\n    /**\n     * (Staging API) re-attach all objects to the original collection, so indexes and views can be rebuilt\n     * then create a message to be inserted in the commitlog\n     * @param {string} stageName - name of stage\n     * @param {string} message\n     */\n    commitStage(stageName: string, message: string): void;\n    /**\n     * Returns all values of a field.\n     * @param {string} field - the field name\n     * @return {any}: the array of values\n     */\n    extract(field: keyof T): any[];\n    /**\n     * Finds the minimum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the minimum value\n     */\n    min(field: keyof T): number;\n    /**\n     * Finds the maximum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the maximum value\n     */\n    max(field: keyof T): number;\n    /**\n     * Finds the minimum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    minRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Finds the maximum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    maxRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Returns all values of a field as numbers (if possible).\n     * @param {string} field - the field name\n     * @return {number[]} - the number array\n     */\n    extractNumerical(field: keyof T): number[];\n    /**\n     * Calculates the average numerical value of a field\n     * @param {string} field - the field name\n     * @returns {number} average of property in all docs in the collection\n     */\n    avg(field: keyof T): number;\n    /**\n     * Calculate the standard deviation of a field.\n     * @param {string} field - the field name\n     * @return {number} the standard deviation\n     */\n    stdDev(field: keyof T): number;\n    /**\n     * Calculates the mode of a field.\n     * @param {string} field - the field name\n     * @return {number} the mode\n     */\n    mode(field: keyof T): number;\n    /**\n     * Calculates the median of a field.\n     * @param {string} field - the field name\n     * @return {number} the median\n     */\n    median(field: keyof T): number;\n}\nexport declare namespace Collection {\n    interface Options<TData extends object, TNested extends object = {}, T extends object = TData & TNested> {\n        unique?: (keyof T)[];\n        unindexedSortComparator?: string;\n        defaultLokiOperatorPackage?: string;\n        rangedIndexes?: RangedIndexOptions;\n        serializableIndexes?: boolean;\n        asyncListeners?: boolean;\n        disableMeta?: boolean;\n        disableChangesApi?: boolean;\n        disableDeltaChangesApi?: boolean;\n        clone?: boolean;\n        serializableIndices?: boolean;\n        cloneMethod?: CloneMethod;\n        transactional?: boolean;\n        ttl?: number;\n        ttlInterval?: number;\n        nestedProperties?: (keyof TNested | {\n            name: keyof TNested;\n            path: string[];\n        })[];\n        fullTextSearch?: FullTextSearch.FieldOptions[];\n    }\n    interface RangedIndexOptions {\n        [prop: string]: RangedIndexMeta;\n    }\n    interface DeserializeOptions {\n        retainDirtyFlags?: boolean;\n        fullTextSearch?: Dict<Analyzer>;\n        [collName: string]: any | {\n            proto?: any;\n            inflate?: (src: object, dest?: object) => void;\n        };\n    }\n    interface BinaryIndex {\n        dirty: boolean;\n        values: any;\n    }\n    interface RangedIndexMeta {\n        index?: IRangedIndex<any>;\n        indexTypeName?: string;\n        comparatorName?: string;\n    }\n    interface Change {\n        name: string;\n        operation: string;\n        obj: any;\n    }\n    interface Serialized {\n        name: string;\n        unindexedSortComparator: string;\n        defaultLokiOperatorPackage: string;\n        _dynamicViews: DynamicView[];\n        _nestedProperties: {\n            name: string;\n            path: string[];\n        }[];\n        uniqueNames: string[];\n        transforms: Dict<Transform[]>;\n        rangedIndexes: RangedIndexOptions;\n        _data: Doc<any>[];\n        idIndex: number[];\n        maxId: number;\n        _dirty: boolean;\n        transactional: boolean;\n        asyncListeners: boolean;\n        disableMeta: boolean;\n        disableChangesApi: boolean;\n        disableDeltaChangesApi: boolean;\n        cloneObjects: boolean;\n        cloneMethod: CloneMethod;\n        changes: any;\n        _fullTextSearch: FullTextSearch;\n    }\n    interface CheckIndexOptions {\n        randomSampling?: boolean;\n        randomSamplingFactor?: number;\n        repair?: boolean;\n    }\n    type Transform<T extends object = object> = {\n        type: \"find\";\n        value: ResultSet.Query<Doc<T>> | string;\n    } | {\n        type: \"where\";\n        value: ((obj: Doc<T>) => boolean) | string;\n    } | {\n        type: \"simplesort\";\n        property: keyof T;\n        options?: boolean | ResultSet.SimpleSortOptions;\n    } | {\n        type: \"compoundsort\";\n        value: (keyof T | [keyof T, boolean])[];\n    } | {\n        type: \"sort\";\n        value: (a: Doc<T>, b: Doc<T>) => number;\n    } | {\n        type: \"sortByScoring\";\n        desc?: boolean;\n    } | {\n        type: \"limit\";\n        value: number;\n    } | {\n        type: \"offset\";\n        value: number;\n    } | {\n        type: \"map\";\n        value: (obj: Doc<T>, index: number, array: Doc<T>[]) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"eqJoin\";\n        joinData: Collection<any> | ResultSet<any>;\n        leftJoinKey: string | ((obj: any) => string);\n        rightJoinKey: string | ((obj: any) => string);\n        mapFun?: (left: any, right: any) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"mapReduce\";\n        mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => any;\n        reduceFunction: (array: any[]) => any;\n    } | {\n        type: \"update\";\n        value: (obj: Doc<T>) => any;\n    } | {\n        type: \"remove\";\n    };\n    interface TTL {\n        age: number;\n        ttlInterval: number;\n        daemon: any;\n    }\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/loki/src/comparators.d.ts",
    "content": "export interface ILokiComparer<T> {\n    (a: T, b: T): -1 | 0 | 1;\n}\nexport interface IComparatorMap {\n    [name: string]: ILokiComparer<any>;\n}\n/** Map/Register of named ILokiComparer functions returning -1, 0, 1 for lt/eq/gt assertions for two passed parameters */\nexport declare let ComparatorMap: IComparatorMap;\n/** Typescript-friendly factory for strongly typed 'js' comparators */\nexport declare function CreateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'abstract js' comparators */\nexport declare function CreateAbstractJavascriptComparator<T>(): ILokiComparer<T>;\n/**\n * Comparator which attempts to deal with deal with dates at comparator level.\n * Should work for dates in any of the object, string, and number formats\n */\nexport declare function CreateAbstractDateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'loki' comparators */\nexport declare function CreateLokiComparator(): ILokiComparer<any>;\n"
  },
  {
    "path": "dist/packages/full-text-search/types/loki/src/dynamic_view.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { ResultSet } from \"./result_set\";\nimport { Collection } from \"./collection\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\n/**\n * DynamicView class is a versatile 'live' view class which can have filters and sorts applied.\n *    Collection.addDynamicView(name) instantiates this DynamicView object and notifies it\n *    whenever documents are add/updated/removed so it can remain up-to-date. (chainable)\n *\n * @example\n * let mydv = mycollection.addDynamicView('test');  // default is non-persistent\n * mydv.applyFind({ 'doors' : 4 });\n * mydv.applyWhere(function(obj) { return obj.name === 'Toyota'; });\n * let results = mydv.data();\n *\n * @extends LokiEventEmitter\n\n * @see {@link Collection#addDynamicView} to construct instances of DynamicView\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class DynamicView<T extends object = object> extends LokiEventEmitter {\n    readonly name: string;\n    private _collection;\n    private _persistent;\n    private _sortPriority;\n    private _minRebuildInterval;\n    private _rebuildPending;\n    private _resultSet;\n    private _resultData;\n    private _resultDirty;\n    private _cachedResultSet;\n    private _filterPipeline;\n    private _sortFunction;\n    private _sortCriteria;\n    private _sortCriteriaSimple;\n    private _sortByScoring;\n    private _sortDirty;\n    /**\n     * Constructor.\n     * @param {Collection} collection - a reference to the collection to work agains\n     * @param {string} name - the name of this dynamic view\n     * @param {object} options - the options\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=\"passive\"] - the sort priority\n     * @param {number} [options.minRebuildInterval=1] - minimum rebuild interval (need clarification to docs here)\n     */\n    constructor(collection: Collection<T>, name: string, options?: DynamicView.Options);\n    /**\n     * Internally used immediately after deserialization (loading)\n     *    This will clear out and reapply filterPipeline ops, recreating the view.\n     *    Since where filters do not persist correctly, this method allows\n     *    restoring the view to state where user can re-apply those where filters.\n     *\n     * @param removeWhereFilters\n     * @returns {DynamicView} This dynamic view for further chained ops.\n     * @fires DynamicView.rebuild\n     */\n    private _rematerialize({removeWhereFilters});\n    /**\n     * Makes a copy of the internal ResultSet for branched queries.\n     * Unlike this dynamic view, the branched ResultSet will not be 'live' updated,\n     * so your branched query should be immediately resolved and not held for future evaluation.\n     * @param {(string|array=)} transform - Optional name of collection transform, or an array of transform steps\n     * @param {object} parameters - optional parameters (if optional transform requires them)\n     * @returns {ResultSet} A copy of the internal ResultSet for branched queries.\n     */\n    branchResultSet(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Override of toJSON to avoid circular references.\n     */\n    toJSON(): DynamicView.Serialized;\n    static fromJSONObject(collection: Collection, obj: DynamicView.Serialized): DynamicView;\n    /**\n     * Used to clear pipeline and reset dynamic view to initial state.\n     * Existing options should be retained.\n     * @param {boolean} queueSortPhase - (default: false) if true we will async rebuild view (maybe set default to true in future?)\n     */\n    removeFilters({queueSortPhase}?: {\n        queueSortPhase?: boolean;\n    }): void;\n    /**\n     * Used to apply a sort to the dynamic view\n     * @example\n     * dv.applySort(function(obj1, obj2) {\n       *   if (obj1.name === obj2.name) return 0;\n       *   if (obj1.name > obj2.name) return 1;\n       *   if (obj1.name < obj2.name) return -1;\n       * });\n     * @param {function} comparefun - a javascript compare function used for sorting\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applySort(comparefun: (lhs: Doc<T>, rhs: Doc<T>) => number): this;\n    /**\n     * Used to specify a property used for view translation.\n     * @param {string} field - the field name\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether we should sort descending.\n     * @param {boolean} [options.disableIndexIntersect=false] - whether we should explicity not use array intersection.\n     * @param {boolean} [options.forceIndexIntersect=false] - force array intersection (if binary index exists).\n     * @param {boolean} [options.useJavascriptSorting=false] - whether results are sorted via basic javascript sort.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     * @example\n     * dv.applySimpleSort(\"name\");\n     */\n    applySimpleSort(field: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @param {Array} criteria - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {DynamicView} Reference to this DynamicView, sorted, for future chain operations.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * dv.applySortCriteria(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * dv.applySortCriteria(['age', ['name', true]]);\n     * // to sort by age (descending) and then by name (descending)\n     * dv.applySortCriteria([['age', true], ['name', true]]);\n     */\n    applySortCriteria(criteria: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Used to apply a sort by the latest full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     */\n    applySortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Marks the beginning of a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    startTransaction(): this;\n    /**\n     * Commits a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    commit(): this;\n    /**\n     * Rolls back a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    rollback(): this;\n    /**\n     * Find the index of a filter in the pipeline, by that filter's ID.\n     * @param {(string|number)} uid - The unique ID of the filter.\n     * @returns {number}: index of the referenced filter in the pipeline; -1 if not found.\n     */\n    private _indexOfFilterWithId(uid);\n    /**\n     * Add the filter object to the end of view's filter pipeline and apply the filter to the ResultSet.\n     * @param {object} filter - The filter object. Refer to applyFilter() for extra details.\n     */\n    private _addFilter(filter);\n    /**\n     * Reapply all the filters in the current pipeline.\n     *\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    reapplyFilters(): this;\n    /**\n     * Adds or updates a filter in the DynamicView filter pipeline\n     * @param {object} filter - A filter object to add to the pipeline.\n     *    The object is in the format { 'type': filter_type, 'val', filter_param, 'uid', optional_filter_id }\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFilter(filter: DynamicView.Filter<T>): this;\n    /**\n     * applyFind() - Adds or updates a mongo-style query option in the DynamicView filter pipeline\n     *\n     * @param {object} query - A mongo-style query object to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFind(query: object, uid?: string | number): this;\n    /**\n     * Adds or updates a javascript filter function in the DynamicView filter pipeline\n     * @param {function} fun - A javascript filter function to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyWhere(fun: (obj: Doc<T>) => boolean, uid?: string | number): this;\n    /**\n     * Remove the specified filter from the DynamicView filter pipeline\n     * @param {(string|number)} uid - The unique ID of the filter to be removed.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    removeFilter(uid: string | number): this;\n    /**\n     * Returns the number of documents representing the current DynamicView contents.\n     * @returns {number} The number of documents representing the current DynamicView contents.\n     */\n    count(): number;\n    /**\n     * Resolves and pending filtering and sorting, then returns document array as result.\n     * @param {object} options - optional parameters to pass to ResultSet.data() if non-persistent\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values include 'parse-stringify', 'jquery-extend-deep', 'shallow', 'shallow-assign'\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} An array of documents representing the current DynamicView contents.\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * When the view is not sorted we may still wish to be notified of rebuild events.\n     * This event will throttle and queue a single rebuild event when batches of updates affect the view.\n     */\n    private _queueRebuildEvent();\n    /**\n     * If the view is sorted we will throttle sorting to either :\n     * (1) passive - when the user calls data(), or\n     * (2) active - once they stop updating and yield js thread control\n     */\n    private _queueSortPhase();\n    /**\n     * Invoked synchronously or asynchronously to perform final sort phase (if needed)\n     */\n    private _performSortPhase(options?);\n    /**\n     * (Re)evaluating document inclusion.\n     * Called by : collection.insert() and collection.update().\n     * @param {int} objIndex - index of document to (re)run through filter pipeline.\n     * @param {boolean} isNew - true if the document was just added to the collection.\n     * @hidden\n     */\n    _evaluateDocument(objIndex: number, isNew: boolean): void;\n    /**\n     * Internal function called on collection.delete().\n     * @hidden\n     */\n    _removeDocument(objIndex: number): void;\n    /**\n     * Data transformation via user supplied functions\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: T, index: number, array: T[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n}\nexport declare namespace DynamicView {\n    interface Options {\n        persistent?: boolean;\n        sortPriority?: SortPriority;\n        minRebuildInterval?: number;\n    }\n    type SortPriority = \"passive\" | \"active\";\n    interface Serialized {\n        name: string;\n        _persistent: boolean;\n        _sortPriority: SortPriority;\n        _minRebuildInterval: number;\n        _resultSet: ResultSet<any>;\n        _filterPipeline: Filter<any>[];\n        _sortCriteria: (string | [string, boolean])[];\n        _sortCriteriaSimple: {\n            field: string;\n            options: boolean | ResultSet.SimpleSortOptions;\n        };\n        _sortByScoring: boolean;\n        _sortDirty: boolean;\n    }\n    type Filter<T extends object = object> = {\n        type: \"find\";\n        val: ResultSet.Query<Doc<T>>;\n        uid: number | string;\n    } | {\n        type: \"where\";\n        val: (obj: Doc<T>) => boolean;\n        uid: number | string;\n    };\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/loki/src/event_emitter.d.ts",
    "content": "/**\n * LokiEventEmitter is a minimalist version of EventEmitter. It enables any\n * constructor that inherits EventEmitter to emit events and trigger\n * listeners that have been added to the event through the on(event, callback) method\n *\n * @constructor LokiEventEmitter\n */\nexport declare class LokiEventEmitter {\n    /**\n     * A map, with each property being an array of callbacks.\n     */\n    protected _events: object;\n    /**\n     * Determines whether or not the callbacks associated with each event should happen in an async fashion or not.\n     * Default is false, which means events are synchronous\n     */\n    protected _asyncListeners: boolean;\n    /**\n     * Adds a listener to the queue of callbacks associated to an event\n     * @param {string|string[]} eventName - the name(s) of the event(s) to listen to\n     * @param {function} listener - callback function of listener to attach\n     * @returns {int} the index of the callback in the array of listeners for a particular event\n     */\n    on(eventName: string | string[], listener: Function): Function;\n    /**\n     * Emits a particular event\n     * with the option of passing optional parameters which are going to be processed by the callback\n     * provided signatures match (i.e. if passing emit(event, arg0, arg1) the listener should take two parameters)\n     * @param {string} eventName - the name of the event\n     * @param {object} data - optional object passed with the event\n     */\n    protected emit(eventName: string, ...data: any[]): void;\n    /**\n     * Alias of EventEmitter.on().\n     */\n    addListener(eventName: string | string[], listener: Function): Function;\n    /**\n     * Removes the listener at position 'index' from the event 'eventName'\n     * @param {string|string[]} eventName - the name(s) of the event(s) which the listener is attached to\n     * @param {function} listener - the listener callback function to remove from emitter\n     */\n    removeListener(eventName: string | string[], listener: Function): void;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/loki/src/index.d.ts",
    "content": "import { Loki } from \"./loki\";\nimport { Collection } from \"./collection\";\nexport { Loki, Collection };\nexport default Loki;\n"
  },
  {
    "path": "dist/packages/full-text-search/types/loki/src/loki.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { Collection } from \"./collection\";\nimport { Doc, StorageAdapter } from \"../../common/types\";\nimport { IComparatorMap } from \"./comparators\";\nimport { IRangedIndexFactoryMap } from \"./ranged_indexes\";\nimport { ILokiOperatorPackageMap } from \"./operator_packages\";\nexport declare class Loki extends LokiEventEmitter {\n    filename: string;\n    private databaseVersion;\n    private engineVersion;\n    _collections: Collection[];\n    private _env;\n    private _serializationMethod;\n    private _destructureDelimiter;\n    private _persistenceMethod;\n    private _persistenceAdapter;\n    private _throttledSaves;\n    private _throttledSaveRunning;\n    private _throttledSavePending;\n    private _autosave;\n    private _autosaveInterval;\n    private _autosaveRunning;\n    private _autosaveHandler;\n    /**\n     * Constructs the main database class.\n     * @param {string} filename - name of the file to be saved to\n     * @param {object} [options={}] - options\n     * @param {Loki.Environment} [options.env] - the javascript environment\n     * @param {Loki.SerializationMethod} [options.serializationMethod=NORMAL] - the serialization method\n     * @param {string} [options.destructureDelimiter=\"$<\\n\"] - string delimiter used for destructured serialization\n     * @param {IComparatorMap} [options.comparatorMap] allows injecting or overriding registered comparators\n     * @param {IRangedIndexFactoryMap} [options.rangedIndexFactoryMap] allows injecting or overriding registered ranged index factories\n     * @param {ILokiOperatorPackageMap} [options.lokiOperatorPackageMap] allows injecting or overriding registered loki operator packages\n     */\n    constructor(filename?: string, options?: Loki.Options);\n    /**\n     * configures options related to database persistence.\n     *\n     * @param {Loki.PersistenceOptions} [options={}] - options\n     * @param {adapter} [options.adapter=auto] - an instance of a loki persistence adapter\n     * @param {boolean} [options.autosave=false] - enables autosave\n     * @param {int} [options.autosaveInterval=5000] - time interval (in milliseconds) between saves (if dirty)\n     * @param {boolean} [options.autoload=false] - enables autoload on loki instantiation\n     * @param {object} options.inflate - options that are passed to loadDatabase if autoload enabled\n     * @param {boolean} [options.throttledSaves=true] - if true, it batches multiple calls to to saveDatabase reducing number of\n     *   disk I/O operations and guaranteeing proper serialization of the calls. Default value is true.\n     * @param {Loki.PersistenceMethod} options.persistenceMethod - a persistence method which should be used (FS_STORAGE, LOCAL_STORAGE...)\n     * @returns {Promise} a Promise that resolves after initialization and (if enabled) autoloading the database\n     */\n    initializePersistence(options?: Loki.PersistenceOptions): Promise<void>;\n    /**\n     * Copies 'this' database into a new Loki instance. Object references are shared to make lightweight.\n     * @param {object} options - options\n     * @param {boolean} options.removeNonSerializable - nulls properties not safe for serialization.\n     */\n    copy(options?: Loki.CopyOptions): Loki;\n    /**\n     * Adds a collection to the database.\n     * @param {string} name - name of collection to add\n     * @param {object} [options={}] - options to configure collection with.\n     * @param {array} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {array} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {array} [options.indices=[]] - array property names to define binary indexes for\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are called asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes Api\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {string} [options.cloneMethod=CloneMethod.DEEP] - the clone method\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @returns {Collection} a reference to the collection which was just added\n     */\n    addCollection<TData extends object = object, TNested extends object = object>(name: string, options?: Collection.Options<TData, TNested>): Collection<TData, TNested>;\n    loadCollection(collection: Collection): void;\n    /**\n     * Retrieves reference to a collection by name.\n     * @param {string} name - name of collection to look up\n     * @returns {Collection} Reference to collection in database by that name, or null if not found\n     */\n    getCollection<TData extends object = object, TNested extends object = object>(name: string): Collection<TData, TNested>;\n    /**\n     * Renames an existing loki collection\n     * @param {string} oldName - name of collection to rename\n     * @param {string} newName - new name of collection\n     * @returns {Collection} reference to the newly renamed collection\n     */\n    renameCollection<TData extends object = object, TNested extends object = object>(oldName: string, newName: string): Collection<TData, TNested>;\n    listCollections(): {\n        name: string;\n        count: number;\n    }[];\n    /**\n     * Removes a collection from the database.\n     * @param {string} collectionName - name of collection to remove\n     */\n    removeCollection(collectionName: string): void;\n    /**\n     * Serialize database to a string which can be loaded via {@link Loki#loadJSON}\n     *\n     * @returns {string} Stringified representation of the loki database.\n     */\n    serialize(options?: Loki.SerializeOptions): string | string[];\n    toJSON(): Loki.Serialized;\n    /**\n     * Database level destructured JSON serialization routine to allow alternate serialization methods.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {object} options - output format options for use externally to loki\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to only output an individual collection or db (-1)\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {string|Array} A custom, restructured aggregation of independent serializations.\n     */\n    serializeDestructured(options?: Loki.SerializeDestructuredOptions): string | string[];\n    /**\n     * Collection level utility method to serialize a collection in a 'destructured' format\n     *\n     * @param {object} options - used to determine output of method\n     * @param {int} options.delimited - whether to return single delimited string or an array\n     * @param {string} options.delimiter - (optional) if delimited, this is delimiter to use\n     * @param {int} options.collectionIndex -  specify which collection to serialize data for\n     *\n     * @returns {string|array} A custom, restructured aggregation of independent serializations for a single collection.\n     */\n    serializeCollection(options?: {\n        delimited?: boolean;\n        collectionIndex?: number;\n        delimiter?: string;\n    }): string | string[];\n    /**\n     * Database level destructured JSON deserialization routine to minimize memory overhead.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {string|array} destructuredSource - destructured json or array to deserialize from\n     * @param {object} options - source format options\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to deserialize only a single partition\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {object|array} An object representation of the deserialized database, not yet applied to 'this' db or document array\n     */\n    deserializeDestructured(destructuredSource: string | string[], options?: Loki.SerializeDestructuredOptions): any;\n    /**\n     * Collection level utility function to deserializes a destructured collection.\n     *\n     * @param {string|string[]} destructuredSource - destructured representation of collection to inflate\n     * @param {object} options - used to describe format of destructuredSource input\n     * @param {int} [options.delimited=false] - whether source is delimited string or an array\n     * @param {string} options.delimiter - if delimited, this is delimiter to use (if other than default)\n     *\n     * @returns {Array} an array of documents to attach to collection.data.\n     */\n    deserializeCollection<T extends object = object>(destructuredSource: string | string[], options?: Loki.DeserializeCollectionOptions): Doc<T>[];\n    /**\n     * Inflates a loki database from a serialized JSON string\n     *\n     * @param {string} serializedDb - a serialized loki database string\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSON(serializedDb: string | string[], options?: Collection.DeserializeOptions): void;\n    /**\n     * Inflates a loki database from a JS object\n     *\n     * @param {object} dbObject - a serialized loki database object\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSONObject(dbObject: Loki, options?: Collection.DeserializeOptions): void;\n    loadJSONObject(dbObject: Loki.Serialized, options?: Collection.DeserializeOptions): void;\n    /**\n     * Emits the close event. In autosave scenarios, if the database is dirty, this will save and disable timer.\n     * Does not actually destroy the db.\n     *\n     * @returns {Promise} a Promise that resolves after closing the database succeeded\n     */\n    close(): Promise<void>;\n    /**-------------------------+\n     | Changes API               |\n     +--------------------------*/\n    /**\n     * The Changes API enables the tracking the changes occurred in the collections since the beginning of the session,\n     * so it's possible to create a differential dataset for synchronization purposes (possibly to a remote db)\n     */\n    /**\n     * (Changes API) : takes all the changes stored in each\n     * collection and creates a single array for the entire database. If an array of names\n     * of collections is passed then only the included collections will be tracked.\n     *\n     * @param {Array} [arrayOfCollectionNames=] - array of collection names. No arg means all collections are processed.\n     * @returns {Array} array of changes\n     * @see private method _createChange() in Collection\n     */\n    generateChangesNotification(arrayOfCollectionNames?: string[]): Collection.Change[];\n    /**\n     * (Changes API) - stringify changes for network transmission\n     * @returns {string} string representation of the changes\n     */\n    serializeChanges(collectionNamesArray?: string[]): string;\n    /**\n     * (Changes API) : clears all the changes in all collections.\n     */\n    clearChanges(): void;\n    /**\n     * Wait for throttledSaves to complete and invoke your callback when drained or duration is met.\n     *\n     * @param {object} options - configuration options\n     * @param {boolean} [options.recursiveWait=true] - if after queue is drained, another save was kicked off, wait for it\n     * @param {boolean} [options.recursiveWaitLimit=false] - limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDuration=2000] - cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves when save queue is drained, it is passed a sucess parameter value\n     */\n    throttledSaveDrain(options?: Loki.ThrottledDrainOptions): Promise<void>;\n    /**\n     * Internal load logic, decoupled from throttling/contention logic\n     *\n     * @param {object} options - an object containing inflation options for each collection\n     * @param {boolean} ignore_not_found - does not raise an error if database is not found\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    private _loadDatabase(options?, ignore_not_found?);\n    /**\n     * Handles manually loading from an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *    To avoid contention with any throttledSaves, we will drain the save queue first.\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @param {object} [options={}] - if throttling saves and loads, this controls how we drain save queue before loading\n     * @param {boolean} [options.recursiveWait=true] wait recursively until no saves are queued\n     * @param {boolean} [options.recursiveWaitLimit=false] limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDelay=2000] cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    loadDatabase(options?: Loki.LoadDatabaseOptions): Promise<void>;\n    private _saveDatabase();\n    /**\n     * Handles manually saving to an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @returns {Promise} a Promise that resolves after the database is persisted\n     */\n    saveDatabase(): Promise<void>;\n    /**\n     * Handles deleting a database from the underlying storage adapter\n     *\n     * @returns {Promise} a Promise that resolves after the database is deleted\n     */\n    deleteDatabase(): Promise<void>;\n    /****************\n     * Autosave API\n     ****************/\n    /**\n     * Check whether any collections are \"dirty\" meaning we need to save the (entire) database\n     * @returns {boolean} - true if database has changed since last autosave, otherwise false\n     */\n    private _autosaveDirty();\n    /**\n     * Resets dirty flags on all collections.\n     */\n    private _autosaveClearFlags();\n    /**\n     * Starts periodically saves to the underlying storage adapter.\n     */\n    private _autosaveEnable();\n    /**\n     * Stops the autosave interval timer.\n     */\n    private _autosaveDisable();\n}\nexport declare namespace Loki {\n    interface Options {\n        env?: Environment;\n        serializationMethod?: SerializationMethod;\n        destructureDelimiter?: string;\n        comparatorMap?: IComparatorMap;\n        rangedIndexFactoryMap?: IRangedIndexFactoryMap;\n        lokiOperatorPackageMap?: ILokiOperatorPackageMap;\n    }\n    interface PersistenceOptions {\n        adapter?: StorageAdapter;\n        autosave?: boolean;\n        autosaveInterval?: number;\n        autoload?: boolean;\n        throttledSaves?: boolean;\n        persistenceMethod?: Loki.PersistenceMethod;\n        inflate?: any;\n    }\n    interface CopyOptions {\n        removeNonSerializable?: boolean;\n    }\n    interface SerializeOptions {\n        serializationMethod?: SerializationMethod;\n    }\n    interface SerializeDestructuredOptions {\n        partitioned?: boolean;\n        partition?: number;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface DeserializeCollectionOptions {\n        partitioned?: boolean;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface ThrottledDrainOptions {\n        recursiveWait?: boolean;\n        recursiveWaitLimit?: boolean;\n        recursiveWaitLimitDuration?: number;\n        started?: Date;\n    }\n    interface Serialized {\n        _env: Environment;\n        _serializationMethod: SerializationMethod;\n        _autosave: boolean;\n        _autosaveInterval: number;\n        _collections: Collection[];\n        databaseVersion: number;\n        engineVersion: number;\n        filename: string;\n        _persistenceAdapter: StorageAdapter;\n        _persistenceMethod: PersistenceMethod;\n        _throttledSaves: boolean;\n    }\n    type LoadDatabaseOptions = Collection.DeserializeOptions & ThrottledDrainOptions;\n    type SerializationMethod = \"normal\" | \"pretty\" | \"destructured\";\n    type PersistenceMethod = \"fs-storage\" | \"local-storage\" | \"indexed-storage\" | \"memory-storage\" | \"adapter\";\n    type Environment = \"NATIVESCRIPT\" | \"NODEJS\" | \"CORDOVA\" | \"BROWSER\" | \"MEMORY\";\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/loki/src/operator_packages.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\n/** Hash interface for named LokiOperatorPackage registration */\nexport interface ILokiOperatorPackageMap {\n    [name: string]: LokiOperatorPackage;\n}\n/**\n * Helper function for determining 'loki' abstract equality which is a little more abstract than ==\n *     aeqHelper(5, '5') === true\n *     aeqHelper(5.0, '5') === true\n *     aeqHelper(new Date(\"1/1/2011\"), new Date(\"1/1/2011\")) === true\n *     aeqHelper({a:1}, {z:4}) === true (all objects sorted equally)\n *     aeqHelper([1, 2, 3], [1, 3]) === false\n *     aeqHelper([1, 2, 3], [1, 2, 3]) === true\n *     aeqHelper(undefined, null) === true\n * @param {any} prop1\n * @param {any} prop2\n * @returns {boolean}\n * @hidden\n */\nexport declare function aeqHelper(prop1: any, prop2: any): boolean;\n/**\n * Helper function for determining 'less-than' conditions for ops, sorting, and binary indices.\n *     In the future we might want $lt and $gt ops to use their own functionality/helper.\n *     Since binary indices on a property might need to index [12, NaN, new Date(), Infinity], we\n *     need this function (as well as gtHelper) to always ensure one value is LT, GT, or EQ to another.\n * @hidden\n */\nexport declare function ltHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @hidden\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} equal\n * @returns {boolean}\n */\nexport declare function gtHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} descending\n * @returns {number}\n * @hidden\n */\nexport declare function sortHelper(prop1: any, prop2: any, descending: boolean): number;\n/**\n * Default implementation of LokiOperatorPackage, using fastest javascript comparison operators.\n */\nexport declare class LokiOperatorPackage {\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n    $in(a: any, b: any): boolean;\n    $nin(a: any, b: any): boolean;\n    $keyin(a: string, b: object): boolean;\n    $nkeyin(a: string, b: object): boolean;\n    $definedin(a: string, b: object): boolean;\n    $undefinedin(a: string, b: object): boolean;\n    $regex(a: string, b: RegExp): boolean;\n    $containsNone(a: any, b: any): boolean;\n    $containsAny(a: any, b: any): boolean;\n    $contains(a: any, b: any): boolean;\n    $type(a: any, b: any): boolean;\n    $finite(a: number, b: boolean): boolean;\n    $size(a: any, b: any): boolean;\n    $len(a: any, b: any): boolean;\n    $where(a: any, b: any): boolean;\n    $not(a: any, b: any): boolean;\n    $and(a: any, b: any): boolean;\n    $or(a: any, b: any): boolean;\n    private doQueryOp(val, op);\n    private containsCheckFn(a);\n}\n/**\n * LokiOperatorPackage which utilizes abstract 'loki' comparisons for basic relational equality op implementations.\n */\nexport declare class LokiAbstractOperatorPackage extends LokiOperatorPackage {\n    constructor();\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * LokiOperatorPackage which utilizes provided comparator for basic relational equality op implementations.\n */\nexport declare class ComparatorOperatorPackage<T> extends LokiOperatorPackage {\n    comparator: ILokiComparer<T>;\n    constructor(comparator: ILokiComparer<T>);\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * Map/Register of named LokiOperatorPackages which implement all unindexed query ops within 'find' query objects\n */\nexport declare let LokiOperatorPackageMap: ILokiOperatorPackageMap;\n"
  },
  {
    "path": "dist/packages/full-text-search/types/loki/src/ranged_indexes.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\nexport declare type RangedValueOperator = \"$gt\" | \"$gte\" | \"$lt\" | \"$lte\" | \"$eq\" | \"$neq\" | \"$between\";\nexport interface IRangedIndexRequest<T> {\n    op: RangedValueOperator;\n    val: T;\n    high?: T;\n}\n/** Defines interface which all loki ranged indexes need to implement */\nexport interface IRangedIndex<T> {\n    insert(id: number, val: T): void;\n    update(id: number, val: T): void;\n    remove(id: number): void;\n    restore(tree: any): void;\n    backup(): IRangedIndex<T>;\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    validateIndex(): boolean;\n}\n/** Hash Interface for global ranged index factory map*/\nexport interface IRangedIndexFactoryMap {\n    [name: string]: (name: string, comparator: ILokiComparer<any>) => IRangedIndex<any>;\n}\n/** Map/Register of named factory functions returning IRangedIndex instances */\nexport declare let RangedIndexFactoryMap: IRangedIndexFactoryMap;\n"
  },
  {
    "path": "dist/packages/full-text-search/types/loki/src/result_set.d.ts",
    "content": "import { Collection } from \"./collection\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\nimport { Query as FullTextSearchQuery } from \"../../full-text-search/src/query_types\";\n/**\n * ResultSet class allowing chainable queries.  Intended to be instanced internally.\n *    Collection.find(), Collection.where(), and Collection.chain() instantiate this.\n *\n * @example\n *    mycollection.chain()\n *      .find({ 'doors' : 4 })\n *      .where(function(obj) { return obj.name === 'Toyota' })\n *      .data();\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class ResultSet<T extends object = object> {\n    _collection: Collection<T>;\n    _filteredRows: number[];\n    _filterInitialized: boolean;\n    private _scoring;\n    /**\n     * Constructor.\n     * @param {Collection} collection - the collection which this ResultSet will query against\n     */\n    constructor(collection: Collection<T>);\n    /**\n     * Reset the ResultSet to its initial state.\n     * @returns {ResultSet} Reference to this ResultSet, for future chain operations.\n     */\n    reset(): this;\n    /**\n     * Override of toJSON to avoid circular references\n     */\n    toJSON(): ResultSet<T>;\n    /**\n     * Allows you to limit the number of documents passed to next chain operation.\n     * A ResultSet copy() is made to avoid altering original ResultSet.\n     * @param {int} qty - The number of documents to return.\n     * @returns {ResultSet} Returns a copy of the ResultSet, limited by qty, for subsequent chain ops.\n     */\n    limit(qty: number): this;\n    /**\n     * Used for skipping 'pos' number of documents in the ResultSet.\n     * @param {int} pos - Number of documents to skip; all preceding documents are filtered out.\n     * @returns {ResultSet} Returns a copy of the ResultSet, containing docs starting at 'pos' for subsequent chain ops.\n     */\n    offset(pos: number): this;\n    /**\n     * To support reuse of ResultSet in branched query situations.\n     * @returns {ResultSet} Returns a copy of the ResultSet (set) but the underlying document references will be the same.\n     */\n    copy(): ResultSet<T>;\n    /**\n     * Executes a named collection transform or raw array of transform steps against the ResultSet.\n     * @param {(string|array)} transform - name of collection transform or raw transform array\n     * @param {object} [parameters=] - object property hash of parameters, if the transform requires them.\n     * @returns {ResultSet} either (this) ResultSet or a clone of of this ResultSet (depending on steps)\n     */\n    transform(transform: string | Collection.Transform<T>[], parameters?: object): this;\n    /**\n     * User supplied compare function is provided two documents to compare. (chainable)\n     * @example\n     *    rslt.sort(function(obj1, obj2) {\n       *      if (obj1.name === obj2.name) return 0;\n       *      if (obj1.name > obj2.name) return 1;\n       *      if (obj1.name < obj2.name) return -1;\n       *    });\n     * @param {function} comparefun - A javascript compare function used for sorting.\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    sort(comparefun: (a: Doc<T>, b: Doc<T>) => number): this;\n    /**\n     * Simpler, loose evaluation for user to sort based on a property name. (chainable).\n     * Sorting based on the same lt/gt helper functions used for binary indices.\n     * @param {string} propname - name of property to sort by.\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether to sort descending\n     * @param {string} [options.sortComparator] override default with name of comparator registered in ComparatorMap\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    simplesort(propname: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * rs.compoundsort(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * rs.compoundsort(['age', ['name', true]);\n     * @param {array} properties - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    compoundsort(properties: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Helper function for compoundsort(), performing individual object comparisons\n     * @param {Array} properties - array of property names, in order, by which to evaluate sort order\n     * @param {object} obj1 - first object to compare\n     * @param {object} obj2 - second object to compare\n     * @returns {number} 0, -1, or 1 to designate if identical (sortwise) or which should be first\n     */\n    private _compoundeval(properties, obj1, obj2);\n    /**\n     * Sorts the ResultSet based on the last full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     * @returns {ResultSet}\n     */\n    sortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Oversee the operation of OR'ed query expressions.\n     * OR'ed expression evaluation runs each expression individually against the full collection,\n     * and finally does a set OR on each expression's results.\n     * Each evaluation can utilize a binary index to prevent multiple linear array scans.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findOr(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $or(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Oversee the operation of AND'ed query expressions.\n     * AND'ed expression evaluation runs each expression progressively against the full collection,\n     * internally utilizing existing chained ResultSet functionality.\n     * Only the first filter can utilize a binary index.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findAnd(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $and(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Used for querying via a mongo-style query object.\n     *\n     * @param {object} query - A mongo-style query object used for filtering current results.\n     * @param {boolean} firstOnly - (Optional) Used by collection.findOne() - flag if this was invoked via findOne()\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    find(query?: ResultSet.Query<Doc<T>>, firstOnly?: boolean): this;\n    /**\n     * Used for filtering via a javascript filter function.\n     * @param {function} fun - A javascript function used for filtering current results by.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    where(fun: (obj: Doc<T>) => boolean): this;\n    /**\n     * Returns the number of documents in the ResultSet.\n     * @returns {number} The number of documents in the ResultSet.\n     */\n    count(): number;\n    /**\n     * Terminates the chain and returns array of filtered documents\n     * @param {object} options\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values 'parse-stringify', 'deep', and 'shallow' and\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} Array of documents in the ResultSet\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * Used to run an update operation on all documents currently in the ResultSet.\n     * @param {function} updateFunction - User supplied updateFunction(obj) will be executed for each document object.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    update(updateFunction: (obj: Doc<T>) => Doc<T>): this;\n    /**\n     * Removes all document objects which are currently in ResultSet from collection (as well as ResultSet)\n     * @returns {ResultSet} this (empty) ResultSet for further chain ops.\n     */\n    remove(): this;\n    /**\n     * data transformation via user supplied functions\n     *\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns {value} The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Left joining two sets of data. Join keys can be defined or calculated properties\n     * eqJoin expects the right join key values to be unique.  Otherwise left data will be joined on the last joinData object with that key\n     * @param {Array|ResultSet|Collection} joinData - Data array to join to.\n     * @param {(string|function)} leftJoinKey - Property name in this result set to join on or a function to produce a value to join on\n     * @param {(string|function)} rightJoinKey - Property name in the joinData to join on or a function to produce a value to join on\n     * @param {function} [mapFun=] - a function that receives each matching pair and maps them into output objects - function(left,right){return joinedObject}\n     * @param {object} [dataOptions=] - optional options to apply to data() calls for left and right sides\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} A ResultSet with data in the format [{left: leftObj, right: rightObj}]\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinKey: string | ((obj: any) => string), rightJoinKey: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * Applies a map function into a new collection for further chaining.\n     * @param {function} mapFun - javascript map function\n     * @param {object} [dataOptions=] - options to data() before input to your map function\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - Allows overriding the default or collection specified cloning method\n     * @return {ResultSet}\n     */\n    map<U extends object>(mapFun: (obj: Doc<T>, index: number, array: Doc<T>[]) => U, dataOptions?: ResultSet.DataOptions): ResultSet<U>;\n}\nexport declare namespace ResultSet {\n    interface DataOptions {\n        forceClones?: boolean;\n        forceCloneMethod?: CloneMethod;\n        removeMeta?: boolean;\n    }\n    interface SimpleSortOptions {\n        desc?: boolean;\n        sortComparator?: string;\n    }\n    type ContainsHelperType<R> = R extends string ? string | string[] : R extends any[] ? R[number] | R[number][] : R extends object ? keyof R | (keyof R)[] : never;\n    type LokiOps<R> = {\n        $eq?: R;\n    } | {\n        $ne?: R;\n    } | {\n        $gt?: R;\n    } | {\n        $gte?: R;\n    } | {\n        $lt?: R;\n    } | {\n        $lte?: R;\n    } | {\n        $between?: [R, R];\n    } | {\n        $in?: R[];\n    } | {\n        $nin?: R[];\n    } | {\n        $keyin?: object;\n    } | {\n        $nkeyin?: object;\n    } | {\n        $definedin?: object;\n    } | {\n        $undefinedin?: object;\n    } | {\n        $regex?: RegExp | string | [string, string];\n    } | {\n        $containsNone?: ContainsHelperType<R>;\n    } | {\n        $containsAny?: ContainsHelperType<R>;\n    } | {\n        $contains?: ContainsHelperType<R>;\n    } | {\n        $type?: string;\n    } | {\n        $finite?: boolean;\n    } | {\n        $size?: number;\n    } | {\n        $len?: number;\n    } | {\n        $where?: (val?: R) => boolean;\n    };\n    type Query<T> = {\n        [P in keyof T]?: LokiOps<T[P]> | T[P];\n    } & {\n        $and?: Query<T>[];\n    } & {\n        $or?: Query<T>[];\n    } & {\n        $fts?: FullTextSearchQuery;\n    };\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/loki/src/unique_index.d.ts",
    "content": "export declare class UniqueIndex {\n    private _field;\n    private _lokiMap;\n    private _valMap;\n    /**\n     * Constructs an unique index object.\n     * @param {string} propertyField - the property field to index\n     */\n    constructor(propertyField: string);\n    /**\n     * Sets a document's unique index.\n     * @param {number} id loki id to associate with value\n     * @param {*} value  value to associate with id\n     */\n    set(id: number, value: any): void;\n    /**\n     * Returns the $loki id of an unique value.\n     * @param {*} value the value to retrieve a loki id match for\n     */\n    get(value: any): number;\n    /**\n     * Updates a document's unique index.\n     * @param {number} id (loki) id of document to update the value to\n     * @param {*} value value to associate with loki id\n     */\n    update(id: number, value: any): void;\n    /**\n     * Removes an unique index.\n     * @param {number} id (loki) id to remove from index\n     */\n    remove(id: number): void;\n    /**\n     * Clears the unique index.\n     */\n    clear(): void;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/memory-storage/src/index.d.ts",
    "content": "import { MemoryStorage } from \"./memory_storage\";\nexport { MemoryStorage };\nexport default MemoryStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search/types/memory-storage/src/memory_storage.d.ts",
    "content": "import { Dict, StorageAdapter } from \"../../common/types\";\n/**\n * An in-memory persistence adapter for an in-memory database.\n * This simple 'key/value' adapter is intended for unit testing and diagnostics.\n */\nexport declare class MemoryStorage implements StorageAdapter {\n    hashStore: Dict<{\n        savecount: number;\n        lastsave: Date;\n        value: string;\n    }>;\n    options: MemoryStorage.Options;\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} options - memory storage options\n     * @param {boolean} [options.asyncResponses=false] - whether callbacks are invoked asynchronously (default: false)\n     * @param {int} [options.asyncTimeout=50] - timeout in ms to queue callbacks (default: 50)\n     */\n    constructor(options?: MemoryStorage.Options);\n    /**\n     * Loads a serialized database from its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * Saves a serialized database to its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {string} dbstring - the database content\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a database from its in-memory store.\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport declare namespace MemoryStorage {\n    interface Options {\n        asyncResponses?: boolean;\n        asyncTimeout?: number;\n    }\n}\n"
  },
  {
    "path": "dist/packages/full-text-search/types/partitioning-adapter/src/index.d.ts",
    "content": "import { PartitioningAdapter } from \"./partitioning_adapter\";\nexport { PartitioningAdapter };\nexport default PartitioningAdapter;\n"
  },
  {
    "path": "dist/packages/full-text-search/types/partitioning-adapter/src/partitioning_adapter.d.ts",
    "content": "import { Loki } from \"../../loki/src/loki\";\nimport { StorageAdapter } from \"../../common/types\";\n/**\n * An adapter for adapters. Converts a non reference mode adapter into a reference mode adapter\n * which can perform destructuring and partitioning. Each collection will be stored in its own key/save and\n * only dirty collections will be saved. If you  turn on paging with default page size of 25megs and save\n * a 75 meg collection it should use up roughly 3 save slots (key/value pairs sent to inner adapter).\n * A dirty collection that spans three pages will save all three pages again\n * Paging mode was added mainly because Chrome has issues saving 'too large' of a string within a\n * single IndexedDB row. If a single document update causes the collection to be flagged as dirty, all\n * of that collection's pages will be written on next save.\n */\nexport declare class PartitioningAdapter implements StorageAdapter {\n    mode: string;\n    private _adapter;\n    private _dbref;\n    private _dbname;\n    private _pageIterator;\n    private _paging;\n    private _pageSize;\n    private _delimiter;\n    private _dirtyPartitions;\n    /**\n     * Registers the partitioning adapter as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the partitioning storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} adapter - reference to a 'non-reference' mode loki adapter instance.\n     * @param {boolean} paging - (default: false) set to true to enable paging collection data.\n     * @param {number} pageSize - (default : 25MB) you can use this to limit size of strings passed to inner adapter.\n     * @param {string} delimiter - allows you to override the default delimiter\n     */\n    constructor(adapter: StorageAdapter, {paging, pageSize, delimiter}?: {\n        paging?: boolean;\n        pageSize?: number;\n        delimiter?: string;\n    });\n    /**\n     * Loads a database which was partitioned into several key/value saves.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Used to sequentially load each collection partition, one at a time.\n     *\n     * @param {int} partition - ordinal collection position to load next\n     * @returns {Promise} a Promise that resolves after the next partition is loaded\n     */\n    private _loadNextPartition(partition);\n    /**\n     * Used to sequentially load the next page of collection partition, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next page is loaded\n     */\n    private _loadNextPage();\n    /**\n     * Saves a database by partioning into separate key/value saves.\n     * (Loki 'reference mode' persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {object} dbref - reference to database which we will partition and save.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     *\n     */\n    exportDatabase(dbname: string, dbref: Loki): Promise<void>;\n    /**\n     * Helper method used internally to save each dirty collection, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPartition();\n    /**\n     * Helper method used internally to generate and save the next page of the current (dirty) partition.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPage();\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/lokidb.full-text-search-language.js",
    "content": "(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"@lokidb/full-text-search-language\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"@lokidb/full-text-search-language\"] = factory();\n\telse\n\t\t{ root[\"@lokidb/full-text-search-language\"] = factory(); root[\"LokiFullTextSearchLanguage\"] = root[\"@lokidb/full-text-search-language\"].default; }\n})(typeof self !== 'undefined' ? self : this, function() {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// define __esModule on exports\n/******/ \t__webpack_require__.r = function(exports) {\n/******/ \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n/******/ \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n/******/ \t\t}\n/******/ \t\tObject.defineProperty(exports, '__esModule', { value: true });\n/******/ \t};\n/******/\n/******/ \t// create a fake namespace object\n/******/ \t// mode & 1: value is a module id, require it\n/******/ \t// mode & 2: merge all properties of value into the ns\n/******/ \t// mode & 4: return value when already ns object\n/******/ \t// mode & 8|1: behave like require\n/******/ \t__webpack_require__.t = function(value, mode) {\n/******/ \t\tif(mode & 1) value = __webpack_require__(value);\n/******/ \t\tif(mode & 8) return value;\n/******/ \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n/******/ \t\tvar ns = Object.create(null);\n/******/ \t\t__webpack_require__.r(ns);\n/******/ \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n/******/ \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n/******/ \t\treturn ns;\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 0);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n\n// CONCATENATED MODULE: ./packages/full-text-search-language/src/language.ts\n/*\n * From MihaiValentin/lunr-languages.\n * Last update from 2017/04/16 - 19af41fb9bd644d9081ad274f96f700b21464290\n */\nfunction generateTrimmer(wordCharacters) {\n    const regex = new RegExp(`^[^${wordCharacters}]+|[^${wordCharacters}]+$`, \"g\");\n    return (token) => token.replace(regex, \"\");\n}\nfunction generateStopWordFilter(stopWords) {\n    const words = new Set(stopWords);\n    return (token) => words.has(token) ? \"\" : token;\n}\nclass Among {\n    constructor(s, substring_i, result, method) {\n        if ((!s && s !== \"\") || (!substring_i && (substring_i !== 0)) || !result) {\n            throw (\"Bad Among initialisation: s:\" + s + \", substring_i: \" + substring_i + \", result: \" + result);\n        }\n        this.s_size = s.length;\n        this.substring_i = substring_i;\n        this.result = result;\n        this.method = method;\n        // Split string into a numeric character array.\n        this.s = new Array(this.s_size);\n        for (let i = 0; i < this.s_size; i++) {\n            this.s[i] = +s.charCodeAt(i);\n        }\n    }\n}\nclass SnowballProgram {\n    constructor() {\n        this.current = null;\n        this.bra = 0;\n        this.ket = 0;\n        this.limit = 0;\n        this.cursor = 0;\n        this.limit_backward = 0;\n    }\n    setCurrent(word) {\n        this.current = word;\n        this.cursor = 0;\n        this.limit = word.length;\n        this.limit_backward = 0;\n        this.bra = this.cursor;\n        this.ket = this.limit;\n    }\n    getCurrent() {\n        let result = this.current;\n        this.current = null;\n        return result;\n    }\n    in_grouping(s, min, max) {\n        if (this.cursor < this.limit) {\n            let ch = this.current.charCodeAt(this.cursor);\n            if (ch <= max && ch >= min) {\n                ch -= min;\n                if (s[ch >> 3] & (0X1 << (ch & 0X7))) {\n                    this.cursor++;\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n    in_grouping_b(s, min, max) {\n        if (this.cursor > this.limit_backward) {\n            let ch = this.current.charCodeAt(this.cursor - 1);\n            if (ch <= max && ch >= min) {\n                ch -= min;\n                if (s[ch >> 3] & (0X1 << (ch & 0X7))) {\n                    this.cursor--;\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n    out_grouping(s, min, max) {\n        if (this.cursor < this.limit) {\n            let ch = this.current.charCodeAt(this.cursor);\n            if (ch > max || ch < min) {\n                this.cursor++;\n                return true;\n            }\n            ch -= min;\n            if (!(s[ch >> 3] & (0X1 << (ch & 0X7)))) {\n                this.cursor++;\n                return true;\n            }\n        }\n        return false;\n    }\n    out_grouping_b(s, min, max) {\n        if (this.cursor > this.limit_backward) {\n            let ch = this.current.charCodeAt(this.cursor - 1);\n            if (ch > max || ch < min) {\n                this.cursor--;\n                return true;\n            }\n            ch -= min;\n            if (!(s[ch >> 3] & (0X1 << (ch & 0X7)))) {\n                this.cursor--;\n                return true;\n            }\n        }\n        return false;\n    }\n    eq_s(s_size, s) {\n        if (this.limit - this.cursor < s_size) {\n            return false;\n        }\n        for (let i = 0; i < s_size; i++) {\n            if (this.current.charCodeAt(this.cursor + i) !== s.charCodeAt(i)) {\n                return false;\n            }\n        }\n        this.cursor += s_size;\n        return true;\n    }\n    eq_s_b(s_size, s) {\n        if (this.cursor - this.limit_backward < s_size) {\n            return false;\n        }\n        for (let i = 0; i < s_size; i++) {\n            if (this.current.charCodeAt(this.cursor - s_size + i) !== s.charCodeAt(i)) {\n                return false;\n            }\n        }\n        this.cursor -= s_size;\n        return true;\n    }\n    find_among(v, v_size) {\n        let i = 0;\n        let j = v_size;\n        let c = this.cursor;\n        let l = this.limit;\n        let common_i = 0;\n        let common_j = 0;\n        let first_key_inspected = false;\n        while (true) {\n            let k = i + ((j - i) >> 1);\n            let diff = 0;\n            let common = common_i < common_j ? common_i : common_j;\n            let w = v[k];\n            for (let i2 = common; i2 < w.s_size; i2++) {\n                if (c + common === l) {\n                    diff = -1;\n                    break;\n                }\n                diff = this.current.charCodeAt(c + common) - w.s[i2];\n                if (diff) {\n                    break;\n                }\n                common++;\n            }\n            if (diff < 0) {\n                j = k;\n                common_j = common;\n            }\n            else {\n                i = k;\n                common_i = common;\n            }\n            if (j - i <= 1) {\n                if (i > 0 || j === i || first_key_inspected) {\n                    break;\n                }\n                first_key_inspected = true;\n            }\n        }\n        while (true) {\n            let w = v[i];\n            if (common_i >= w.s_size) {\n                this.cursor = c + w.s_size;\n                if (!w.method) {\n                    return w.result;\n                }\n                let res = w.method();\n                this.cursor = c + w.s_size;\n                if (res) {\n                    return w.result;\n                }\n            }\n            i = w.substring_i;\n            if (i < 0) {\n                return 0;\n            }\n        }\n    }\n    find_among_b(v, v_size) {\n        let i = 0;\n        let j = v_size;\n        let c = this.cursor;\n        let lb = this.limit_backward;\n        let common_i = 0;\n        let common_j = 0;\n        let first_key_inspected = false;\n        while (true) {\n            let k = i + ((j - i) >> 1);\n            let diff = 0;\n            let common = common_i < common_j\n                ? common_i\n                : common_j;\n            let w = v[k];\n            for (let i2 = w.s_size - 1 - common; i2 >= 0; i2--) {\n                if (c - common === lb) {\n                    diff = -1;\n                    break;\n                }\n                diff = this.current.charCodeAt(c - 1 - common) - w.s[i2];\n                if (diff)\n                    break;\n                common++;\n            }\n            if (diff < 0) {\n                j = k;\n                common_j = common;\n            }\n            else {\n                i = k;\n                common_i = common;\n            }\n            if (j - i <= 1) {\n                if (i > 0 || j === i || first_key_inspected)\n                    break;\n                first_key_inspected = true;\n            }\n        }\n        while (true) {\n            let w = v[i];\n            if (common_i >= w.s_size) {\n                this.cursor = c - w.s_size;\n                if (!w.method)\n                    return w.result;\n                let res = w.method();\n                this.cursor = c - w.s_size;\n                if (res)\n                    return w.result;\n            }\n            i = w.substring_i;\n            if (i < 0)\n                return 0;\n        }\n    }\n    replace_s(c_bra, c_ket, s) {\n        let adjustment = s.length - (c_ket - c_bra);\n        let left = this.current\n            .substring(0, c_bra);\n        let right = this.current.substring(c_ket);\n        this.current = left + s + right;\n        this.limit += adjustment;\n        if (this.cursor >= c_ket)\n            this.cursor += adjustment;\n        else if (this.cursor > c_bra)\n            this.cursor = c_bra;\n        return adjustment;\n    }\n    slice_check() {\n        if (this.bra < 0 || this.bra > this.ket || this.ket > this.limit\n            || this.limit > this.current.length) {\n            throw (\"faulty slice operation\");\n        }\n    }\n    slice_from(s) {\n        this.slice_check();\n        this.replace_s(this.bra, this.ket, s);\n    }\n    slice_del() {\n        this.slice_from(\"\");\n    }\n    insert(c_bra, c_ket, s) {\n        let adjustment = this.replace_s(c_bra, c_ket, s);\n        if (c_bra <= this.bra)\n            this.bra += adjustment;\n        if (c_bra <= this.ket)\n            this.ket += adjustment;\n    }\n    slice_to() {\n        this.slice_check();\n        return this.current.substring(this.bra, this.ket);\n    }\n    eq_v_b(s) {\n        return this.eq_s_b(s.length, s);\n    }\n}\n\n// CONCATENATED MODULE: ./packages/full-text-search-language/src/index.ts\n/* concated harmony reexport */__webpack_require__.d(__webpack_exports__, \"generateStopWordFilter\", function() { return generateStopWordFilter; });\n/* concated harmony reexport */__webpack_require__.d(__webpack_exports__, \"generateTrimmer\", function() { return generateTrimmer; });\n/* concated harmony reexport */__webpack_require__.d(__webpack_exports__, \"Among\", function() { return Among; });\n/* concated harmony reexport */__webpack_require__.d(__webpack_exports__, \"SnowballProgram\", function() { return SnowballProgram; });\n\n\n\n/***/ })\n/******/ ]);\n});\n//# sourceMappingURL=lokidb.full-text-search-language.js.map"
  },
  {
    "path": "dist/packages/full-text-search-language/types/common/plugin.d.ts",
    "content": "/**\n * @hidden\n */\nexport declare const PLUGINS: void;\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/common/types.d.ts",
    "content": "/**\n * @hidden\n */\nimport { Loki } from \"../loki/src/loki\";\nexport interface StorageAdapter {\n    loadDatabase(dbname: string): Promise<any>;\n    saveDatabase?(dbname: string, serialization: string): Promise<void>;\n    deleteDatabase?(dbname: string): Promise<void>;\n    mode?: string;\n    exportDatabase?(dbname: string, dbref: Loki): Promise<void>;\n}\nexport declare type Doc<T extends object = object> = T & {\n    $loki: number;\n    meta?: {\n        created: number;\n        revision: number;\n        version: number;\n        updated?: number;\n    };\n};\nexport interface Dict<T> {\n    [index: string]: T;\n    [index: number]: T;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/fs-storage/src/fs_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists using node fs module.\n */\nexport declare class FSStorage implements StorageAdapter {\n    /**\n     * Registers the fs storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the fs storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * Load data from file, will throw an error if the file does not exist\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Save data to file, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Delete the database file, will throw an error if the\n     * file can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/fs-storage/src/index.d.ts",
    "content": "import { FSStorage } from \"./fs_storage\";\nexport { FSStorage };\nexport default FSStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search/src/analyzer/analyzer.d.ts",
    "content": "import { CharacterFilter } from \"./character_filter\";\nimport { Tokenizer, whitespaceTokenizer } from \"./tokenizer\";\nimport { lowercaseTokenFilter, TokenFilter } from \"./token_filter\";\n/**\n * A analyzer converts a string into tokens which are added to the inverted index for searching.\n */\nexport interface Analyzer {\n    /**\n     * The character filters of the analyzer.\n     */\n    char_filter?: CharacterFilter[];\n    /**\n     * The tokenizer of the analyzer.\n     */\n    tokenizer: Tokenizer;\n    /**\n     * The token filters of the analyzer.\n     */\n    token_filter?: TokenFilter[];\n}\n/**\n * Analyzes a given string.\n * @param {Analyzer} analyzer - the analyzer\n * @param {string} str - the string\n * @returns {string[]} - the tokens\n */\nexport declare function analyze(analyzer: Analyzer, str: string): string[];\n/**\n * An analyzer with the whitespace tokenizer and the lowercase token filter.\n */\nexport declare class StandardAnalyzer implements Analyzer {\n    tokenizer: typeof whitespaceTokenizer;\n    token_filter: (typeof lowercaseTokenFilter)[];\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search/src/analyzer/character_filter.d.ts",
    "content": "/**\n * A character filter is used to preprocess a string before it is passed to a tokenizer.\n */\nexport declare type CharacterFilter = (value: string) => string;\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search/src/analyzer/token_filter.d.ts",
    "content": "/**\n * A token filter takes tokens from a tokenizer and modify, delete or add tokens.\n */\nexport declare type TokenFilter = (value: string, index: number, array: string[]) => string;\n/**\n * Converts a token to lowercase.\n * @param {string} token - the token\n * @returns {string} - the lowercased token\n */\nexport declare function lowercaseTokenFilter(token: string): string;\n/**\n * Converts a token to uppercase.\n * @param {string} token - the token\n * @returns {string} - the uppercased token\n */\nexport declare function uppercaseTokenFilter(token: string): string;\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search/src/analyzer/tokenizer.d.ts",
    "content": "/**\n * A tokenizer splits a string into individual tokens.\n */\nexport declare type Tokenizer = (value: string) => string[];\n/**\n * Splits a string at whitespace characters into tokens.\n * @param {string} value - the string\n * @returns {string[]} - the tokens\n */\nexport declare function whitespaceTokenizer(value: string): string[];\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search/src/full_text_search.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\nimport { Scorer } from \"./scorer\";\nimport { Analyzer } from \"./analyzer/analyzer\";\nexport declare class FullTextSearch {\n    private _id;\n    private _docs;\n    private _idxSearcher;\n    private _invIdxs;\n    /**\n     * Registers the full-text search as plugin.\n     */\n    static register(): void;\n    /**\n     * Initialize the full-text search for the given fields.\n     * @param {object[]} fieldOptions - the field options\n     * @param {string} fieldOptions.field - the name of the property field\n     * @param {boolean=true} fieldOptions.store - flag to indicate if the full-text search should be stored on serialization or\n     *  rebuild on deserialization\n     * @param {boolean=true} fieldOptions.optimizeChanges - flag to optimize updating and deleting of documents\n     *    (requires more memory but performs faster)\n     * @param {Analyzer} fieldOptions.analyzer - an analyzer for the field\n     * @param {string} [id] - the property name of the document index\n     */\n    constructor(fieldOptions?: FullTextSearch.FieldOptions[], id?: string);\n    addDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    removeDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    updateDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    clear(): void;\n    search(query: Query): Scorer.ScoreResults;\n    toJSON(): FullTextSearch.Serialization;\n    static fromJSONObject(serialized: FullTextSearch.Serialization, analyzers?: Dict<Analyzer>): FullTextSearch;\n}\nexport declare namespace FullTextSearch {\n    interface FieldOptions extends InvertedIndex.FieldOptions {\n        field: string;\n    }\n    interface Serialization {\n        id: string;\n        ii: Dict<InvertedIndex.Serialization>;\n    }\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search/src/fuzzy/automaton.d.ts",
    "content": "/**\n * Transition with dest, min and max.\n * @hidden\n */\nexport declare type Transition = [number, number, number];\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MIN_CODE_POINT = 0;\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MAX_CODE_POINT = 1114111;\n/**\n * From org/apache/lucene/util/automaton/Automaton.java\n * @hidden\n */\nexport declare class Automaton {\n    private _stateTransitions;\n    private _accept;\n    private _nextState;\n    private _currState;\n    private _transitions;\n    constructor();\n    isAccept(n: number): boolean;\n    createState(): number;\n    setAccept(state: number, accept: boolean): void;\n    finishState(): void;\n    private _finishCurrentState();\n    getStartPoints(): number[];\n    step(state: number, label: number): number;\n    getNumStates(): number;\n    addTransition(source: number, dest: number, min: number, max: number): void;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search/src/fuzzy/lev1t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev1TParametricDescription.java\n * @hidden\n */\nexport declare class Lev1TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search/src/fuzzy/lev2t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev2TParametricDescription.java\n * @hidden\n */\nexport declare class Lev2TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search/src/fuzzy/levenshtein_automata.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java\n * @hidden\n */\nexport declare class LevenshteinAutomata {\n    private _word;\n    private _numRanges;\n    private _rangeLower;\n    private _rangeUpper;\n    private _description;\n    private _alphabet;\n    private _editDistance;\n    constructor(input: number[], editDistance: number);\n    /**\n     * Transforms the NDFA to a DFA.\n     * @returns {Automaton}\n     */\n    toAutomaton(): Automaton;\n    private _getVector(x, pos, end);\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search/src/fuzzy/long.d.ts",
    "content": "/**\n * Class supports 64Bit integer operations.\n * A cut-down version of dcodeIO/long.js.\n * @hidden\n */\nexport declare class Long {\n    private _low;\n    private _high;\n    constructor(low?: number, high?: number);\n    /**\n     * Returns this long with bits arithmetically shifted to the right by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftRight(numBits: number): Long;\n    /**\n     * Returns this long with bits arithmetically shifted to the left by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftLeft(numBits: number): Long;\n    /**\n     * Returns the bitwise AND of this Long and the specified.\n     * @param {Long} other - the other Long\n     * @returns {Long} the long\n     */\n    and(other: Long): Long;\n    /**\n     * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.\n     * @returns {number}\n     */\n    toInt(): number;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search/src/fuzzy/parametric_description.d.ts",
    "content": "import { Long } from \"./long\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java#ParametricDescription\n * @hidden\n */\nexport declare class ParametricDescription {\n    protected _w: number;\n    private _n;\n    private _minErrors;\n    constructor(w: number, n: number, minErrors: number[]);\n    /**\n     * Return the number of states needed to compute a Levenshtein DFA\n     */\n    size(): number;\n    /**\n     * Returns true if the <code>state</code> in any Levenshtein DFA is an accept state (final state).\n     */\n    isAccept(absState: number): boolean;\n    /**\n     * Returns the position in the input word for a given <code>state</code>.\n     * This is the minimal boundary for the state.\n     */\n    getPosition(absState: number): number;\n    static unpack(data: Long[], index: number, bitsPerValue: number): number;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search/src/fuzzy/run_automaton.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/RunAutomaton.java\n * @hidden\n */\nexport declare class RunAutomaton {\n    private _points;\n    private _accept;\n    private _transitions;\n    private _classmap;\n    constructor(automaton: Automaton);\n    getCharClass(c: number): number;\n    step(state: number, c: number): number;\n    isAccept(state: number): boolean;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search/src/index.d.ts",
    "content": "import { FullTextSearch } from \"./full_text_search\";\nimport { analyze, StandardAnalyzer } from \"./analyzer/analyzer\";\nimport { whitespaceTokenizer } from \"./analyzer/tokenizer\";\nimport { lowercaseTokenFilter, uppercaseTokenFilter } from \"./analyzer/token_filter\";\nexport { FullTextSearch, analyze, StandardAnalyzer, whitespaceTokenizer, lowercaseTokenFilter, uppercaseTokenFilter };\nexport default FullTextSearch;\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search/src/index_searcher.d.ts",
    "content": "import { Scorer } from \"./scorer\";\nimport { InvertedIndex } from \"./inverted_index\";\nimport { Query } from \"./query_types\";\nimport { Dict } from \"../../common/types\";\n/**\n * @hidden\n */\nexport declare class IndexSearcher {\n    private _invIdxs;\n    private _docs;\n    private _scorer;\n    /**\n     * Constructs an index searcher.\n     * @param {Dict<InvertedIndex>} invIdxs - the inverted indexes\n     * @param {Set<number>} docs - the ids of the documents\n     */\n    constructor(invIdxs: Dict<InvertedIndex>, docs: Set<InvertedIndex.DocumentIndex>);\n    search(query: Query): Scorer.ScoreResults;\n    setDirty(): void;\n    private _recursive(query, doScoring);\n    private _getUnique(queries, doScoring, queryResults);\n    private _getAll(queries, doScoring, queryResults?);\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search/src/inverted_index.d.ts",
    "content": "import { Analyzer } from \"./analyzer/analyzer\";\n/**\n * Converts a string into an array of code points.\n * @param str - the string\n * @returns {number[]} to code points\n * @hidden\n */\nexport declare function toCodePoints(str: string): number[];\n/**\n * Inverted index class handles featured text search for specific document fields.\n * @hidden\n */\nexport declare class InvertedIndex {\n    analyzer: Analyzer;\n    docCount: number;\n    docStore: Map<InvertedIndex.DocumentIndex, InvertedIndex.DocStore>;\n    totalFieldLength: number;\n    root: InvertedIndex.Index;\n    private _store;\n    private _optimizeChanges;\n    /**\n     * @param {boolean} [options.store=true] - inverted index will be stored at serialization rather than rebuilt on load\n     * @param {boolean} [options.optimizeChanges=true] - flag to store additional metadata inside the index for better\n     *  performance if an existing field is updated or removed\n     * @param {Analyzer} [options.analyzer=] - the analyzer of this inverted index\n     */\n    constructor(options?: InvertedIndex.FieldOptions);\n    /**\n     * Adds defined fields of a document to the inverted index.\n     * @param {string} field - the field to add\n     * @param {number} docId - the doc id of the field\n     */\n    insert(field: string, docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Removes all relevant terms of a document from the inverted index.\n     * @param {number} docId - the document.\n     */\n    remove(docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Gets the term index of a term.\n     * @param {string} term - the term\n     * @param {object} root - the term index to start from\n     * @param {number} start - the position of the term string to start from\n     * @return {object} - The term index or null if the term is not in the term tree.\n     */\n    static getTermIndex(term: number[], root: InvertedIndex.Index, start?: number): InvertedIndex.Index;\n    /**\n     * Extends a term index to all available term leafs.\n     * @param {object} idx - the term index to start from\n     * @param {number[]} [term=[]] - the current term\n     * @param {Array} termIndices - all extended indices with their term\n     * @returns {Array} - Array with term indices and extension\n     */\n    static extendTermIndex(idx: InvertedIndex.Index, term?: number[], termIndices?: InvertedIndex.IndexTerm[]): InvertedIndex.IndexTerm[];\n    /**\n     * Serialize the inverted index.\n     * @returns {{docStore: *, _fields: *, index: *}}\n     */\n    toJSON(): InvertedIndex.Serialization;\n    /**\n     * Deserialize the inverted index.\n     * @param {{docStore: *, _fields: *, index: *}} serialized - The serialized inverted index.\n     * @param {Analyzer} analyzer[undefined] - an analyzer\n     */\n    static fromJSONObject(serialized: InvertedIndex.Serialization, analyzer?: Analyzer): InvertedIndex;\n    private static _serializeIndex(idx);\n    private static _deserializeIndex(serialized);\n    /**\n     * Set parent of to each index and regenerate the indexRef.\n     * @param {Index} index - the index\n     * @param {Index} parent - the parent\n     */\n    private _regenerate(index, parent);\n    /**\n     * Iterate over the whole inverted index and remove the document.\n     * Delete branch if not needed anymore.\n     * Function is needed if index is used without optimization.\n     * @param {Index} idx - the index\n     * @param {number} docId - the doc id\n     * @returns {boolean} true if index is empty\n     */\n    private _remove(idx, docId);\n}\nexport declare namespace InvertedIndex {\n    interface FieldOptions {\n        store?: boolean;\n        optimizeChanges?: boolean;\n        analyzer?: Analyzer;\n    }\n    type Index = Map<number, any> & {\n        dc?: Map<DocumentIndex, number>;\n        df?: number;\n        pa?: Index;\n    };\n    type IndexTerm = {\n        index: Index;\n        term: number[];\n    };\n    interface SerializedIndex {\n        d?: {\n            df: number;\n            dc: [DocumentIndex, number][];\n        };\n        k?: number[];\n        v?: SerializedIndex[];\n    }\n    type Serialization = SpareSerialization | FullSerialization;\n    type SpareSerialization = {\n        _store: false;\n        _optimizeChanges: boolean;\n    };\n    type FullSerialization = {\n        _store: true;\n        _optimizeChanges: boolean;\n        docCount: number;\n        docStore: [DocumentIndex, DocStore][];\n        totalFieldLength: number;\n        root: SerializedIndex;\n    };\n    interface DocStore {\n        fieldLength?: number;\n        indexRef?: Index[];\n    }\n    type DocumentIndex = number | string;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search/src/query_types.d.ts",
    "content": "/**\n * Base query to enable boost to a query type.\n */\nexport interface BaseQuery<Type> {\n    type: Type;\n    boost?: number;\n}\n/**\n * A query which finds documents where a document field contains a term.\n */\nexport interface TermQuery extends BaseQuery<\"term\"> {\n    field: string;\n    value: string;\n}\n/**\n * A query which finds documents where a document field contains any of the terms.\n */\nexport interface TermsQuery extends BaseQuery<\"terms\"> {\n    field: string;\n    value: string[];\n}\n/**\n * A query which finds documents where the wildcard term can be applied at an existing document field term.\n */\nexport interface WildcardQuery extends BaseQuery<\"wildcard\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which finds documents where the fuzzy term can be transformed into an existing document field term within a\n * given edit distance.\n */\nexport interface FuzzyQuery extends BaseQuery<\"fuzzy\"> {\n    field: string;\n    value: string;\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query which matches documents containing the prefix of a term inside a field.\n */\nexport interface PrefixQuery extends BaseQuery<\"prefix\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which matches all documents with a given field.\n */\nexport interface ExistsQuery extends BaseQuery<\"exists\"> {\n    field: string;\n}\n/**\n * A query which tokenizes the given text into tokens and performs a sub query for each token. The results are combined\n * using a boolean operator.\n */\nexport interface MatchQuery extends BaseQuery<\"match\"> {\n    field: string;\n    value: string;\n    minimum_should_match?: number | string;\n    operator?: \"and\" | \"or\";\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query that matches all documents and giving them a constant score equal to the query boost.\n*/\nexport interface MatchQueryAll extends BaseQuery<\"match_all\"> {\n}\n/**\n * A query that wraps sub queries and returns a constant score equal to the query boost for every document in the filter.\n */\nexport interface ConstantScoreQuery extends BaseQuery<\"constant_score\"> {\n    filter: QueryTypes[];\n}\n/**\n * A query that matches documents matching boolean combinations of sub queries.\n */\nexport interface BoolQuery extends BaseQuery<\"bool\"> {\n    must?: QueryTypes[];\n    filter?: QueryTypes[];\n    should?: QueryTypes[];\n    not?: QueryTypes[];\n    minimum_should_match?: number | string;\n}\n/**\n * Union type of possible query types.\n */\nexport declare type QueryTypes = BoolQuery | ConstantScoreQuery | TermQuery | TermsQuery | WildcardQuery | FuzzyQuery | MatchQuery | MatchQueryAll | PrefixQuery | ExistsQuery;\n/**\n * The main query with the actually full-text search query and the scoring parameters.\n */\nexport interface Query {\n    query: QueryTypes;\n    calculate_scoring?: boolean;\n    explain?: boolean;\n    bm25?: {\n        k1: number;\n        b: number;\n    };\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search/src/scorer.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\n/**\n * @hidden\n */\nexport declare class Scorer {\n    private _invIdxs;\n    private _cache;\n    constructor(invIdxs: Dict<InvertedIndex>);\n    setDirty(): void;\n    score(fieldName: string, boost: number, termIdx: InvertedIndex.Index, doScoring: boolean | null, queryResults: Scorer.QueryResults, term: number[], df?: number): void;\n    scoreConstant(boost: number, docId: InvertedIndex.DocumentIndex, queryResults: Scorer.QueryResults): Scorer.QueryResults;\n    finalScore(query: Query, queryResults: Scorer.QueryResults): Scorer.ScoreResults;\n    private static _calculateFieldLength(fieldLength);\n    private _getCache(fieldName);\n    /**\n     * Returns the idf by either calculate it or use a cached one.\n     * @param {string} fieldName - the name of the field\n     * @param {number} docFreq - the doc frequency of the term\n     * @returns {number} the idf\n     * @private\n     */\n    private _idf(fieldName, docFreq);\n    private _avgFieldLength(fieldName);\n}\nexport declare namespace Scorer {\n    interface IDFCache {\n        idfs: Dict<number>;\n        avgFieldLength: number;\n    }\n    interface QueryResult {\n        tf?: number;\n        idf?: number;\n        boost: number;\n        fieldName?: string;\n        term?: number[];\n    }\n    type QueryResults = Map<InvertedIndex.DocumentIndex, QueryResult[]>;\n    interface BM25Explanation {\n        boost: number;\n        score: number;\n        docID: number;\n        fieldName: string;\n        index: string;\n        idf: number;\n        tfNorm: number;\n        tf: number;\n        fieldLength: number;\n        avgFieldLength: number;\n    }\n    interface ConstantExplanation {\n        boost: number;\n        score: number;\n    }\n    type ScoreExplanation = BM25Explanation | ConstantExplanation;\n    type ScoreResult = {\n        score: number;\n        explanation?: ScoreExplanation[];\n    };\n    type ScoreResults = Dict<ScoreResult>;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search-language/src/index.d.ts",
    "content": "export { generateStopWordFilter, generateTrimmer, Among, SnowballProgram } from \"./language\";\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search-language/src/language.d.ts",
    "content": "export declare function generateTrimmer(wordCharacters: string): (token: string) => string;\nexport declare function generateStopWordFilter(stopWords: string[]): (token: string) => string;\nexport declare class Among {\n    s_size: number;\n    s: number[];\n    substring_i: number;\n    result: number;\n    method: any;\n    constructor(s: string, substring_i: number, result: number, method?: any);\n}\nexport declare class SnowballProgram {\n    current: string;\n    bra: number;\n    ket: number;\n    limit: number;\n    cursor: number;\n    limit_backward: number;\n    constructor();\n    setCurrent(word: string): void;\n    getCurrent(): string;\n    in_grouping(s: number[], min: number, max: number): boolean;\n    in_grouping_b(s: number[], min: number, max: number): boolean;\n    out_grouping(s: number[], min: number, max: number): boolean;\n    out_grouping_b(s: number[], min: number, max: number): boolean;\n    eq_s(s_size: number, s: string): boolean;\n    eq_s_b(s_size: number, s: string): boolean;\n    find_among(v: Among[], v_size: number): number;\n    find_among_b(v: Among[], v_size: number): number;\n    replace_s(c_bra: number, c_ket: number, s: string): number;\n    slice_check(): void;\n    slice_from(s: string): void;\n    slice_del(): void;\n    insert(c_bra: number, c_ket: number, s: string): void;\n    slice_to(): string;\n    eq_v_b(s: string): boolean;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search-language-de/src/german_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class GermanAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search-language-de/src/index.d.ts",
    "content": "import { GermanAnalyzer } from \"./german_analyzer\";\nexport { GermanAnalyzer };\nexport default GermanAnalyzer;\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search-language-en/src/english_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class EnglishAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/full-text-search-language-en/src/index.d.ts",
    "content": "import { EnglishAnalyzer } from \"./english_analyzer\";\nexport { EnglishAnalyzer };\nexport default EnglishAnalyzer;\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/indexed-storage/src/index.d.ts",
    "content": "import { IndexedStorage } from \"./indexed_storage\";\nexport { IndexedStorage };\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/indexed-storage/src/indexed_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * Loki persistence adapter class for indexedDb.\n *     This class fulfills abstract adapter interface which can be applied to other storage methods.\n *     Utilizes the included LokiCatalog app/key/value database for actual database persistence.\n *     IndexedDb storage is provided per-domain, so we implement app/key/value database to\n *     allow separate contexts for separate apps within a domain.\n */\nexport declare class IndexedStorage implements StorageAdapter {\n    private _appname;\n    private catalog;\n    /**\n     * Registers the indexed storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the indexed storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {string} [appname=loki] - Application name context can be used to distinguish subdomains, \"loki\" by default\n     */\n    constructor(appname?: string);\n    /**\n     * Retrieves a serialized db string from the catalog.\n     *\n     * @example\n     * // LOAD\n     * var idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * var db = new loki(\"test\", { adapter: idbAdapter });\n     *   db.base(function(result) {\n       *   console.log(\"done\");\n       * });\n     *\n     * @param {string} dbname - the name of the database to retrieve.\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<{}>;\n    /**\n     * Saves a serialized db to the catalog.\n     *\n     * @example\n     * // SAVE : will save App/Key/Val as \"finance\"/\"test\"/{serializedDb}\n     * let idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * let db = new loki(\"test\", { adapter: idbAdapter });\n     * let coll = db.addCollection(\"testColl\");\n     * coll.insert({test: \"val\"});\n     * db.saveDatabase();  // could pass callback if needed for async complete\n     *\n     * @param {string} dbname - the name to give the serialized database within the catalog.\n     * @param {string} dbstring - the serialized db string to save.\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a serialized db from the catalog.\n     *\n     * @example\n     * // DELETE DATABASE\n     * // delete \"finance\"/\"test\" value from catalog\n     * idbAdapter.deleteDatabase(\"test\", function {\n       *   // database deleted\n       * });\n     *\n     * @param {string} dbname - the name of the database to delete from the catalog.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n    /**\n     * Removes all database partitions and pages with the base filename passed in.\n     * This utility method does not (yet) guarantee async deletions will be completed before returning\n     *\n     * @param {string} dbname - the base filename which container, partitions, or pages are derived\n     */\n    deleteDatabasePartitions(dbname: string): void;\n    /**\n     * Retrieves object array of catalog entries for current app.\n     *\n     * @example\n     * idbAdapter.getDatabaseList(function(result) {\n       *   // result is array of string names for that appcontext (\"finance\")\n       *   result.forEach(function(str) {\n       *     console.log(str);\n       *   });\n       * });\n     *\n     * @param {function} callback - should accept array of database names in the catalog for current app.\n     */\n    getDatabaseList(callback: (names: string[]) => void): void;\n    /**\n     * Allows retrieval of list of all keys in catalog along with size\n     * @param {function} callback - (Optional) callback to accept result array.\n     */\n    getCatalogSummary(callback: (entry: Entry[]) => void): void;\n}\nexport interface Entry {\n    app: string;\n    key: string;\n    size: number;\n}\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/local-storage/src/index.d.ts",
    "content": "import { LocalStorage } from \"./local_storage\";\nexport { LocalStorage };\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/local-storage/src/local_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists to web browser's local storage object\n * @constructor LocalStorageAdapter\n */\nexport declare class LocalStorage implements StorageAdapter {\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * loadDatabase() - Load data from localstorage\n     * @param {string} dbname - the name of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * saveDatabase() - save data to localstorage, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was saved\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * deleteDatabase() - delete the database from localstorage, will throw an error if it\n     * can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/loki/src/avl_index.d.ts",
    "content": "import { IRangedIndex, IRangedIndexRequest } from \"./ranged_indexes\";\nimport { ILokiComparer } from \"./comparators\";\n/**\n * Treenode type for binary search tree (BST) implementation.\n *\n * To support duplicates, we may need to either repurpose parent to\n * point to 'elder' sibling or add a siblingId to point to owner of\n * node represented in tree.\n */\nexport declare type TreeNode<T> = {\n    id: number;\n    value: T;\n    parent: number | null;\n    balance: number;\n    height: number;\n    left: number | null;\n    right: number | null;\n    siblings: number[];\n};\nexport interface ITreeNodeHash<T> {\n    [id: number]: TreeNode<T>;\n}\n/**\n * LokiDB AVL Balanced Binary Tree Index implementation.\n * To support duplicates, we use siblings (array) in tree nodes.\n * Basic AVL components guided by William Fiset tutorials at :\n * https://github.com/williamfiset/data-structures/blob/master/com/williamfiset/datastructures/balancedtree/AVLTreeRecursive.java\n * https://www.youtube.com/watch?v=g4y2h70D6Nk&list=PLDV1Zeh2NRsD06x59fxczdWLhDDszUHKt\n */\nexport declare class AvlTreeIndex<T> implements IRangedIndex<T> {\n    name: string;\n    comparator: ILokiComparer<T>;\n    nodes: ITreeNodeHash<T>;\n    apex: number | null;\n    /**\n     * Initializes index with property name and a comparer function.\n     */\n    constructor(name: string, comparator: ILokiComparer<T>);\n    backup(): AvlTreeIndex<T>;\n    restore(tree: AvlTreeIndex<T>): void;\n    /**\n     * Used for inserting a new value into the BinaryTreeIndex\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val Value to be indexed and inserted into binary tree\n     */\n    insert(id: number, val: T): void;\n    /**\n     * Recursively inserts a treenode and re-balances if needed.\n     * @param current\n     * @param node\n     */\n    insertNode(current: TreeNode<T>, node: TreeNode<T>): number;\n    /**\n     * Updates height and balance (calculation) for tree node\n     * @param node\n     */\n    private updateBalance(node);\n    /**\n     * Balance the 'double left-heavy' condition\n     * @param node\n     */\n    private leftLeftCase(node);\n    /**\n     * Balance the '(parent) left heavy, (child) right heavy' condition\n     * @param node\n     */\n    private leftRightCase(node);\n    /**\n     * Balance the 'double right-heavy' condition\n     * @param node\n     */\n    private rightRightCase(node);\n    /**\n     * Balance the '(parent) right heavy, (child) left heavy' condition\n     * @param node\n     */\n    private rightLeftCase(node);\n    /**\n     * Left rotation of node. Swaps right child into current location.\n     * @param node\n     */\n    private rotateLeft(node);\n    /**\n     * Right rotation of node. Swaps left child into current location.\n     * @param node\n     */\n    private rotateRight(node);\n    /**\n     * Diagnostic method for examining tree contents and structure\n     * @param node\n     */\n    getValuesAsTree(node?: TreeNode<T>): any;\n    /**\n     * Updates a value, possibly relocating it, within binary tree\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val New value to be indexed within binary tree\n     */\n    update(id: number, val: T): void;\n    /**\n     * Removes a value from the binary tree index\n     * @param id\n     */\n    remove(id: number): void;\n    /**\n     * Recursive node removal and rebalancer\n     * @param node\n     * @param val\n     */\n    private removeNode(node, id);\n    /**\n     * Utility method for updating a parent's child link when it changes\n     * @param parentId\n     * @param oldChildId\n     * @param newChildId\n     */\n    private updateChildLink(parentId, oldChildId, newChildId);\n    /**\n     * When removing a parent with only child, this does simple remap of child to grandParent.\n     * @param grandParent New parent of 'child'.\n     * @param parent Node being removed.\n     * @param child Node to reparent to grandParent.\n     */\n    private promoteChild(parent, child);\n    /**\n     * Finds a successor to a node and replaces that node with it.\n     * @param node\n     */\n    private promoteSuccessor(node);\n    /**\n     * Utility method for finding In-Order predecessor to the provided node\n     * @param node Parent node to find leaf node of greatest 'value'\n    */\n    private findGreaterLeaf(node);\n    /**\n     * Utility method for finding In-Order successor to the provided node\n     * @param node Parent Node to find leaf node of least 'value'\n     */\n    private findLesserLeaf(node);\n    /**\n     *  Interface method to support ranged queries.  Results sorted by index property.\n     * @param range Options for ranged request.\n     */\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    /**\n     * Implements ranged request operations.\n     * @param node\n     * @param range\n     */\n    private collateRequest(node, range);\n    /**\n     * Used on a branch node to return an array of id within that branch, sorted by their value\n     * @param node\n     */\n    private collateIds(node);\n    /**\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    /**\n     * Inline/Non-recusive 'single value' ($eq) lookup.\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    private locate(node, val);\n    /**\n     * Index integrity check (IRangedIndex interface function)\n     */\n    validateIndex(): boolean;\n    /**\n     * Recursive Node validation routine\n     * @param node\n     */\n    private validateNode(node);\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/loki/src/clone.d.ts",
    "content": "export declare type CloneMethod = \"parse-stringify\" | \"deep\" | \"shallow\" | \"shallow-recurse\";\n/**\n * @hidden\n */\nexport declare function clone<T>(data: T, method?: CloneMethod): T;\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/loki/src/collection.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { UniqueIndex } from \"./unique_index\";\nimport { ResultSet } from \"./result_set\";\nimport { DynamicView } from \"./dynamic_view\";\nimport { IRangedIndex } from \"./ranged_indexes\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc, Dict } from \"../../common/types\";\nimport { FullTextSearch } from \"../../full-text-search/src/full_text_search\";\nimport { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\n/**\n * Collection class that handles documents of same type\n * @extends LokiEventEmitter\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class Collection<TData extends object = object, TNested extends object = object, T extends TData & TNested = TData & TNested> extends LokiEventEmitter {\n    name: string;\n    _data: Doc<T>[];\n    private _idIndex;\n    _rangedIndexes: {\n        [P in keyof T]?: Collection.RangedIndexMeta;\n    };\n    _lokimap: {\n        [$loki: number]: Doc<T>;\n    };\n    _unindexedSortComparator: string;\n    _defaultLokiOperatorPackage: string;\n    /**\n     * Unique constraints contain duplicate object references, so they are not persisted.\n     * We will keep track of properties which have unique constraints applied here, and regenerate on load.\n     */\n    _constraints: {\n        unique: {\n            [P in keyof T]?: UniqueIndex;\n        };\n    };\n    /**\n     * Transforms will be used to store frequently used query chains as a series of steps which itself can be stored along\n     * with the database.\n     */\n    _transforms: Dict<Collection.Transform<T>[]>;\n    /**\n     * In autosave scenarios we will use collection level dirty flags to determine whether save is needed.\n     * currently, if any collection is dirty we will autosave the whole database if autosave is configured.\n     * Defaulting to true since this is called from addCollection and adding a collection should trigger save.\n     */\n    _dirty: boolean;\n    private _cached;\n    /**\n     * Is collection transactional.\n     */\n    private _transactional;\n    /**\n     * Options to clone objects when inserting them.\n     */\n    _cloneObjects: boolean;\n    /**\n     * Default clone method (if enabled) is parse-stringify.\n     */\n    _cloneMethod: CloneMethod;\n    /**\n     * If set to true we will not maintain a meta property for a document.\n     */\n    private _disableMeta;\n    /**\n     * Disable track changes.\n     */\n    private _disableChangesApi;\n    /**\n     * Disable delta update object style on changes.\n     */\n    _disableDeltaChangesApi: boolean;\n    /**\n     * By default, if you insert a document with a Date value for an indexed property, we will convert that value to number.\n     */\n    private _serializableIndexes;\n    /**\n     * Name of path of used nested properties.\n     */\n    private _nestedProperties;\n    /**\n     * Option to activate a cleaner daemon - clears \"aged\" documents at set intervals.\n     */\n    _ttl: Collection.TTL;\n    private _maxId;\n    private _dynamicViews;\n    /**\n     * Changes are tracked by collection and aggregated by the db.\n     */\n    private _changes;\n    /**\n     * stages: a map of uniquely identified 'stages', which hold copies of objects to be\n     * manipulated without affecting the data in the original collection\n     */\n    private _stages;\n    private _commitLog;\n    _fullTextSearch: FullTextSearch;\n    /**\n     * @param {string} name - collection name\n     * @param {(object)} [options={}] - a configuration object\n     * @param {string[]} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {string[]} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {RangedIndexOptions} [options.rangedIndexes] - configuration object for ranged indexes\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are invoked asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes API\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {boolean} [options.serializableIndexes=true] - converts date values on binary indexed property values are serializable\n     * @param {string} [options.cloneMethod=\"deep\"] - the clone method\n     * @param {number} [options.transactional=false] - ?\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale.\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @param {string} [options.unindexedSortComparator=\"js\"] \"js\", \"abstract\", \"abstract-date\", \"loki\" or other registered comparator name\n     * @param {string} [options.defaultLokiOperatorPackage=\"js\"] \"js\", \"loki\", \"comparator\" (or user defined) query ops package\n     * @param {FullTextSearch.FieldOptions} [options.fullTextSearch=] - the full-text search options\n     * @see {@link Loki#addCollection} for normal creation of collections\n     */\n    constructor(name: string, options?: Collection.Options<TData, TNested>);\n    toJSON(): Collection.Serialized;\n    static fromJSONObject(obj: Collection.Serialized, options?: Collection.DeserializeOptions): Collection<any, object, any>;\n    /**\n     * Adds a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {array} transform - an array of transformation 'step' objects to save into the collection\n     */\n    addTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Retrieves a named transform from the collection.\n     * @param {string} name - name of the transform to lookup.\n     */\n    getTransform(name: string): Collection.Transform<T>[];\n    /**\n     * Updates a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {object} transform - a transformation object to save into collection\n     */\n    setTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Removes a named collection transform from the collection\n     * @param {string} name - name of collection transform to remove\n     */\n    removeTransform(name: string): void;\n    private setTTL(age, interval);\n    /**\n     * Create a row filter that covers all documents in the collection.\n     */\n    _prepareFullDocIndex(): number[];\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field\n     * @param indexTypeName\n     * @param comparatorName\n     */\n    ensureIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field Property to create an index on (need to look into contraining on keyof T)\n     * @param indexTypeName Name of IndexType factory within (global?) hashmap to create IRangedIndex from\n     * @param comparatorName Name of Comparator within (global?) hashmap\n     */\n    ensureRangedIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    ensureUniqueIndex(field: keyof T): UniqueIndex;\n    /**\n     * Quickly determine number of documents in collection (or query)\n     * @param {object} query - (optional) query object to count results of\n     * @returns {number} number of documents in the collection\n     */\n    count(query?: ResultSet.Query<Doc<T>>): number;\n    /**\n     * Rebuild idIndex\n     */\n    private _ensureId();\n    /**\n     * Add a dynamic view to the collection\n     * @param {string} name - name of dynamic view to add\n     * @param {object} options - (optional) options to configure dynamic view with\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=SortPriority.PASSIVE] - the sort priority\n     * @param {number} options.minRebuildInterval - minimum rebuild interval (need clarification to docs here)\n     * @returns {DynamicView} reference to the dynamic view added\n     **/\n    addDynamicView(name: string, options?: DynamicView.Options): DynamicView<T>;\n    /**\n     * Remove a dynamic view from the collection\n     * @param {string} name - name of dynamic view to remove\n     **/\n    removeDynamicView(name: string): void;\n    /**\n     * Look up dynamic view reference from within the collection\n     * @param {string} name - name of dynamic view to retrieve reference of\n     * @returns {DynamicView} A reference to the dynamic view with that name\n     **/\n    getDynamicView(name: string): DynamicView<T>;\n    /**\n     * Applies a 'mongo-like' find query object and passes all results to an update function.\n     * @param {object} filterObject - the 'mongo-like' query object\n     * @param {function} updateFunction - the update function\n     */\n    findAndUpdate(filterObject: ResultSet.Query<Doc<T>>, updateFunction: (obj: Doc<T>) => any): void;\n    /**\n     * Applies a 'mongo-like' find query object removes all documents which match that filter.\n     * @param {object} filterObject - 'mongo-like' query object\n     */\n    findAndRemove(filterObject: ResultSet.Query<Doc<T>>): void;\n    /**\n     * Adds object(s) to collection, ensure object(s) have meta properties, clone it if necessary, etc.\n     * @param {(object|array)} doc - the document (or array of documents) to be inserted\n     * @returns {(object|array)} document or documents inserted\n     */\n    insert(doc: TData): Doc<T>;\n    insert(doc: TData[]): Doc<T>[];\n    /**\n     * Adds a single object, ensures it has meta properties, clone it if necessary, etc.\n     * @param {object} doc - the document to be inserted\n     * @param {boolean} bulkInsert - quiet pre-insert and insert event emits\n     * @returns {object} document or 'undefined' if there was a problem inserting it\n     */\n    insertOne(doc: TData, bulkInsert?: boolean): Doc<T>;\n    /**\n     * Refers nested properties of an object to the root of it.\n     * @param {T} data - the object\n     * @returns {T & TNested} the object with nested properties\n     * @hidden\n     */\n    _defineNestedProperties<U extends TData>(data: U): U & TNested;\n    /**\n     * Empties the collection.\n     * @param {boolean} [removeIndices=false] - remove indices\n     */\n    clear({removeIndices: removeIndices}?: {\n        removeIndices?: boolean;\n    }): void;\n    /**\n     * Updates an object and notifies collection that the document has changed.\n     * @param {object} doc - document to update within the collection\n     */\n    update(doc: Doc<T> | Doc<T>[]): void;\n    /**\n     * Add object to collection\n     */\n    private _add(obj);\n    /**\n     * Applies a filter function and passes all results to an update function.\n     * @param {function} filterFunction - the filter function\n     * @param {function} updateFunction - the update function\n     */\n    updateWhere(filterFunction: (obj: Doc<T>) => boolean, updateFunction: (obj: Doc<T>) => Doc<T>): void;\n    /**\n     * Remove all documents matching supplied filter function.\n     * @param {function} filterFunction - the filter function\n     */\n    removeWhere(filterFunction: (obj: Doc<T>) => boolean): void;\n    removeDataOnly(): void;\n    /**\n     * Remove a document from the collection\n     * @param {number|object} doc - document to remove from collection\n     */\n    remove(doc: number | Doc<T> | Doc<T>[]): void;\n    /**\n     * Returns all changes.\n     * @returns {Collection.Change[]}\n     */\n    getChanges(): Collection.Change[];\n    /**\n     * Enables/disables changes api.\n     * @param {boolean} disableChangesApi\n     * @param {boolean} disableDeltaChangesApi\n     */\n    setChangesApi(disableChangesApi: boolean, disableDeltaChangesApi?: boolean): void;\n    /**\n     * Clears all the changes.\n     */\n    flushChanges(): void;\n    private _getObjectDelta(oldObject, newObject);\n    /**\n     * Compare changed object (which is a forced clone) with existing object and return the delta\n     */\n    private _getChangeDelta(obj, old);\n    /**\n     * Creates a clone of the current status of an object and associates operation and collection name,\n     * so the parent db can aggregate and generate a changes object for the entire db\n     */\n    private _createChange(name, op, obj, old?);\n    private _createInsertChange(obj);\n    private _createUpdateChange(obj, old);\n    private _insertMetaWithChange(obj);\n    private _updateMetaWithChange(obj, old);\n    private _insertMeta(obj);\n    private _updateMeta(obj);\n    /**\n     * Get by Id - faster than other methods because of the searching algorithm\n     * @param {int} id - $loki id of document you want to retrieve\n     * @param {boolean} returnPosition - if 'true' we will return [object, position]\n     * @returns {(object|array|null)} Object reference if document was found, null if not,\n     *     or an array if 'returnPosition' was passed.\n     */\n    get(id: number): Doc<T>;\n    get(id: number, returnPosition: boolean): Doc<T> | [Doc<T>, number];\n    /**\n     * Retrieve doc by Unique index\n     * @param {string} field - name of uniquely indexed property to use when doing lookup\n     * @param {any} value - unique value to search for\n     * @returns {object} document matching the value passed\n     */\n    by(field: keyof T, value: any): Doc<T>;\n    /**\n     * Find one object by index property, by property equal to value\n     * @param {object} query - query object used to perform search with\n     * @returns {(object|null)} First matching document, or null if none\n     */\n    findOne(query: ResultSet.Query<Doc<T>>): Doc<T>;\n    /**\n     * Chain method, used for beginning a series of chained find() and/or view() operations\n     * on a collection.\n     *\n     * @param {array} transform - Ordered array of transform step objects similar to chain\n     * @param {object} parameters - Object containing properties representing parameters to substitute\n     * @returns {ResultSet} (this) ResultSet, or data array if any map or join functions where called\n     */\n    chain(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Find method, api is similar to mongodb.\n     * for more complex queries use [chain()]{@link Collection#chain} or [where()]{@link Collection#where}.\n     * @example {@tutorial Query Examples}\n     * @param {object} query - 'mongo-like' query object\n     * @returns {array} Array of matching documents\n     */\n    find(query?: ResultSet.Query<Doc<T>>): Doc<T>[];\n    /**\n     * Find object by unindexed field by property equal to value,\n     * simply iterates and returns the first element matching the query\n     */\n    findOneUnindexed(prop: string, value: any): Doc<T>;\n    /**\n     * Transaction methods\n     */\n    /**\n     * start the transation\n     */\n    startTransaction(): void;\n    /**\n     * Commit the transaction.\n     */\n    commit(): void;\n    /**\n     * Rollback the transaction.\n     */\n    rollback(): void;\n    /**\n     * Query the collection by supplying a javascript filter function.\n     * @example\n     * let results = coll.where(function(obj) {\n       *   return obj.legs === 8;\n       * });\n     * @param {function} fun - filter function to run against all collection docs\n     * @returns {array} all documents which pass your filter function\n     */\n    where(fun: (obj: Doc<T>) => boolean): Doc<T>[];\n    /**\n     * Map Reduce operation\n     * @param {function} mapFunction - function to use as map function\n     * @param {function} reduceFunction - function to use as reduce function\n     * @returns {data} The result of your mapReduce operation\n     */\n    mapReduce<U1, U2>(mapFunction: (value: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Join two collections on specified properties\n     * @param {array} joinData - array of documents to 'join' to this collection\n     * @param {string} leftJoinProp - property name in collection\n     * @param {string} rightJoinProp - property name in joinData\n     * @param {function} mapFun - (Optional) map function to use\n     * @param dataOptions - options to data() before input to your map function\n     * @param [dataOptions.removeMeta] - allows removing meta before calling mapFun\n     * @param [dataOptions.forceClones] - forcing the return of cloned objects to your map object\n     * @param [dataOptions.forceCloneMethod] - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} Result of the mapping operation\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinProp: string | ((obj: any) => string), rightJoinProp: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * (Staging API) create a stage and/or retrieve it\n     */\n    getStage(name: string): any;\n    /**\n     * a collection of objects recording the changes applied through a commmitStage\n     */\n    /**\n     * (Staging API) create a copy of an object and insert it into a stage\n     */\n    stage<F extends TData>(stageName: string, obj: Doc<F>): F;\n    /**\n     * (Staging API) re-attach all objects to the original collection, so indexes and views can be rebuilt\n     * then create a message to be inserted in the commitlog\n     * @param {string} stageName - name of stage\n     * @param {string} message\n     */\n    commitStage(stageName: string, message: string): void;\n    /**\n     * Returns all values of a field.\n     * @param {string} field - the field name\n     * @return {any}: the array of values\n     */\n    extract(field: keyof T): any[];\n    /**\n     * Finds the minimum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the minimum value\n     */\n    min(field: keyof T): number;\n    /**\n     * Finds the maximum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the maximum value\n     */\n    max(field: keyof T): number;\n    /**\n     * Finds the minimum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    minRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Finds the maximum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    maxRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Returns all values of a field as numbers (if possible).\n     * @param {string} field - the field name\n     * @return {number[]} - the number array\n     */\n    extractNumerical(field: keyof T): number[];\n    /**\n     * Calculates the average numerical value of a field\n     * @param {string} field - the field name\n     * @returns {number} average of property in all docs in the collection\n     */\n    avg(field: keyof T): number;\n    /**\n     * Calculate the standard deviation of a field.\n     * @param {string} field - the field name\n     * @return {number} the standard deviation\n     */\n    stdDev(field: keyof T): number;\n    /**\n     * Calculates the mode of a field.\n     * @param {string} field - the field name\n     * @return {number} the mode\n     */\n    mode(field: keyof T): number;\n    /**\n     * Calculates the median of a field.\n     * @param {string} field - the field name\n     * @return {number} the median\n     */\n    median(field: keyof T): number;\n}\nexport declare namespace Collection {\n    interface Options<TData extends object, TNested extends object = {}, T extends object = TData & TNested> {\n        unique?: (keyof T)[];\n        unindexedSortComparator?: string;\n        defaultLokiOperatorPackage?: string;\n        rangedIndexes?: RangedIndexOptions;\n        serializableIndexes?: boolean;\n        asyncListeners?: boolean;\n        disableMeta?: boolean;\n        disableChangesApi?: boolean;\n        disableDeltaChangesApi?: boolean;\n        clone?: boolean;\n        serializableIndices?: boolean;\n        cloneMethod?: CloneMethod;\n        transactional?: boolean;\n        ttl?: number;\n        ttlInterval?: number;\n        nestedProperties?: (keyof TNested | {\n            name: keyof TNested;\n            path: string[];\n        })[];\n        fullTextSearch?: FullTextSearch.FieldOptions[];\n    }\n    interface RangedIndexOptions {\n        [prop: string]: RangedIndexMeta;\n    }\n    interface DeserializeOptions {\n        retainDirtyFlags?: boolean;\n        fullTextSearch?: Dict<Analyzer>;\n        [collName: string]: any | {\n            proto?: any;\n            inflate?: (src: object, dest?: object) => void;\n        };\n    }\n    interface BinaryIndex {\n        dirty: boolean;\n        values: any;\n    }\n    interface RangedIndexMeta {\n        index?: IRangedIndex<any>;\n        indexTypeName?: string;\n        comparatorName?: string;\n    }\n    interface Change {\n        name: string;\n        operation: string;\n        obj: any;\n    }\n    interface Serialized {\n        name: string;\n        unindexedSortComparator: string;\n        defaultLokiOperatorPackage: string;\n        _dynamicViews: DynamicView[];\n        _nestedProperties: {\n            name: string;\n            path: string[];\n        }[];\n        uniqueNames: string[];\n        transforms: Dict<Transform[]>;\n        rangedIndexes: RangedIndexOptions;\n        _data: Doc<any>[];\n        idIndex: number[];\n        maxId: number;\n        _dirty: boolean;\n        transactional: boolean;\n        asyncListeners: boolean;\n        disableMeta: boolean;\n        disableChangesApi: boolean;\n        disableDeltaChangesApi: boolean;\n        cloneObjects: boolean;\n        cloneMethod: CloneMethod;\n        changes: any;\n        _fullTextSearch: FullTextSearch;\n    }\n    interface CheckIndexOptions {\n        randomSampling?: boolean;\n        randomSamplingFactor?: number;\n        repair?: boolean;\n    }\n    type Transform<T extends object = object> = {\n        type: \"find\";\n        value: ResultSet.Query<Doc<T>> | string;\n    } | {\n        type: \"where\";\n        value: ((obj: Doc<T>) => boolean) | string;\n    } | {\n        type: \"simplesort\";\n        property: keyof T;\n        options?: boolean | ResultSet.SimpleSortOptions;\n    } | {\n        type: \"compoundsort\";\n        value: (keyof T | [keyof T, boolean])[];\n    } | {\n        type: \"sort\";\n        value: (a: Doc<T>, b: Doc<T>) => number;\n    } | {\n        type: \"sortByScoring\";\n        desc?: boolean;\n    } | {\n        type: \"limit\";\n        value: number;\n    } | {\n        type: \"offset\";\n        value: number;\n    } | {\n        type: \"map\";\n        value: (obj: Doc<T>, index: number, array: Doc<T>[]) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"eqJoin\";\n        joinData: Collection<any> | ResultSet<any>;\n        leftJoinKey: string | ((obj: any) => string);\n        rightJoinKey: string | ((obj: any) => string);\n        mapFun?: (left: any, right: any) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"mapReduce\";\n        mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => any;\n        reduceFunction: (array: any[]) => any;\n    } | {\n        type: \"update\";\n        value: (obj: Doc<T>) => any;\n    } | {\n        type: \"remove\";\n    };\n    interface TTL {\n        age: number;\n        ttlInterval: number;\n        daemon: any;\n    }\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/loki/src/comparators.d.ts",
    "content": "export interface ILokiComparer<T> {\n    (a: T, b: T): -1 | 0 | 1;\n}\nexport interface IComparatorMap {\n    [name: string]: ILokiComparer<any>;\n}\n/** Map/Register of named ILokiComparer functions returning -1, 0, 1 for lt/eq/gt assertions for two passed parameters */\nexport declare let ComparatorMap: IComparatorMap;\n/** Typescript-friendly factory for strongly typed 'js' comparators */\nexport declare function CreateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'abstract js' comparators */\nexport declare function CreateAbstractJavascriptComparator<T>(): ILokiComparer<T>;\n/**\n * Comparator which attempts to deal with deal with dates at comparator level.\n * Should work for dates in any of the object, string, and number formats\n */\nexport declare function CreateAbstractDateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'loki' comparators */\nexport declare function CreateLokiComparator(): ILokiComparer<any>;\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/loki/src/dynamic_view.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { ResultSet } from \"./result_set\";\nimport { Collection } from \"./collection\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\n/**\n * DynamicView class is a versatile 'live' view class which can have filters and sorts applied.\n *    Collection.addDynamicView(name) instantiates this DynamicView object and notifies it\n *    whenever documents are add/updated/removed so it can remain up-to-date. (chainable)\n *\n * @example\n * let mydv = mycollection.addDynamicView('test');  // default is non-persistent\n * mydv.applyFind({ 'doors' : 4 });\n * mydv.applyWhere(function(obj) { return obj.name === 'Toyota'; });\n * let results = mydv.data();\n *\n * @extends LokiEventEmitter\n\n * @see {@link Collection#addDynamicView} to construct instances of DynamicView\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class DynamicView<T extends object = object> extends LokiEventEmitter {\n    readonly name: string;\n    private _collection;\n    private _persistent;\n    private _sortPriority;\n    private _minRebuildInterval;\n    private _rebuildPending;\n    private _resultSet;\n    private _resultData;\n    private _resultDirty;\n    private _cachedResultSet;\n    private _filterPipeline;\n    private _sortFunction;\n    private _sortCriteria;\n    private _sortCriteriaSimple;\n    private _sortByScoring;\n    private _sortDirty;\n    /**\n     * Constructor.\n     * @param {Collection} collection - a reference to the collection to work agains\n     * @param {string} name - the name of this dynamic view\n     * @param {object} options - the options\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=\"passive\"] - the sort priority\n     * @param {number} [options.minRebuildInterval=1] - minimum rebuild interval (need clarification to docs here)\n     */\n    constructor(collection: Collection<T>, name: string, options?: DynamicView.Options);\n    /**\n     * Internally used immediately after deserialization (loading)\n     *    This will clear out and reapply filterPipeline ops, recreating the view.\n     *    Since where filters do not persist correctly, this method allows\n     *    restoring the view to state where user can re-apply those where filters.\n     *\n     * @param removeWhereFilters\n     * @returns {DynamicView} This dynamic view for further chained ops.\n     * @fires DynamicView.rebuild\n     */\n    private _rematerialize({removeWhereFilters});\n    /**\n     * Makes a copy of the internal ResultSet for branched queries.\n     * Unlike this dynamic view, the branched ResultSet will not be 'live' updated,\n     * so your branched query should be immediately resolved and not held for future evaluation.\n     * @param {(string|array=)} transform - Optional name of collection transform, or an array of transform steps\n     * @param {object} parameters - optional parameters (if optional transform requires them)\n     * @returns {ResultSet} A copy of the internal ResultSet for branched queries.\n     */\n    branchResultSet(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Override of toJSON to avoid circular references.\n     */\n    toJSON(): DynamicView.Serialized;\n    static fromJSONObject(collection: Collection, obj: DynamicView.Serialized): DynamicView;\n    /**\n     * Used to clear pipeline and reset dynamic view to initial state.\n     * Existing options should be retained.\n     * @param {boolean} queueSortPhase - (default: false) if true we will async rebuild view (maybe set default to true in future?)\n     */\n    removeFilters({queueSortPhase}?: {\n        queueSortPhase?: boolean;\n    }): void;\n    /**\n     * Used to apply a sort to the dynamic view\n     * @example\n     * dv.applySort(function(obj1, obj2) {\n       *   if (obj1.name === obj2.name) return 0;\n       *   if (obj1.name > obj2.name) return 1;\n       *   if (obj1.name < obj2.name) return -1;\n       * });\n     * @param {function} comparefun - a javascript compare function used for sorting\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applySort(comparefun: (lhs: Doc<T>, rhs: Doc<T>) => number): this;\n    /**\n     * Used to specify a property used for view translation.\n     * @param {string} field - the field name\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether we should sort descending.\n     * @param {boolean} [options.disableIndexIntersect=false] - whether we should explicity not use array intersection.\n     * @param {boolean} [options.forceIndexIntersect=false] - force array intersection (if binary index exists).\n     * @param {boolean} [options.useJavascriptSorting=false] - whether results are sorted via basic javascript sort.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     * @example\n     * dv.applySimpleSort(\"name\");\n     */\n    applySimpleSort(field: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @param {Array} criteria - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {DynamicView} Reference to this DynamicView, sorted, for future chain operations.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * dv.applySortCriteria(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * dv.applySortCriteria(['age', ['name', true]]);\n     * // to sort by age (descending) and then by name (descending)\n     * dv.applySortCriteria([['age', true], ['name', true]]);\n     */\n    applySortCriteria(criteria: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Used to apply a sort by the latest full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     */\n    applySortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Marks the beginning of a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    startTransaction(): this;\n    /**\n     * Commits a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    commit(): this;\n    /**\n     * Rolls back a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    rollback(): this;\n    /**\n     * Find the index of a filter in the pipeline, by that filter's ID.\n     * @param {(string|number)} uid - The unique ID of the filter.\n     * @returns {number}: index of the referenced filter in the pipeline; -1 if not found.\n     */\n    private _indexOfFilterWithId(uid);\n    /**\n     * Add the filter object to the end of view's filter pipeline and apply the filter to the ResultSet.\n     * @param {object} filter - The filter object. Refer to applyFilter() for extra details.\n     */\n    private _addFilter(filter);\n    /**\n     * Reapply all the filters in the current pipeline.\n     *\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    reapplyFilters(): this;\n    /**\n     * Adds or updates a filter in the DynamicView filter pipeline\n     * @param {object} filter - A filter object to add to the pipeline.\n     *    The object is in the format { 'type': filter_type, 'val', filter_param, 'uid', optional_filter_id }\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFilter(filter: DynamicView.Filter<T>): this;\n    /**\n     * applyFind() - Adds or updates a mongo-style query option in the DynamicView filter pipeline\n     *\n     * @param {object} query - A mongo-style query object to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFind(query: object, uid?: string | number): this;\n    /**\n     * Adds or updates a javascript filter function in the DynamicView filter pipeline\n     * @param {function} fun - A javascript filter function to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyWhere(fun: (obj: Doc<T>) => boolean, uid?: string | number): this;\n    /**\n     * Remove the specified filter from the DynamicView filter pipeline\n     * @param {(string|number)} uid - The unique ID of the filter to be removed.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    removeFilter(uid: string | number): this;\n    /**\n     * Returns the number of documents representing the current DynamicView contents.\n     * @returns {number} The number of documents representing the current DynamicView contents.\n     */\n    count(): number;\n    /**\n     * Resolves and pending filtering and sorting, then returns document array as result.\n     * @param {object} options - optional parameters to pass to ResultSet.data() if non-persistent\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values include 'parse-stringify', 'jquery-extend-deep', 'shallow', 'shallow-assign'\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} An array of documents representing the current DynamicView contents.\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * When the view is not sorted we may still wish to be notified of rebuild events.\n     * This event will throttle and queue a single rebuild event when batches of updates affect the view.\n     */\n    private _queueRebuildEvent();\n    /**\n     * If the view is sorted we will throttle sorting to either :\n     * (1) passive - when the user calls data(), or\n     * (2) active - once they stop updating and yield js thread control\n     */\n    private _queueSortPhase();\n    /**\n     * Invoked synchronously or asynchronously to perform final sort phase (if needed)\n     */\n    private _performSortPhase(options?);\n    /**\n     * (Re)evaluating document inclusion.\n     * Called by : collection.insert() and collection.update().\n     * @param {int} objIndex - index of document to (re)run through filter pipeline.\n     * @param {boolean} isNew - true if the document was just added to the collection.\n     * @hidden\n     */\n    _evaluateDocument(objIndex: number, isNew: boolean): void;\n    /**\n     * Internal function called on collection.delete().\n     * @hidden\n     */\n    _removeDocument(objIndex: number): void;\n    /**\n     * Data transformation via user supplied functions\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: T, index: number, array: T[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n}\nexport declare namespace DynamicView {\n    interface Options {\n        persistent?: boolean;\n        sortPriority?: SortPriority;\n        minRebuildInterval?: number;\n    }\n    type SortPriority = \"passive\" | \"active\";\n    interface Serialized {\n        name: string;\n        _persistent: boolean;\n        _sortPriority: SortPriority;\n        _minRebuildInterval: number;\n        _resultSet: ResultSet<any>;\n        _filterPipeline: Filter<any>[];\n        _sortCriteria: (string | [string, boolean])[];\n        _sortCriteriaSimple: {\n            field: string;\n            options: boolean | ResultSet.SimpleSortOptions;\n        };\n        _sortByScoring: boolean;\n        _sortDirty: boolean;\n    }\n    type Filter<T extends object = object> = {\n        type: \"find\";\n        val: ResultSet.Query<Doc<T>>;\n        uid: number | string;\n    } | {\n        type: \"where\";\n        val: (obj: Doc<T>) => boolean;\n        uid: number | string;\n    };\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/loki/src/event_emitter.d.ts",
    "content": "/**\n * LokiEventEmitter is a minimalist version of EventEmitter. It enables any\n * constructor that inherits EventEmitter to emit events and trigger\n * listeners that have been added to the event through the on(event, callback) method\n *\n * @constructor LokiEventEmitter\n */\nexport declare class LokiEventEmitter {\n    /**\n     * A map, with each property being an array of callbacks.\n     */\n    protected _events: object;\n    /**\n     * Determines whether or not the callbacks associated with each event should happen in an async fashion or not.\n     * Default is false, which means events are synchronous\n     */\n    protected _asyncListeners: boolean;\n    /**\n     * Adds a listener to the queue of callbacks associated to an event\n     * @param {string|string[]} eventName - the name(s) of the event(s) to listen to\n     * @param {function} listener - callback function of listener to attach\n     * @returns {int} the index of the callback in the array of listeners for a particular event\n     */\n    on(eventName: string | string[], listener: Function): Function;\n    /**\n     * Emits a particular event\n     * with the option of passing optional parameters which are going to be processed by the callback\n     * provided signatures match (i.e. if passing emit(event, arg0, arg1) the listener should take two parameters)\n     * @param {string} eventName - the name of the event\n     * @param {object} data - optional object passed with the event\n     */\n    protected emit(eventName: string, ...data: any[]): void;\n    /**\n     * Alias of EventEmitter.on().\n     */\n    addListener(eventName: string | string[], listener: Function): Function;\n    /**\n     * Removes the listener at position 'index' from the event 'eventName'\n     * @param {string|string[]} eventName - the name(s) of the event(s) which the listener is attached to\n     * @param {function} listener - the listener callback function to remove from emitter\n     */\n    removeListener(eventName: string | string[], listener: Function): void;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/loki/src/index.d.ts",
    "content": "import { Loki } from \"./loki\";\nimport { Collection } from \"./collection\";\nexport { Loki, Collection };\nexport default Loki;\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/loki/src/loki.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { Collection } from \"./collection\";\nimport { Doc, StorageAdapter } from \"../../common/types\";\nimport { IComparatorMap } from \"./comparators\";\nimport { IRangedIndexFactoryMap } from \"./ranged_indexes\";\nimport { ILokiOperatorPackageMap } from \"./operator_packages\";\nexport declare class Loki extends LokiEventEmitter {\n    filename: string;\n    private databaseVersion;\n    private engineVersion;\n    _collections: Collection[];\n    private _env;\n    private _serializationMethod;\n    private _destructureDelimiter;\n    private _persistenceMethod;\n    private _persistenceAdapter;\n    private _throttledSaves;\n    private _throttledSaveRunning;\n    private _throttledSavePending;\n    private _autosave;\n    private _autosaveInterval;\n    private _autosaveRunning;\n    private _autosaveHandler;\n    /**\n     * Constructs the main database class.\n     * @param {string} filename - name of the file to be saved to\n     * @param {object} [options={}] - options\n     * @param {Loki.Environment} [options.env] - the javascript environment\n     * @param {Loki.SerializationMethod} [options.serializationMethod=NORMAL] - the serialization method\n     * @param {string} [options.destructureDelimiter=\"$<\\n\"] - string delimiter used for destructured serialization\n     * @param {IComparatorMap} [options.comparatorMap] allows injecting or overriding registered comparators\n     * @param {IRangedIndexFactoryMap} [options.rangedIndexFactoryMap] allows injecting or overriding registered ranged index factories\n     * @param {ILokiOperatorPackageMap} [options.lokiOperatorPackageMap] allows injecting or overriding registered loki operator packages\n     */\n    constructor(filename?: string, options?: Loki.Options);\n    /**\n     * configures options related to database persistence.\n     *\n     * @param {Loki.PersistenceOptions} [options={}] - options\n     * @param {adapter} [options.adapter=auto] - an instance of a loki persistence adapter\n     * @param {boolean} [options.autosave=false] - enables autosave\n     * @param {int} [options.autosaveInterval=5000] - time interval (in milliseconds) between saves (if dirty)\n     * @param {boolean} [options.autoload=false] - enables autoload on loki instantiation\n     * @param {object} options.inflate - options that are passed to loadDatabase if autoload enabled\n     * @param {boolean} [options.throttledSaves=true] - if true, it batches multiple calls to to saveDatabase reducing number of\n     *   disk I/O operations and guaranteeing proper serialization of the calls. Default value is true.\n     * @param {Loki.PersistenceMethod} options.persistenceMethod - a persistence method which should be used (FS_STORAGE, LOCAL_STORAGE...)\n     * @returns {Promise} a Promise that resolves after initialization and (if enabled) autoloading the database\n     */\n    initializePersistence(options?: Loki.PersistenceOptions): Promise<void>;\n    /**\n     * Copies 'this' database into a new Loki instance. Object references are shared to make lightweight.\n     * @param {object} options - options\n     * @param {boolean} options.removeNonSerializable - nulls properties not safe for serialization.\n     */\n    copy(options?: Loki.CopyOptions): Loki;\n    /**\n     * Adds a collection to the database.\n     * @param {string} name - name of collection to add\n     * @param {object} [options={}] - options to configure collection with.\n     * @param {array} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {array} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {array} [options.indices=[]] - array property names to define binary indexes for\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are called asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes Api\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {string} [options.cloneMethod=CloneMethod.DEEP] - the clone method\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @returns {Collection} a reference to the collection which was just added\n     */\n    addCollection<TData extends object = object, TNested extends object = object>(name: string, options?: Collection.Options<TData, TNested>): Collection<TData, TNested>;\n    loadCollection(collection: Collection): void;\n    /**\n     * Retrieves reference to a collection by name.\n     * @param {string} name - name of collection to look up\n     * @returns {Collection} Reference to collection in database by that name, or null if not found\n     */\n    getCollection<TData extends object = object, TNested extends object = object>(name: string): Collection<TData, TNested>;\n    /**\n     * Renames an existing loki collection\n     * @param {string} oldName - name of collection to rename\n     * @param {string} newName - new name of collection\n     * @returns {Collection} reference to the newly renamed collection\n     */\n    renameCollection<TData extends object = object, TNested extends object = object>(oldName: string, newName: string): Collection<TData, TNested>;\n    listCollections(): {\n        name: string;\n        count: number;\n    }[];\n    /**\n     * Removes a collection from the database.\n     * @param {string} collectionName - name of collection to remove\n     */\n    removeCollection(collectionName: string): void;\n    /**\n     * Serialize database to a string which can be loaded via {@link Loki#loadJSON}\n     *\n     * @returns {string} Stringified representation of the loki database.\n     */\n    serialize(options?: Loki.SerializeOptions): string | string[];\n    toJSON(): Loki.Serialized;\n    /**\n     * Database level destructured JSON serialization routine to allow alternate serialization methods.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {object} options - output format options for use externally to loki\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to only output an individual collection or db (-1)\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {string|Array} A custom, restructured aggregation of independent serializations.\n     */\n    serializeDestructured(options?: Loki.SerializeDestructuredOptions): string | string[];\n    /**\n     * Collection level utility method to serialize a collection in a 'destructured' format\n     *\n     * @param {object} options - used to determine output of method\n     * @param {int} options.delimited - whether to return single delimited string or an array\n     * @param {string} options.delimiter - (optional) if delimited, this is delimiter to use\n     * @param {int} options.collectionIndex -  specify which collection to serialize data for\n     *\n     * @returns {string|array} A custom, restructured aggregation of independent serializations for a single collection.\n     */\n    serializeCollection(options?: {\n        delimited?: boolean;\n        collectionIndex?: number;\n        delimiter?: string;\n    }): string | string[];\n    /**\n     * Database level destructured JSON deserialization routine to minimize memory overhead.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {string|array} destructuredSource - destructured json or array to deserialize from\n     * @param {object} options - source format options\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to deserialize only a single partition\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {object|array} An object representation of the deserialized database, not yet applied to 'this' db or document array\n     */\n    deserializeDestructured(destructuredSource: string | string[], options?: Loki.SerializeDestructuredOptions): any;\n    /**\n     * Collection level utility function to deserializes a destructured collection.\n     *\n     * @param {string|string[]} destructuredSource - destructured representation of collection to inflate\n     * @param {object} options - used to describe format of destructuredSource input\n     * @param {int} [options.delimited=false] - whether source is delimited string or an array\n     * @param {string} options.delimiter - if delimited, this is delimiter to use (if other than default)\n     *\n     * @returns {Array} an array of documents to attach to collection.data.\n     */\n    deserializeCollection<T extends object = object>(destructuredSource: string | string[], options?: Loki.DeserializeCollectionOptions): Doc<T>[];\n    /**\n     * Inflates a loki database from a serialized JSON string\n     *\n     * @param {string} serializedDb - a serialized loki database string\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSON(serializedDb: string | string[], options?: Collection.DeserializeOptions): void;\n    /**\n     * Inflates a loki database from a JS object\n     *\n     * @param {object} dbObject - a serialized loki database object\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSONObject(dbObject: Loki, options?: Collection.DeserializeOptions): void;\n    loadJSONObject(dbObject: Loki.Serialized, options?: Collection.DeserializeOptions): void;\n    /**\n     * Emits the close event. In autosave scenarios, if the database is dirty, this will save and disable timer.\n     * Does not actually destroy the db.\n     *\n     * @returns {Promise} a Promise that resolves after closing the database succeeded\n     */\n    close(): Promise<void>;\n    /**-------------------------+\n     | Changes API               |\n     +--------------------------*/\n    /**\n     * The Changes API enables the tracking the changes occurred in the collections since the beginning of the session,\n     * so it's possible to create a differential dataset for synchronization purposes (possibly to a remote db)\n     */\n    /**\n     * (Changes API) : takes all the changes stored in each\n     * collection and creates a single array for the entire database. If an array of names\n     * of collections is passed then only the included collections will be tracked.\n     *\n     * @param {Array} [arrayOfCollectionNames=] - array of collection names. No arg means all collections are processed.\n     * @returns {Array} array of changes\n     * @see private method _createChange() in Collection\n     */\n    generateChangesNotification(arrayOfCollectionNames?: string[]): Collection.Change[];\n    /**\n     * (Changes API) - stringify changes for network transmission\n     * @returns {string} string representation of the changes\n     */\n    serializeChanges(collectionNamesArray?: string[]): string;\n    /**\n     * (Changes API) : clears all the changes in all collections.\n     */\n    clearChanges(): void;\n    /**\n     * Wait for throttledSaves to complete and invoke your callback when drained or duration is met.\n     *\n     * @param {object} options - configuration options\n     * @param {boolean} [options.recursiveWait=true] - if after queue is drained, another save was kicked off, wait for it\n     * @param {boolean} [options.recursiveWaitLimit=false] - limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDuration=2000] - cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves when save queue is drained, it is passed a sucess parameter value\n     */\n    throttledSaveDrain(options?: Loki.ThrottledDrainOptions): Promise<void>;\n    /**\n     * Internal load logic, decoupled from throttling/contention logic\n     *\n     * @param {object} options - an object containing inflation options for each collection\n     * @param {boolean} ignore_not_found - does not raise an error if database is not found\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    private _loadDatabase(options?, ignore_not_found?);\n    /**\n     * Handles manually loading from an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *    To avoid contention with any throttledSaves, we will drain the save queue first.\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @param {object} [options={}] - if throttling saves and loads, this controls how we drain save queue before loading\n     * @param {boolean} [options.recursiveWait=true] wait recursively until no saves are queued\n     * @param {boolean} [options.recursiveWaitLimit=false] limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDelay=2000] cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    loadDatabase(options?: Loki.LoadDatabaseOptions): Promise<void>;\n    private _saveDatabase();\n    /**\n     * Handles manually saving to an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @returns {Promise} a Promise that resolves after the database is persisted\n     */\n    saveDatabase(): Promise<void>;\n    /**\n     * Handles deleting a database from the underlying storage adapter\n     *\n     * @returns {Promise} a Promise that resolves after the database is deleted\n     */\n    deleteDatabase(): Promise<void>;\n    /****************\n     * Autosave API\n     ****************/\n    /**\n     * Check whether any collections are \"dirty\" meaning we need to save the (entire) database\n     * @returns {boolean} - true if database has changed since last autosave, otherwise false\n     */\n    private _autosaveDirty();\n    /**\n     * Resets dirty flags on all collections.\n     */\n    private _autosaveClearFlags();\n    /**\n     * Starts periodically saves to the underlying storage adapter.\n     */\n    private _autosaveEnable();\n    /**\n     * Stops the autosave interval timer.\n     */\n    private _autosaveDisable();\n}\nexport declare namespace Loki {\n    interface Options {\n        env?: Environment;\n        serializationMethod?: SerializationMethod;\n        destructureDelimiter?: string;\n        comparatorMap?: IComparatorMap;\n        rangedIndexFactoryMap?: IRangedIndexFactoryMap;\n        lokiOperatorPackageMap?: ILokiOperatorPackageMap;\n    }\n    interface PersistenceOptions {\n        adapter?: StorageAdapter;\n        autosave?: boolean;\n        autosaveInterval?: number;\n        autoload?: boolean;\n        throttledSaves?: boolean;\n        persistenceMethod?: Loki.PersistenceMethod;\n        inflate?: any;\n    }\n    interface CopyOptions {\n        removeNonSerializable?: boolean;\n    }\n    interface SerializeOptions {\n        serializationMethod?: SerializationMethod;\n    }\n    interface SerializeDestructuredOptions {\n        partitioned?: boolean;\n        partition?: number;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface DeserializeCollectionOptions {\n        partitioned?: boolean;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface ThrottledDrainOptions {\n        recursiveWait?: boolean;\n        recursiveWaitLimit?: boolean;\n        recursiveWaitLimitDuration?: number;\n        started?: Date;\n    }\n    interface Serialized {\n        _env: Environment;\n        _serializationMethod: SerializationMethod;\n        _autosave: boolean;\n        _autosaveInterval: number;\n        _collections: Collection[];\n        databaseVersion: number;\n        engineVersion: number;\n        filename: string;\n        _persistenceAdapter: StorageAdapter;\n        _persistenceMethod: PersistenceMethod;\n        _throttledSaves: boolean;\n    }\n    type LoadDatabaseOptions = Collection.DeserializeOptions & ThrottledDrainOptions;\n    type SerializationMethod = \"normal\" | \"pretty\" | \"destructured\";\n    type PersistenceMethod = \"fs-storage\" | \"local-storage\" | \"indexed-storage\" | \"memory-storage\" | \"adapter\";\n    type Environment = \"NATIVESCRIPT\" | \"NODEJS\" | \"CORDOVA\" | \"BROWSER\" | \"MEMORY\";\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/loki/src/operator_packages.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\n/** Hash interface for named LokiOperatorPackage registration */\nexport interface ILokiOperatorPackageMap {\n    [name: string]: LokiOperatorPackage;\n}\n/**\n * Helper function for determining 'loki' abstract equality which is a little more abstract than ==\n *     aeqHelper(5, '5') === true\n *     aeqHelper(5.0, '5') === true\n *     aeqHelper(new Date(\"1/1/2011\"), new Date(\"1/1/2011\")) === true\n *     aeqHelper({a:1}, {z:4}) === true (all objects sorted equally)\n *     aeqHelper([1, 2, 3], [1, 3]) === false\n *     aeqHelper([1, 2, 3], [1, 2, 3]) === true\n *     aeqHelper(undefined, null) === true\n * @param {any} prop1\n * @param {any} prop2\n * @returns {boolean}\n * @hidden\n */\nexport declare function aeqHelper(prop1: any, prop2: any): boolean;\n/**\n * Helper function for determining 'less-than' conditions for ops, sorting, and binary indices.\n *     In the future we might want $lt and $gt ops to use their own functionality/helper.\n *     Since binary indices on a property might need to index [12, NaN, new Date(), Infinity], we\n *     need this function (as well as gtHelper) to always ensure one value is LT, GT, or EQ to another.\n * @hidden\n */\nexport declare function ltHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @hidden\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} equal\n * @returns {boolean}\n */\nexport declare function gtHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} descending\n * @returns {number}\n * @hidden\n */\nexport declare function sortHelper(prop1: any, prop2: any, descending: boolean): number;\n/**\n * Default implementation of LokiOperatorPackage, using fastest javascript comparison operators.\n */\nexport declare class LokiOperatorPackage {\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n    $in(a: any, b: any): boolean;\n    $nin(a: any, b: any): boolean;\n    $keyin(a: string, b: object): boolean;\n    $nkeyin(a: string, b: object): boolean;\n    $definedin(a: string, b: object): boolean;\n    $undefinedin(a: string, b: object): boolean;\n    $regex(a: string, b: RegExp): boolean;\n    $containsNone(a: any, b: any): boolean;\n    $containsAny(a: any, b: any): boolean;\n    $contains(a: any, b: any): boolean;\n    $type(a: any, b: any): boolean;\n    $finite(a: number, b: boolean): boolean;\n    $size(a: any, b: any): boolean;\n    $len(a: any, b: any): boolean;\n    $where(a: any, b: any): boolean;\n    $not(a: any, b: any): boolean;\n    $and(a: any, b: any): boolean;\n    $or(a: any, b: any): boolean;\n    private doQueryOp(val, op);\n    private containsCheckFn(a);\n}\n/**\n * LokiOperatorPackage which utilizes abstract 'loki' comparisons for basic relational equality op implementations.\n */\nexport declare class LokiAbstractOperatorPackage extends LokiOperatorPackage {\n    constructor();\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * LokiOperatorPackage which utilizes provided comparator for basic relational equality op implementations.\n */\nexport declare class ComparatorOperatorPackage<T> extends LokiOperatorPackage {\n    comparator: ILokiComparer<T>;\n    constructor(comparator: ILokiComparer<T>);\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * Map/Register of named LokiOperatorPackages which implement all unindexed query ops within 'find' query objects\n */\nexport declare let LokiOperatorPackageMap: ILokiOperatorPackageMap;\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/loki/src/ranged_indexes.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\nexport declare type RangedValueOperator = \"$gt\" | \"$gte\" | \"$lt\" | \"$lte\" | \"$eq\" | \"$neq\" | \"$between\";\nexport interface IRangedIndexRequest<T> {\n    op: RangedValueOperator;\n    val: T;\n    high?: T;\n}\n/** Defines interface which all loki ranged indexes need to implement */\nexport interface IRangedIndex<T> {\n    insert(id: number, val: T): void;\n    update(id: number, val: T): void;\n    remove(id: number): void;\n    restore(tree: any): void;\n    backup(): IRangedIndex<T>;\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    validateIndex(): boolean;\n}\n/** Hash Interface for global ranged index factory map*/\nexport interface IRangedIndexFactoryMap {\n    [name: string]: (name: string, comparator: ILokiComparer<any>) => IRangedIndex<any>;\n}\n/** Map/Register of named factory functions returning IRangedIndex instances */\nexport declare let RangedIndexFactoryMap: IRangedIndexFactoryMap;\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/loki/src/result_set.d.ts",
    "content": "import { Collection } from \"./collection\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\nimport { Query as FullTextSearchQuery } from \"../../full-text-search/src/query_types\";\n/**\n * ResultSet class allowing chainable queries.  Intended to be instanced internally.\n *    Collection.find(), Collection.where(), and Collection.chain() instantiate this.\n *\n * @example\n *    mycollection.chain()\n *      .find({ 'doors' : 4 })\n *      .where(function(obj) { return obj.name === 'Toyota' })\n *      .data();\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class ResultSet<T extends object = object> {\n    _collection: Collection<T>;\n    _filteredRows: number[];\n    _filterInitialized: boolean;\n    private _scoring;\n    /**\n     * Constructor.\n     * @param {Collection} collection - the collection which this ResultSet will query against\n     */\n    constructor(collection: Collection<T>);\n    /**\n     * Reset the ResultSet to its initial state.\n     * @returns {ResultSet} Reference to this ResultSet, for future chain operations.\n     */\n    reset(): this;\n    /**\n     * Override of toJSON to avoid circular references\n     */\n    toJSON(): ResultSet<T>;\n    /**\n     * Allows you to limit the number of documents passed to next chain operation.\n     * A ResultSet copy() is made to avoid altering original ResultSet.\n     * @param {int} qty - The number of documents to return.\n     * @returns {ResultSet} Returns a copy of the ResultSet, limited by qty, for subsequent chain ops.\n     */\n    limit(qty: number): this;\n    /**\n     * Used for skipping 'pos' number of documents in the ResultSet.\n     * @param {int} pos - Number of documents to skip; all preceding documents are filtered out.\n     * @returns {ResultSet} Returns a copy of the ResultSet, containing docs starting at 'pos' for subsequent chain ops.\n     */\n    offset(pos: number): this;\n    /**\n     * To support reuse of ResultSet in branched query situations.\n     * @returns {ResultSet} Returns a copy of the ResultSet (set) but the underlying document references will be the same.\n     */\n    copy(): ResultSet<T>;\n    /**\n     * Executes a named collection transform or raw array of transform steps against the ResultSet.\n     * @param {(string|array)} transform - name of collection transform or raw transform array\n     * @param {object} [parameters=] - object property hash of parameters, if the transform requires them.\n     * @returns {ResultSet} either (this) ResultSet or a clone of of this ResultSet (depending on steps)\n     */\n    transform(transform: string | Collection.Transform<T>[], parameters?: object): this;\n    /**\n     * User supplied compare function is provided two documents to compare. (chainable)\n     * @example\n     *    rslt.sort(function(obj1, obj2) {\n       *      if (obj1.name === obj2.name) return 0;\n       *      if (obj1.name > obj2.name) return 1;\n       *      if (obj1.name < obj2.name) return -1;\n       *    });\n     * @param {function} comparefun - A javascript compare function used for sorting.\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    sort(comparefun: (a: Doc<T>, b: Doc<T>) => number): this;\n    /**\n     * Simpler, loose evaluation for user to sort based on a property name. (chainable).\n     * Sorting based on the same lt/gt helper functions used for binary indices.\n     * @param {string} propname - name of property to sort by.\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether to sort descending\n     * @param {string} [options.sortComparator] override default with name of comparator registered in ComparatorMap\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    simplesort(propname: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * rs.compoundsort(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * rs.compoundsort(['age', ['name', true]);\n     * @param {array} properties - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    compoundsort(properties: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Helper function for compoundsort(), performing individual object comparisons\n     * @param {Array} properties - array of property names, in order, by which to evaluate sort order\n     * @param {object} obj1 - first object to compare\n     * @param {object} obj2 - second object to compare\n     * @returns {number} 0, -1, or 1 to designate if identical (sortwise) or which should be first\n     */\n    private _compoundeval(properties, obj1, obj2);\n    /**\n     * Sorts the ResultSet based on the last full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     * @returns {ResultSet}\n     */\n    sortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Oversee the operation of OR'ed query expressions.\n     * OR'ed expression evaluation runs each expression individually against the full collection,\n     * and finally does a set OR on each expression's results.\n     * Each evaluation can utilize a binary index to prevent multiple linear array scans.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findOr(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $or(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Oversee the operation of AND'ed query expressions.\n     * AND'ed expression evaluation runs each expression progressively against the full collection,\n     * internally utilizing existing chained ResultSet functionality.\n     * Only the first filter can utilize a binary index.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findAnd(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $and(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Used for querying via a mongo-style query object.\n     *\n     * @param {object} query - A mongo-style query object used for filtering current results.\n     * @param {boolean} firstOnly - (Optional) Used by collection.findOne() - flag if this was invoked via findOne()\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    find(query?: ResultSet.Query<Doc<T>>, firstOnly?: boolean): this;\n    /**\n     * Used for filtering via a javascript filter function.\n     * @param {function} fun - A javascript function used for filtering current results by.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    where(fun: (obj: Doc<T>) => boolean): this;\n    /**\n     * Returns the number of documents in the ResultSet.\n     * @returns {number} The number of documents in the ResultSet.\n     */\n    count(): number;\n    /**\n     * Terminates the chain and returns array of filtered documents\n     * @param {object} options\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values 'parse-stringify', 'deep', and 'shallow' and\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} Array of documents in the ResultSet\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * Used to run an update operation on all documents currently in the ResultSet.\n     * @param {function} updateFunction - User supplied updateFunction(obj) will be executed for each document object.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    update(updateFunction: (obj: Doc<T>) => Doc<T>): this;\n    /**\n     * Removes all document objects which are currently in ResultSet from collection (as well as ResultSet)\n     * @returns {ResultSet} this (empty) ResultSet for further chain ops.\n     */\n    remove(): this;\n    /**\n     * data transformation via user supplied functions\n     *\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns {value} The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Left joining two sets of data. Join keys can be defined or calculated properties\n     * eqJoin expects the right join key values to be unique.  Otherwise left data will be joined on the last joinData object with that key\n     * @param {Array|ResultSet|Collection} joinData - Data array to join to.\n     * @param {(string|function)} leftJoinKey - Property name in this result set to join on or a function to produce a value to join on\n     * @param {(string|function)} rightJoinKey - Property name in the joinData to join on or a function to produce a value to join on\n     * @param {function} [mapFun=] - a function that receives each matching pair and maps them into output objects - function(left,right){return joinedObject}\n     * @param {object} [dataOptions=] - optional options to apply to data() calls for left and right sides\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} A ResultSet with data in the format [{left: leftObj, right: rightObj}]\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinKey: string | ((obj: any) => string), rightJoinKey: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * Applies a map function into a new collection for further chaining.\n     * @param {function} mapFun - javascript map function\n     * @param {object} [dataOptions=] - options to data() before input to your map function\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - Allows overriding the default or collection specified cloning method\n     * @return {ResultSet}\n     */\n    map<U extends object>(mapFun: (obj: Doc<T>, index: number, array: Doc<T>[]) => U, dataOptions?: ResultSet.DataOptions): ResultSet<U>;\n}\nexport declare namespace ResultSet {\n    interface DataOptions {\n        forceClones?: boolean;\n        forceCloneMethod?: CloneMethod;\n        removeMeta?: boolean;\n    }\n    interface SimpleSortOptions {\n        desc?: boolean;\n        sortComparator?: string;\n    }\n    type ContainsHelperType<R> = R extends string ? string | string[] : R extends any[] ? R[number] | R[number][] : R extends object ? keyof R | (keyof R)[] : never;\n    type LokiOps<R> = {\n        $eq?: R;\n    } | {\n        $ne?: R;\n    } | {\n        $gt?: R;\n    } | {\n        $gte?: R;\n    } | {\n        $lt?: R;\n    } | {\n        $lte?: R;\n    } | {\n        $between?: [R, R];\n    } | {\n        $in?: R[];\n    } | {\n        $nin?: R[];\n    } | {\n        $keyin?: object;\n    } | {\n        $nkeyin?: object;\n    } | {\n        $definedin?: object;\n    } | {\n        $undefinedin?: object;\n    } | {\n        $regex?: RegExp | string | [string, string];\n    } | {\n        $containsNone?: ContainsHelperType<R>;\n    } | {\n        $containsAny?: ContainsHelperType<R>;\n    } | {\n        $contains?: ContainsHelperType<R>;\n    } | {\n        $type?: string;\n    } | {\n        $finite?: boolean;\n    } | {\n        $size?: number;\n    } | {\n        $len?: number;\n    } | {\n        $where?: (val?: R) => boolean;\n    };\n    type Query<T> = {\n        [P in keyof T]?: LokiOps<T[P]> | T[P];\n    } & {\n        $and?: Query<T>[];\n    } & {\n        $or?: Query<T>[];\n    } & {\n        $fts?: FullTextSearchQuery;\n    };\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/loki/src/unique_index.d.ts",
    "content": "export declare class UniqueIndex {\n    private _field;\n    private _lokiMap;\n    private _valMap;\n    /**\n     * Constructs an unique index object.\n     * @param {string} propertyField - the property field to index\n     */\n    constructor(propertyField: string);\n    /**\n     * Sets a document's unique index.\n     * @param {number} id loki id to associate with value\n     * @param {*} value  value to associate with id\n     */\n    set(id: number, value: any): void;\n    /**\n     * Returns the $loki id of an unique value.\n     * @param {*} value the value to retrieve a loki id match for\n     */\n    get(value: any): number;\n    /**\n     * Updates a document's unique index.\n     * @param {number} id (loki) id of document to update the value to\n     * @param {*} value value to associate with loki id\n     */\n    update(id: number, value: any): void;\n    /**\n     * Removes an unique index.\n     * @param {number} id (loki) id to remove from index\n     */\n    remove(id: number): void;\n    /**\n     * Clears the unique index.\n     */\n    clear(): void;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/memory-storage/src/index.d.ts",
    "content": "import { MemoryStorage } from \"./memory_storage\";\nexport { MemoryStorage };\nexport default MemoryStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/memory-storage/src/memory_storage.d.ts",
    "content": "import { Dict, StorageAdapter } from \"../../common/types\";\n/**\n * An in-memory persistence adapter for an in-memory database.\n * This simple 'key/value' adapter is intended for unit testing and diagnostics.\n */\nexport declare class MemoryStorage implements StorageAdapter {\n    hashStore: Dict<{\n        savecount: number;\n        lastsave: Date;\n        value: string;\n    }>;\n    options: MemoryStorage.Options;\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} options - memory storage options\n     * @param {boolean} [options.asyncResponses=false] - whether callbacks are invoked asynchronously (default: false)\n     * @param {int} [options.asyncTimeout=50] - timeout in ms to queue callbacks (default: 50)\n     */\n    constructor(options?: MemoryStorage.Options);\n    /**\n     * Loads a serialized database from its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * Saves a serialized database to its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {string} dbstring - the database content\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a database from its in-memory store.\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport declare namespace MemoryStorage {\n    interface Options {\n        asyncResponses?: boolean;\n        asyncTimeout?: number;\n    }\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/partitioning-adapter/src/index.d.ts",
    "content": "import { PartitioningAdapter } from \"./partitioning_adapter\";\nexport { PartitioningAdapter };\nexport default PartitioningAdapter;\n"
  },
  {
    "path": "dist/packages/full-text-search-language/types/partitioning-adapter/src/partitioning_adapter.d.ts",
    "content": "import { Loki } from \"../../loki/src/loki\";\nimport { StorageAdapter } from \"../../common/types\";\n/**\n * An adapter for adapters. Converts a non reference mode adapter into a reference mode adapter\n * which can perform destructuring and partitioning. Each collection will be stored in its own key/save and\n * only dirty collections will be saved. If you  turn on paging with default page size of 25megs and save\n * a 75 meg collection it should use up roughly 3 save slots (key/value pairs sent to inner adapter).\n * A dirty collection that spans three pages will save all three pages again\n * Paging mode was added mainly because Chrome has issues saving 'too large' of a string within a\n * single IndexedDB row. If a single document update causes the collection to be flagged as dirty, all\n * of that collection's pages will be written on next save.\n */\nexport declare class PartitioningAdapter implements StorageAdapter {\n    mode: string;\n    private _adapter;\n    private _dbref;\n    private _dbname;\n    private _pageIterator;\n    private _paging;\n    private _pageSize;\n    private _delimiter;\n    private _dirtyPartitions;\n    /**\n     * Registers the partitioning adapter as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the partitioning storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} adapter - reference to a 'non-reference' mode loki adapter instance.\n     * @param {boolean} paging - (default: false) set to true to enable paging collection data.\n     * @param {number} pageSize - (default : 25MB) you can use this to limit size of strings passed to inner adapter.\n     * @param {string} delimiter - allows you to override the default delimiter\n     */\n    constructor(adapter: StorageAdapter, {paging, pageSize, delimiter}?: {\n        paging?: boolean;\n        pageSize?: number;\n        delimiter?: string;\n    });\n    /**\n     * Loads a database which was partitioned into several key/value saves.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Used to sequentially load each collection partition, one at a time.\n     *\n     * @param {int} partition - ordinal collection position to load next\n     * @returns {Promise} a Promise that resolves after the next partition is loaded\n     */\n    private _loadNextPartition(partition);\n    /**\n     * Used to sequentially load the next page of collection partition, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next page is loaded\n     */\n    private _loadNextPage();\n    /**\n     * Saves a database by partioning into separate key/value saves.\n     * (Loki 'reference mode' persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {object} dbref - reference to database which we will partition and save.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     *\n     */\n    exportDatabase(dbname: string, dbref: Loki): Promise<void>;\n    /**\n     * Helper method used internally to save each dirty collection, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPartition();\n    /**\n     * Helper method used internally to generate and save the next page of the current (dirty) partition.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPage();\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/lokidb.full-text-search-language-de.js",
    "content": "(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"@lokidb/full-text-search-language\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"@lokidb/full-text-search-language-de\", [\"@lokidb/full-text-search-language\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"@lokidb/full-text-search-language-de\"] = factory(require(\"@lokidb/full-text-search-language\"));\n\telse\n\t\t{ root[\"@lokidb/full-text-search-language-de\"] = factory(root[\"@lokidb/full-text-search-language\"]); root[\"LokiFullTextSearchLanguageDe\"] = root[\"@lokidb/full-text-search-language-de\"].default; }\n})(typeof self !== 'undefined' ? self : this, function(__WEBPACK_EXTERNAL_MODULE__0__) {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// define __esModule on exports\n/******/ \t__webpack_require__.r = function(exports) {\n/******/ \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n/******/ \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n/******/ \t\t}\n/******/ \t\tObject.defineProperty(exports, '__esModule', { value: true });\n/******/ \t};\n/******/\n/******/ \t// create a fake namespace object\n/******/ \t// mode & 1: value is a module id, require it\n/******/ \t// mode & 2: merge all properties of value into the ns\n/******/ \t// mode & 4: return value when already ns object\n/******/ \t// mode & 8|1: behave like require\n/******/ \t__webpack_require__.t = function(value, mode) {\n/******/ \t\tif(mode & 1) value = __webpack_require__(value);\n/******/ \t\tif(mode & 8) return value;\n/******/ \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n/******/ \t\tvar ns = Object.create(null);\n/******/ \t\t__webpack_require__.r(ns);\n/******/ \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n/******/ \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n/******/ \t\treturn ns;\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 1);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, exports) {\n\nmodule.exports = __WEBPACK_EXTERNAL_MODULE__0__;\n\n/***/ }),\n/* 1 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n\n// EXTERNAL MODULE: external \"@lokidb/full-text-search-language\"\nvar full_text_search_language_ = __webpack_require__(0);\n\n// CONCATENATED MODULE: ./packages/full-text-search-language-de/src/german_analyzer.ts\n\nclass german_analyzer_GermanStemmer {\n    constructor() {\n        // Write everything in the constructor to reduce code size and increase performance.\n        // The original implementation uses a ES5 anonymous function class.\n        let a_0 = [new full_text_search_language_[\"Among\"](\"\", -1, 6), new full_text_search_language_[\"Among\"](\"U\", 0, 2),\n            new full_text_search_language_[\"Among\"](\"Y\", 0, 1), new full_text_search_language_[\"Among\"](\"\\u00E4\", 0, 3),\n            new full_text_search_language_[\"Among\"](\"\\u00F6\", 0, 4), new full_text_search_language_[\"Among\"](\"\\u00FC\", 0, 5)\n        ];\n        let a_1 = [\n            new full_text_search_language_[\"Among\"](\"e\", -1, 2), new full_text_search_language_[\"Among\"](\"em\", -1, 1),\n            new full_text_search_language_[\"Among\"](\"en\", -1, 2), new full_text_search_language_[\"Among\"](\"ern\", -1, 1),\n            new full_text_search_language_[\"Among\"](\"er\", -1, 1), new full_text_search_language_[\"Among\"](\"s\", -1, 3),\n            new full_text_search_language_[\"Among\"](\"es\", 5, 2)\n        ];\n        let a_2 = [new full_text_search_language_[\"Among\"](\"en\", -1, 1),\n            new full_text_search_language_[\"Among\"](\"er\", -1, 1), new full_text_search_language_[\"Among\"](\"st\", -1, 2),\n            new full_text_search_language_[\"Among\"](\"est\", 2, 1)\n        ];\n        let a_3 = [new full_text_search_language_[\"Among\"](\"ig\", -1, 1),\n            new full_text_search_language_[\"Among\"](\"lich\", -1, 1)\n        ];\n        let a_4 = [new full_text_search_language_[\"Among\"](\"end\", -1, 1),\n            new full_text_search_language_[\"Among\"](\"ig\", -1, 2), new full_text_search_language_[\"Among\"](\"ung\", -1, 1),\n            new full_text_search_language_[\"Among\"](\"lich\", -1, 3), new full_text_search_language_[\"Among\"](\"isch\", -1, 2),\n            new full_text_search_language_[\"Among\"](\"ik\", -1, 2), new full_text_search_language_[\"Among\"](\"heit\", -1, 3),\n            new full_text_search_language_[\"Among\"](\"keit\", -1, 4)\n        ];\n        let g_v = [17, 65, 16, 1, 0, 0, 0, 0, 0, 0,\n            0, 0, 0, 0, 0, 0, 8, 0, 32, 8\n        ];\n        let g_s_ending = [117, 30, 5];\n        let g_st_ending = [\n            117, 30, 4\n        ];\n        let I_x;\n        let I_p2;\n        let I_p1;\n        let sbp = new full_text_search_language_[\"SnowballProgram\"]();\n        this.setCurrent = (word) => {\n            sbp.setCurrent(word);\n        };\n        this.getCurrent = () => sbp.getCurrent();\n        function habr1(c1, c2, v_1) {\n            if (sbp.eq_s(1, c1)) {\n                sbp.ket = sbp.cursor;\n                if (sbp.in_grouping(g_v, 97, 252)) {\n                    sbp.slice_from(c2);\n                    sbp.cursor = v_1;\n                    return true;\n                }\n            }\n            return false;\n        }\n        function r_prelude() {\n            let v_1 = sbp.cursor;\n            let v_2;\n            let v_3;\n            let v_4;\n            let v_5;\n            while (true) {\n                v_2 = sbp.cursor;\n                sbp.bra = v_2;\n                if (sbp.eq_s(1, \"\\u00DF\")) {\n                    sbp.ket = sbp.cursor;\n                    sbp.slice_from(\"ss\");\n                }\n                else {\n                    if (v_2 >= sbp.limit)\n                        break;\n                    sbp.cursor = v_2 + 1;\n                }\n            }\n            sbp.cursor = v_1;\n            while (true) {\n                v_3 = sbp.cursor;\n                while (true) {\n                    v_4 = sbp.cursor;\n                    if (sbp.in_grouping(g_v, 97, 252)) {\n                        v_5 = sbp.cursor;\n                        sbp.bra = v_5;\n                        if (habr1(\"u\", \"U\", v_4))\n                            break;\n                        sbp.cursor = v_5;\n                        if (habr1(\"y\", \"Y\", v_4))\n                            break;\n                    }\n                    if (v_4 >= sbp.limit) {\n                        sbp.cursor = v_3;\n                        return;\n                    }\n                    sbp.cursor = v_4 + 1;\n                }\n            }\n        }\n        function habr2() {\n            while (!sbp.in_grouping(g_v, 97, 252)) {\n                if (sbp.cursor >= sbp.limit)\n                    return true;\n                sbp.cursor++;\n            }\n            while (!sbp.out_grouping(g_v, 97, 252)) {\n                if (sbp.cursor >= sbp.limit)\n                    return true;\n                sbp.cursor++;\n            }\n            return false;\n        }\n        function r_mark_regions() {\n            I_p1 = sbp.limit;\n            I_p2 = I_p1;\n            let c = sbp.cursor + 3;\n            if (0 <= c && c <= sbp.limit) {\n                I_x = c;\n                if (!habr2()) {\n                    I_p1 = sbp.cursor;\n                    if (I_p1 < I_x)\n                        I_p1 = I_x;\n                    if (!habr2())\n                        I_p2 = sbp.cursor;\n                }\n            }\n        }\n        function r_postlude() {\n            let among_var;\n            let v_1;\n            while (true) {\n                v_1 = sbp.cursor;\n                sbp.bra = v_1;\n                among_var = sbp.find_among(a_0, 6);\n                if (!among_var)\n                    return;\n                sbp.ket = sbp.cursor;\n                switch (among_var) {\n                    case 1:\n                        sbp.slice_from(\"y\");\n                        break;\n                    case 2:\n                    case 5:\n                        sbp.slice_from(\"u\");\n                        break;\n                    case 3:\n                        sbp.slice_from(\"a\");\n                        break;\n                    case 4:\n                        sbp.slice_from(\"o\");\n                        break;\n                    case 6:\n                        if (sbp.cursor >= sbp.limit)\n                            return;\n                        sbp.cursor++;\n                        break;\n                }\n            }\n        }\n        function r_R1() {\n            return I_p1 <= sbp.cursor;\n        }\n        function r_R2() {\n            return I_p2 <= sbp.cursor;\n        }\n        function r_standard_suffix() {\n            let among_var;\n            let v_1 = sbp.limit - sbp.cursor;\n            let v_2;\n            let v_3;\n            let v_4;\n            sbp.ket = sbp.cursor;\n            among_var = sbp.find_among_b(a_1, 7);\n            if (among_var) {\n                sbp.bra = sbp.cursor;\n                if (r_R1()) {\n                    switch (among_var) {\n                        case 1:\n                            sbp.slice_del();\n                            break;\n                        case 2:\n                            sbp.slice_del();\n                            sbp.ket = sbp.cursor;\n                            if (sbp.eq_s_b(1, \"s\")) {\n                                sbp.bra = sbp.cursor;\n                                if (sbp.eq_s_b(3, \"nis\"))\n                                    sbp.slice_del();\n                            }\n                            break;\n                        case 3:\n                            if (sbp.in_grouping_b(g_s_ending, 98, 116))\n                                sbp.slice_del();\n                            break;\n                    }\n                }\n            }\n            sbp.cursor = sbp.limit - v_1;\n            sbp.ket = sbp.cursor;\n            among_var = sbp.find_among_b(a_2, 4);\n            if (among_var) {\n                sbp.bra = sbp.cursor;\n                if (r_R1()) {\n                    switch (among_var) {\n                        case 1:\n                            sbp.slice_del();\n                            break;\n                        case 2:\n                            if (sbp.in_grouping_b(g_st_ending, 98, 116)) {\n                                let c = sbp.cursor - 3;\n                                if (sbp.limit_backward <= c && c <= sbp.limit) {\n                                    sbp.cursor = c;\n                                    sbp.slice_del();\n                                }\n                            }\n                            break;\n                    }\n                }\n            }\n            sbp.cursor = sbp.limit - v_1;\n            sbp.ket = sbp.cursor;\n            among_var = sbp.find_among_b(a_4, 8);\n            if (among_var) {\n                sbp.bra = sbp.cursor;\n                if (r_R2()) {\n                    switch (among_var) {\n                        case 1:\n                            sbp.slice_del();\n                            sbp.ket = sbp.cursor;\n                            if (sbp.eq_s_b(2, \"ig\")) {\n                                sbp.bra = sbp.cursor;\n                                v_2 = sbp.limit - sbp.cursor;\n                                if (!sbp.eq_s_b(1, \"e\")) {\n                                    sbp.cursor = sbp.limit - v_2;\n                                    if (r_R2())\n                                        sbp.slice_del();\n                                }\n                            }\n                            break;\n                        case 2:\n                            v_3 = sbp.limit - sbp.cursor;\n                            if (!sbp.eq_s_b(1, \"e\")) {\n                                sbp.cursor = sbp.limit - v_3;\n                                sbp.slice_del();\n                            }\n                            break;\n                        case 3:\n                            sbp.slice_del();\n                            sbp.ket = sbp.cursor;\n                            v_4 = sbp.limit - sbp.cursor;\n                            if (!sbp.eq_s_b(2, \"er\")) {\n                                sbp.cursor = sbp.limit - v_4;\n                                if (!sbp.eq_s_b(2, \"en\"))\n                                    break;\n                            }\n                            sbp.bra = sbp.cursor;\n                            if (r_R1())\n                                sbp.slice_del();\n                            break;\n                        case 4:\n                            sbp.slice_del();\n                            sbp.ket = sbp.cursor;\n                            among_var = sbp.find_among_b(a_3, 2);\n                            if (among_var) {\n                                sbp.bra = sbp.cursor;\n                                if (r_R2() && among_var === 1)\n                                    sbp.slice_del();\n                            }\n                            break;\n                    }\n                }\n            }\n        }\n        this.stem = () => {\n            let v_1 = sbp.cursor;\n            r_prelude();\n            sbp.cursor = v_1;\n            r_mark_regions();\n            sbp.limit_backward = v_1;\n            sbp.cursor = sbp.limit;\n            r_standard_suffix();\n            sbp.cursor = sbp.limit_backward;\n            r_postlude();\n        };\n    }\n}\n// Split at whitespace and dashes.\nfunction splitter(str) {\n    let trimmedTokens = [];\n    let tokens = str.split(/[\\s-]+/);\n    for (let i = 0; i < tokens.length; i++) {\n        if (tokens[i] !== \"\") {\n            trimmedTokens.push(tokens[i].toLowerCase());\n        }\n    }\n    return trimmedTokens;\n}\nconst st = new german_analyzer_GermanStemmer();\nfunction stemmer(token) {\n    st.setCurrent(token);\n    st.stem();\n    return st.getCurrent();\n}\nconst trimmer = Object(full_text_search_language_[\"generateTrimmer\"])(\"A-Za-z\\xAA\\xBA\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\u02B8\\u02E0-\\u02E4\\u1D00-\\u1D25\\u1D2C-\\u1D5C\\u1D62-\\u1D65\\u1D6B-\\u1D77\\u1D79-\\u1DBE\\u1E00-\\u1EFF\\u2071\\u207F\\u2090-\\u209C\\u212A\\u212B\\u2132\\u214E\\u2160-\\u2188\\u2C60-\\u2C7F\\uA722-\\uA787\\uA78B-\\uA7AD\\uA7B0-\\uA7B7\\uA7F7-\\uA7FF\\uAB30-\\uAB5A\\uAB5C-\\uAB64\\uFB00-\\uFB06\\uFF21-\\uFF3A\\uFF41-\\uFF5A\");\nconst stopWordFilter = Object(full_text_search_language_[\"generateStopWordFilter\"])([\"aber\", \"alle\", \"allem\", \"allen\", \"aller\", \"alles\", \"als\", \"also\", \"am\", \"an\", \"ander\", \"andere\", \"anderem\", \"anderen\", \"anderer\", \"anderes\", \"anderm\", \"andern\", \"anderr\", \"anders\", \"auch\", \"auf\", \"aus\", \"bei\", \"bin\", \"bis\", \"bist\", \"da\", \"damit\", \"dann\", \"das\", \"dasselbe\", \"dazu\", \"daß\", \"dein\", \"deine\", \"deinem\", \"deinen\", \"deiner\", \"deines\", \"dem\", \"demselben\", \"den\", \"denn\", \"denselben\", \"der\", \"derer\", \"derselbe\", \"derselben\", \"des\", \"desselben\", \"dessen\", \"dich\", \"die\", \"dies\", \"diese\", \"dieselbe\", \"dieselben\", \"diesem\", \"diesen\", \"dieser\", \"dieses\", \"dir\", \"doch\", \"dort\", \"du\", \"durch\", \"ein\", \"eine\", \"einem\", \"einen\", \"einer\", \"eines\", \"einig\", \"einige\", \"einigem\", \"einigen\", \"einiger\", \"einiges\", \"einmal\", \"er\", \"es\", \"etwas\", \"euch\", \"euer\", \"eure\", \"eurem\", \"euren\", \"eurer\", \"eures\", \"für\", \"gegen\", \"gewesen\", \"hab\", \"habe\", \"haben\", \"hat\", \"hatte\", \"hatten\", \"hier\", \"hin\", \"hinter\", \"ich\", \"ihm\", \"ihn\", \"ihnen\", \"ihr\", \"ihre\", \"ihrem\", \"ihren\", \"ihrer\", \"ihres\", \"im\", \"in\", \"indem\", \"ins\", \"ist\", \"jede\", \"jedem\", \"jeden\", \"jeder\", \"jedes\", \"jene\", \"jenem\", \"jenen\", \"jener\", \"jenes\", \"jetzt\", \"kann\", \"kein\", \"keine\", \"keinem\", \"keinen\", \"keiner\", \"keines\", \"können\", \"könnte\", \"machen\", \"man\", \"manche\", \"manchem\", \"manchen\", \"mancher\", \"manches\", \"mein\", \"meine\", \"meinem\", \"meinen\", \"meiner\", \"meines\", \"mich\", \"mir\", \"mit\", \"muss\", \"musste\", \"nach\", \"nicht\", \"nichts\", \"noch\", \"nun\", \"nur\", \"ob\", \"oder\", \"ohne\", \"sehr\", \"sein\", \"seine\", \"seinem\", \"seinen\", \"seiner\", \"seines\", \"selbst\", \"sich\", \"sie\", \"sind\", \"so\", \"solche\", \"solchem\", \"solchen\", \"solcher\", \"solches\", \"soll\", \"sollte\", \"sondern\", \"sonst\", \"um\", \"und\", \"uns\", \"unse\", \"unsem\", \"unsen\", \"unser\", \"unses\", \"unter\", \"viel\", \"vom\", \"von\", \"vor\", \"war\", \"waren\", \"warst\", \"was\", \"weg\", \"weil\", \"weiter\", \"welche\", \"welchem\", \"welchen\", \"welcher\", \"welches\", \"wenn\", \"werde\", \"werden\", \"wie\", \"wieder\", \"will\", \"wir\", \"wird\", \"wirst\", \"wo\", \"wollen\", \"wollte\", \"während\", \"würde\", \"würden\", \"zu\", \"zum\", \"zur\", \"zwar\", \"zwischen\", \"über\"]);\n// Export the analyzer.\nclass GermanAnalyzer {\n    constructor() {\n        this.tokenizer = splitter;\n        this.token_filter = [trimmer, stemmer, stopWordFilter];\n    }\n}\n\n// CONCATENATED MODULE: ./packages/full-text-search-language-de/src/index.ts\n/* concated harmony reexport */__webpack_require__.d(__webpack_exports__, \"GermanAnalyzer\", function() { return GermanAnalyzer; });\n\n\n/* harmony default export */ var src = __webpack_exports__[\"default\"] = (GermanAnalyzer);\n\n\n/***/ })\n/******/ ]);\n});\n//# sourceMappingURL=lokidb.full-text-search-language-de.js.map"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/common/plugin.d.ts",
    "content": "/**\n * @hidden\n */\nexport declare const PLUGINS: void;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/common/types.d.ts",
    "content": "/**\n * @hidden\n */\nimport { Loki } from \"../loki/src/loki\";\nexport interface StorageAdapter {\n    loadDatabase(dbname: string): Promise<any>;\n    saveDatabase?(dbname: string, serialization: string): Promise<void>;\n    deleteDatabase?(dbname: string): Promise<void>;\n    mode?: string;\n    exportDatabase?(dbname: string, dbref: Loki): Promise<void>;\n}\nexport declare type Doc<T extends object = object> = T & {\n    $loki: number;\n    meta?: {\n        created: number;\n        revision: number;\n        version: number;\n        updated?: number;\n    };\n};\nexport interface Dict<T> {\n    [index: string]: T;\n    [index: number]: T;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/fs-storage/src/fs_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists using node fs module.\n */\nexport declare class FSStorage implements StorageAdapter {\n    /**\n     * Registers the fs storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the fs storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * Load data from file, will throw an error if the file does not exist\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Save data to file, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Delete the database file, will throw an error if the\n     * file can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/fs-storage/src/index.d.ts",
    "content": "import { FSStorage } from \"./fs_storage\";\nexport { FSStorage };\nexport default FSStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search/src/analyzer/analyzer.d.ts",
    "content": "import { CharacterFilter } from \"./character_filter\";\nimport { Tokenizer, whitespaceTokenizer } from \"./tokenizer\";\nimport { lowercaseTokenFilter, TokenFilter } from \"./token_filter\";\n/**\n * A analyzer converts a string into tokens which are added to the inverted index for searching.\n */\nexport interface Analyzer {\n    /**\n     * The character filters of the analyzer.\n     */\n    char_filter?: CharacterFilter[];\n    /**\n     * The tokenizer of the analyzer.\n     */\n    tokenizer: Tokenizer;\n    /**\n     * The token filters of the analyzer.\n     */\n    token_filter?: TokenFilter[];\n}\n/**\n * Analyzes a given string.\n * @param {Analyzer} analyzer - the analyzer\n * @param {string} str - the string\n * @returns {string[]} - the tokens\n */\nexport declare function analyze(analyzer: Analyzer, str: string): string[];\n/**\n * An analyzer with the whitespace tokenizer and the lowercase token filter.\n */\nexport declare class StandardAnalyzer implements Analyzer {\n    tokenizer: typeof whitespaceTokenizer;\n    token_filter: (typeof lowercaseTokenFilter)[];\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search/src/analyzer/character_filter.d.ts",
    "content": "/**\n * A character filter is used to preprocess a string before it is passed to a tokenizer.\n */\nexport declare type CharacterFilter = (value: string) => string;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search/src/analyzer/token_filter.d.ts",
    "content": "/**\n * A token filter takes tokens from a tokenizer and modify, delete or add tokens.\n */\nexport declare type TokenFilter = (value: string, index: number, array: string[]) => string;\n/**\n * Converts a token to lowercase.\n * @param {string} token - the token\n * @returns {string} - the lowercased token\n */\nexport declare function lowercaseTokenFilter(token: string): string;\n/**\n * Converts a token to uppercase.\n * @param {string} token - the token\n * @returns {string} - the uppercased token\n */\nexport declare function uppercaseTokenFilter(token: string): string;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search/src/analyzer/tokenizer.d.ts",
    "content": "/**\n * A tokenizer splits a string into individual tokens.\n */\nexport declare type Tokenizer = (value: string) => string[];\n/**\n * Splits a string at whitespace characters into tokens.\n * @param {string} value - the string\n * @returns {string[]} - the tokens\n */\nexport declare function whitespaceTokenizer(value: string): string[];\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search/src/full_text_search.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\nimport { Scorer } from \"./scorer\";\nimport { Analyzer } from \"./analyzer/analyzer\";\nexport declare class FullTextSearch {\n    private _id;\n    private _docs;\n    private _idxSearcher;\n    private _invIdxs;\n    /**\n     * Registers the full-text search as plugin.\n     */\n    static register(): void;\n    /**\n     * Initialize the full-text search for the given fields.\n     * @param {object[]} fieldOptions - the field options\n     * @param {string} fieldOptions.field - the name of the property field\n     * @param {boolean=true} fieldOptions.store - flag to indicate if the full-text search should be stored on serialization or\n     *  rebuild on deserialization\n     * @param {boolean=true} fieldOptions.optimizeChanges - flag to optimize updating and deleting of documents\n     *    (requires more memory but performs faster)\n     * @param {Analyzer} fieldOptions.analyzer - an analyzer for the field\n     * @param {string} [id] - the property name of the document index\n     */\n    constructor(fieldOptions?: FullTextSearch.FieldOptions[], id?: string);\n    addDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    removeDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    updateDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    clear(): void;\n    search(query: Query): Scorer.ScoreResults;\n    toJSON(): FullTextSearch.Serialization;\n    static fromJSONObject(serialized: FullTextSearch.Serialization, analyzers?: Dict<Analyzer>): FullTextSearch;\n}\nexport declare namespace FullTextSearch {\n    interface FieldOptions extends InvertedIndex.FieldOptions {\n        field: string;\n    }\n    interface Serialization {\n        id: string;\n        ii: Dict<InvertedIndex.Serialization>;\n    }\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search/src/fuzzy/automaton.d.ts",
    "content": "/**\n * Transition with dest, min and max.\n * @hidden\n */\nexport declare type Transition = [number, number, number];\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MIN_CODE_POINT = 0;\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MAX_CODE_POINT = 1114111;\n/**\n * From org/apache/lucene/util/automaton/Automaton.java\n * @hidden\n */\nexport declare class Automaton {\n    private _stateTransitions;\n    private _accept;\n    private _nextState;\n    private _currState;\n    private _transitions;\n    constructor();\n    isAccept(n: number): boolean;\n    createState(): number;\n    setAccept(state: number, accept: boolean): void;\n    finishState(): void;\n    private _finishCurrentState();\n    getStartPoints(): number[];\n    step(state: number, label: number): number;\n    getNumStates(): number;\n    addTransition(source: number, dest: number, min: number, max: number): void;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search/src/fuzzy/lev1t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev1TParametricDescription.java\n * @hidden\n */\nexport declare class Lev1TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search/src/fuzzy/lev2t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev2TParametricDescription.java\n * @hidden\n */\nexport declare class Lev2TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search/src/fuzzy/levenshtein_automata.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java\n * @hidden\n */\nexport declare class LevenshteinAutomata {\n    private _word;\n    private _numRanges;\n    private _rangeLower;\n    private _rangeUpper;\n    private _description;\n    private _alphabet;\n    private _editDistance;\n    constructor(input: number[], editDistance: number);\n    /**\n     * Transforms the NDFA to a DFA.\n     * @returns {Automaton}\n     */\n    toAutomaton(): Automaton;\n    private _getVector(x, pos, end);\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search/src/fuzzy/long.d.ts",
    "content": "/**\n * Class supports 64Bit integer operations.\n * A cut-down version of dcodeIO/long.js.\n * @hidden\n */\nexport declare class Long {\n    private _low;\n    private _high;\n    constructor(low?: number, high?: number);\n    /**\n     * Returns this long with bits arithmetically shifted to the right by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftRight(numBits: number): Long;\n    /**\n     * Returns this long with bits arithmetically shifted to the left by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftLeft(numBits: number): Long;\n    /**\n     * Returns the bitwise AND of this Long and the specified.\n     * @param {Long} other - the other Long\n     * @returns {Long} the long\n     */\n    and(other: Long): Long;\n    /**\n     * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.\n     * @returns {number}\n     */\n    toInt(): number;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search/src/fuzzy/parametric_description.d.ts",
    "content": "import { Long } from \"./long\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java#ParametricDescription\n * @hidden\n */\nexport declare class ParametricDescription {\n    protected _w: number;\n    private _n;\n    private _minErrors;\n    constructor(w: number, n: number, minErrors: number[]);\n    /**\n     * Return the number of states needed to compute a Levenshtein DFA\n     */\n    size(): number;\n    /**\n     * Returns true if the <code>state</code> in any Levenshtein DFA is an accept state (final state).\n     */\n    isAccept(absState: number): boolean;\n    /**\n     * Returns the position in the input word for a given <code>state</code>.\n     * This is the minimal boundary for the state.\n     */\n    getPosition(absState: number): number;\n    static unpack(data: Long[], index: number, bitsPerValue: number): number;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search/src/fuzzy/run_automaton.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/RunAutomaton.java\n * @hidden\n */\nexport declare class RunAutomaton {\n    private _points;\n    private _accept;\n    private _transitions;\n    private _classmap;\n    constructor(automaton: Automaton);\n    getCharClass(c: number): number;\n    step(state: number, c: number): number;\n    isAccept(state: number): boolean;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search/src/index.d.ts",
    "content": "import { FullTextSearch } from \"./full_text_search\";\nimport { analyze, StandardAnalyzer } from \"./analyzer/analyzer\";\nimport { whitespaceTokenizer } from \"./analyzer/tokenizer\";\nimport { lowercaseTokenFilter, uppercaseTokenFilter } from \"./analyzer/token_filter\";\nexport { FullTextSearch, analyze, StandardAnalyzer, whitespaceTokenizer, lowercaseTokenFilter, uppercaseTokenFilter };\nexport default FullTextSearch;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search/src/index_searcher.d.ts",
    "content": "import { Scorer } from \"./scorer\";\nimport { InvertedIndex } from \"./inverted_index\";\nimport { Query } from \"./query_types\";\nimport { Dict } from \"../../common/types\";\n/**\n * @hidden\n */\nexport declare class IndexSearcher {\n    private _invIdxs;\n    private _docs;\n    private _scorer;\n    /**\n     * Constructs an index searcher.\n     * @param {Dict<InvertedIndex>} invIdxs - the inverted indexes\n     * @param {Set<number>} docs - the ids of the documents\n     */\n    constructor(invIdxs: Dict<InvertedIndex>, docs: Set<InvertedIndex.DocumentIndex>);\n    search(query: Query): Scorer.ScoreResults;\n    setDirty(): void;\n    private _recursive(query, doScoring);\n    private _getUnique(queries, doScoring, queryResults);\n    private _getAll(queries, doScoring, queryResults?);\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search/src/inverted_index.d.ts",
    "content": "import { Analyzer } from \"./analyzer/analyzer\";\n/**\n * Converts a string into an array of code points.\n * @param str - the string\n * @returns {number[]} to code points\n * @hidden\n */\nexport declare function toCodePoints(str: string): number[];\n/**\n * Inverted index class handles featured text search for specific document fields.\n * @hidden\n */\nexport declare class InvertedIndex {\n    analyzer: Analyzer;\n    docCount: number;\n    docStore: Map<InvertedIndex.DocumentIndex, InvertedIndex.DocStore>;\n    totalFieldLength: number;\n    root: InvertedIndex.Index;\n    private _store;\n    private _optimizeChanges;\n    /**\n     * @param {boolean} [options.store=true] - inverted index will be stored at serialization rather than rebuilt on load\n     * @param {boolean} [options.optimizeChanges=true] - flag to store additional metadata inside the index for better\n     *  performance if an existing field is updated or removed\n     * @param {Analyzer} [options.analyzer=] - the analyzer of this inverted index\n     */\n    constructor(options?: InvertedIndex.FieldOptions);\n    /**\n     * Adds defined fields of a document to the inverted index.\n     * @param {string} field - the field to add\n     * @param {number} docId - the doc id of the field\n     */\n    insert(field: string, docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Removes all relevant terms of a document from the inverted index.\n     * @param {number} docId - the document.\n     */\n    remove(docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Gets the term index of a term.\n     * @param {string} term - the term\n     * @param {object} root - the term index to start from\n     * @param {number} start - the position of the term string to start from\n     * @return {object} - The term index or null if the term is not in the term tree.\n     */\n    static getTermIndex(term: number[], root: InvertedIndex.Index, start?: number): InvertedIndex.Index;\n    /**\n     * Extends a term index to all available term leafs.\n     * @param {object} idx - the term index to start from\n     * @param {number[]} [term=[]] - the current term\n     * @param {Array} termIndices - all extended indices with their term\n     * @returns {Array} - Array with term indices and extension\n     */\n    static extendTermIndex(idx: InvertedIndex.Index, term?: number[], termIndices?: InvertedIndex.IndexTerm[]): InvertedIndex.IndexTerm[];\n    /**\n     * Serialize the inverted index.\n     * @returns {{docStore: *, _fields: *, index: *}}\n     */\n    toJSON(): InvertedIndex.Serialization;\n    /**\n     * Deserialize the inverted index.\n     * @param {{docStore: *, _fields: *, index: *}} serialized - The serialized inverted index.\n     * @param {Analyzer} analyzer[undefined] - an analyzer\n     */\n    static fromJSONObject(serialized: InvertedIndex.Serialization, analyzer?: Analyzer): InvertedIndex;\n    private static _serializeIndex(idx);\n    private static _deserializeIndex(serialized);\n    /**\n     * Set parent of to each index and regenerate the indexRef.\n     * @param {Index} index - the index\n     * @param {Index} parent - the parent\n     */\n    private _regenerate(index, parent);\n    /**\n     * Iterate over the whole inverted index and remove the document.\n     * Delete branch if not needed anymore.\n     * Function is needed if index is used without optimization.\n     * @param {Index} idx - the index\n     * @param {number} docId - the doc id\n     * @returns {boolean} true if index is empty\n     */\n    private _remove(idx, docId);\n}\nexport declare namespace InvertedIndex {\n    interface FieldOptions {\n        store?: boolean;\n        optimizeChanges?: boolean;\n        analyzer?: Analyzer;\n    }\n    type Index = Map<number, any> & {\n        dc?: Map<DocumentIndex, number>;\n        df?: number;\n        pa?: Index;\n    };\n    type IndexTerm = {\n        index: Index;\n        term: number[];\n    };\n    interface SerializedIndex {\n        d?: {\n            df: number;\n            dc: [DocumentIndex, number][];\n        };\n        k?: number[];\n        v?: SerializedIndex[];\n    }\n    type Serialization = SpareSerialization | FullSerialization;\n    type SpareSerialization = {\n        _store: false;\n        _optimizeChanges: boolean;\n    };\n    type FullSerialization = {\n        _store: true;\n        _optimizeChanges: boolean;\n        docCount: number;\n        docStore: [DocumentIndex, DocStore][];\n        totalFieldLength: number;\n        root: SerializedIndex;\n    };\n    interface DocStore {\n        fieldLength?: number;\n        indexRef?: Index[];\n    }\n    type DocumentIndex = number | string;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search/src/query_types.d.ts",
    "content": "/**\n * Base query to enable boost to a query type.\n */\nexport interface BaseQuery<Type> {\n    type: Type;\n    boost?: number;\n}\n/**\n * A query which finds documents where a document field contains a term.\n */\nexport interface TermQuery extends BaseQuery<\"term\"> {\n    field: string;\n    value: string;\n}\n/**\n * A query which finds documents where a document field contains any of the terms.\n */\nexport interface TermsQuery extends BaseQuery<\"terms\"> {\n    field: string;\n    value: string[];\n}\n/**\n * A query which finds documents where the wildcard term can be applied at an existing document field term.\n */\nexport interface WildcardQuery extends BaseQuery<\"wildcard\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which finds documents where the fuzzy term can be transformed into an existing document field term within a\n * given edit distance.\n */\nexport interface FuzzyQuery extends BaseQuery<\"fuzzy\"> {\n    field: string;\n    value: string;\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query which matches documents containing the prefix of a term inside a field.\n */\nexport interface PrefixQuery extends BaseQuery<\"prefix\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which matches all documents with a given field.\n */\nexport interface ExistsQuery extends BaseQuery<\"exists\"> {\n    field: string;\n}\n/**\n * A query which tokenizes the given text into tokens and performs a sub query for each token. The results are combined\n * using a boolean operator.\n */\nexport interface MatchQuery extends BaseQuery<\"match\"> {\n    field: string;\n    value: string;\n    minimum_should_match?: number | string;\n    operator?: \"and\" | \"or\";\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query that matches all documents and giving them a constant score equal to the query boost.\n*/\nexport interface MatchQueryAll extends BaseQuery<\"match_all\"> {\n}\n/**\n * A query that wraps sub queries and returns a constant score equal to the query boost for every document in the filter.\n */\nexport interface ConstantScoreQuery extends BaseQuery<\"constant_score\"> {\n    filter: QueryTypes[];\n}\n/**\n * A query that matches documents matching boolean combinations of sub queries.\n */\nexport interface BoolQuery extends BaseQuery<\"bool\"> {\n    must?: QueryTypes[];\n    filter?: QueryTypes[];\n    should?: QueryTypes[];\n    not?: QueryTypes[];\n    minimum_should_match?: number | string;\n}\n/**\n * Union type of possible query types.\n */\nexport declare type QueryTypes = BoolQuery | ConstantScoreQuery | TermQuery | TermsQuery | WildcardQuery | FuzzyQuery | MatchQuery | MatchQueryAll | PrefixQuery | ExistsQuery;\n/**\n * The main query with the actually full-text search query and the scoring parameters.\n */\nexport interface Query {\n    query: QueryTypes;\n    calculate_scoring?: boolean;\n    explain?: boolean;\n    bm25?: {\n        k1: number;\n        b: number;\n    };\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search/src/scorer.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\n/**\n * @hidden\n */\nexport declare class Scorer {\n    private _invIdxs;\n    private _cache;\n    constructor(invIdxs: Dict<InvertedIndex>);\n    setDirty(): void;\n    score(fieldName: string, boost: number, termIdx: InvertedIndex.Index, doScoring: boolean | null, queryResults: Scorer.QueryResults, term: number[], df?: number): void;\n    scoreConstant(boost: number, docId: InvertedIndex.DocumentIndex, queryResults: Scorer.QueryResults): Scorer.QueryResults;\n    finalScore(query: Query, queryResults: Scorer.QueryResults): Scorer.ScoreResults;\n    private static _calculateFieldLength(fieldLength);\n    private _getCache(fieldName);\n    /**\n     * Returns the idf by either calculate it or use a cached one.\n     * @param {string} fieldName - the name of the field\n     * @param {number} docFreq - the doc frequency of the term\n     * @returns {number} the idf\n     * @private\n     */\n    private _idf(fieldName, docFreq);\n    private _avgFieldLength(fieldName);\n}\nexport declare namespace Scorer {\n    interface IDFCache {\n        idfs: Dict<number>;\n        avgFieldLength: number;\n    }\n    interface QueryResult {\n        tf?: number;\n        idf?: number;\n        boost: number;\n        fieldName?: string;\n        term?: number[];\n    }\n    type QueryResults = Map<InvertedIndex.DocumentIndex, QueryResult[]>;\n    interface BM25Explanation {\n        boost: number;\n        score: number;\n        docID: number;\n        fieldName: string;\n        index: string;\n        idf: number;\n        tfNorm: number;\n        tf: number;\n        fieldLength: number;\n        avgFieldLength: number;\n    }\n    interface ConstantExplanation {\n        boost: number;\n        score: number;\n    }\n    type ScoreExplanation = BM25Explanation | ConstantExplanation;\n    type ScoreResult = {\n        score: number;\n        explanation?: ScoreExplanation[];\n    };\n    type ScoreResults = Dict<ScoreResult>;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search-language/src/index.d.ts",
    "content": "export { generateStopWordFilter, generateTrimmer, Among, SnowballProgram } from \"./language\";\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search-language/src/language.d.ts",
    "content": "export declare function generateTrimmer(wordCharacters: string): (token: string) => string;\nexport declare function generateStopWordFilter(stopWords: string[]): (token: string) => string;\nexport declare class Among {\n    s_size: number;\n    s: number[];\n    substring_i: number;\n    result: number;\n    method: any;\n    constructor(s: string, substring_i: number, result: number, method?: any);\n}\nexport declare class SnowballProgram {\n    current: string;\n    bra: number;\n    ket: number;\n    limit: number;\n    cursor: number;\n    limit_backward: number;\n    constructor();\n    setCurrent(word: string): void;\n    getCurrent(): string;\n    in_grouping(s: number[], min: number, max: number): boolean;\n    in_grouping_b(s: number[], min: number, max: number): boolean;\n    out_grouping(s: number[], min: number, max: number): boolean;\n    out_grouping_b(s: number[], min: number, max: number): boolean;\n    eq_s(s_size: number, s: string): boolean;\n    eq_s_b(s_size: number, s: string): boolean;\n    find_among(v: Among[], v_size: number): number;\n    find_among_b(v: Among[], v_size: number): number;\n    replace_s(c_bra: number, c_ket: number, s: string): number;\n    slice_check(): void;\n    slice_from(s: string): void;\n    slice_del(): void;\n    insert(c_bra: number, c_ket: number, s: string): void;\n    slice_to(): string;\n    eq_v_b(s: string): boolean;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search-language-de/src/german_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class GermanAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search-language-de/src/index.d.ts",
    "content": "import { GermanAnalyzer } from \"./german_analyzer\";\nexport { GermanAnalyzer };\nexport default GermanAnalyzer;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search-language-en/src/english_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class EnglishAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/full-text-search-language-en/src/index.d.ts",
    "content": "import { EnglishAnalyzer } from \"./english_analyzer\";\nexport { EnglishAnalyzer };\nexport default EnglishAnalyzer;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/indexed-storage/src/index.d.ts",
    "content": "import { IndexedStorage } from \"./indexed_storage\";\nexport { IndexedStorage };\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/indexed-storage/src/indexed_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * Loki persistence adapter class for indexedDb.\n *     This class fulfills abstract adapter interface which can be applied to other storage methods.\n *     Utilizes the included LokiCatalog app/key/value database for actual database persistence.\n *     IndexedDb storage is provided per-domain, so we implement app/key/value database to\n *     allow separate contexts for separate apps within a domain.\n */\nexport declare class IndexedStorage implements StorageAdapter {\n    private _appname;\n    private catalog;\n    /**\n     * Registers the indexed storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the indexed storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {string} [appname=loki] - Application name context can be used to distinguish subdomains, \"loki\" by default\n     */\n    constructor(appname?: string);\n    /**\n     * Retrieves a serialized db string from the catalog.\n     *\n     * @example\n     * // LOAD\n     * var idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * var db = new loki(\"test\", { adapter: idbAdapter });\n     *   db.base(function(result) {\n       *   console.log(\"done\");\n       * });\n     *\n     * @param {string} dbname - the name of the database to retrieve.\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<{}>;\n    /**\n     * Saves a serialized db to the catalog.\n     *\n     * @example\n     * // SAVE : will save App/Key/Val as \"finance\"/\"test\"/{serializedDb}\n     * let idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * let db = new loki(\"test\", { adapter: idbAdapter });\n     * let coll = db.addCollection(\"testColl\");\n     * coll.insert({test: \"val\"});\n     * db.saveDatabase();  // could pass callback if needed for async complete\n     *\n     * @param {string} dbname - the name to give the serialized database within the catalog.\n     * @param {string} dbstring - the serialized db string to save.\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a serialized db from the catalog.\n     *\n     * @example\n     * // DELETE DATABASE\n     * // delete \"finance\"/\"test\" value from catalog\n     * idbAdapter.deleteDatabase(\"test\", function {\n       *   // database deleted\n       * });\n     *\n     * @param {string} dbname - the name of the database to delete from the catalog.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n    /**\n     * Removes all database partitions and pages with the base filename passed in.\n     * This utility method does not (yet) guarantee async deletions will be completed before returning\n     *\n     * @param {string} dbname - the base filename which container, partitions, or pages are derived\n     */\n    deleteDatabasePartitions(dbname: string): void;\n    /**\n     * Retrieves object array of catalog entries for current app.\n     *\n     * @example\n     * idbAdapter.getDatabaseList(function(result) {\n       *   // result is array of string names for that appcontext (\"finance\")\n       *   result.forEach(function(str) {\n       *     console.log(str);\n       *   });\n       * });\n     *\n     * @param {function} callback - should accept array of database names in the catalog for current app.\n     */\n    getDatabaseList(callback: (names: string[]) => void): void;\n    /**\n     * Allows retrieval of list of all keys in catalog along with size\n     * @param {function} callback - (Optional) callback to accept result array.\n     */\n    getCatalogSummary(callback: (entry: Entry[]) => void): void;\n}\nexport interface Entry {\n    app: string;\n    key: string;\n    size: number;\n}\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/local-storage/src/index.d.ts",
    "content": "import { LocalStorage } from \"./local_storage\";\nexport { LocalStorage };\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/local-storage/src/local_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists to web browser's local storage object\n * @constructor LocalStorageAdapter\n */\nexport declare class LocalStorage implements StorageAdapter {\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * loadDatabase() - Load data from localstorage\n     * @param {string} dbname - the name of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * saveDatabase() - save data to localstorage, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was saved\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * deleteDatabase() - delete the database from localstorage, will throw an error if it\n     * can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/loki/src/avl_index.d.ts",
    "content": "import { IRangedIndex, IRangedIndexRequest } from \"./ranged_indexes\";\nimport { ILokiComparer } from \"./comparators\";\n/**\n * Treenode type for binary search tree (BST) implementation.\n *\n * To support duplicates, we may need to either repurpose parent to\n * point to 'elder' sibling or add a siblingId to point to owner of\n * node represented in tree.\n */\nexport declare type TreeNode<T> = {\n    id: number;\n    value: T;\n    parent: number | null;\n    balance: number;\n    height: number;\n    left: number | null;\n    right: number | null;\n    siblings: number[];\n};\nexport interface ITreeNodeHash<T> {\n    [id: number]: TreeNode<T>;\n}\n/**\n * LokiDB AVL Balanced Binary Tree Index implementation.\n * To support duplicates, we use siblings (array) in tree nodes.\n * Basic AVL components guided by William Fiset tutorials at :\n * https://github.com/williamfiset/data-structures/blob/master/com/williamfiset/datastructures/balancedtree/AVLTreeRecursive.java\n * https://www.youtube.com/watch?v=g4y2h70D6Nk&list=PLDV1Zeh2NRsD06x59fxczdWLhDDszUHKt\n */\nexport declare class AvlTreeIndex<T> implements IRangedIndex<T> {\n    name: string;\n    comparator: ILokiComparer<T>;\n    nodes: ITreeNodeHash<T>;\n    apex: number | null;\n    /**\n     * Initializes index with property name and a comparer function.\n     */\n    constructor(name: string, comparator: ILokiComparer<T>);\n    backup(): AvlTreeIndex<T>;\n    restore(tree: AvlTreeIndex<T>): void;\n    /**\n     * Used for inserting a new value into the BinaryTreeIndex\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val Value to be indexed and inserted into binary tree\n     */\n    insert(id: number, val: T): void;\n    /**\n     * Recursively inserts a treenode and re-balances if needed.\n     * @param current\n     * @param node\n     */\n    insertNode(current: TreeNode<T>, node: TreeNode<T>): number;\n    /**\n     * Updates height and balance (calculation) for tree node\n     * @param node\n     */\n    private updateBalance(node);\n    /**\n     * Balance the 'double left-heavy' condition\n     * @param node\n     */\n    private leftLeftCase(node);\n    /**\n     * Balance the '(parent) left heavy, (child) right heavy' condition\n     * @param node\n     */\n    private leftRightCase(node);\n    /**\n     * Balance the 'double right-heavy' condition\n     * @param node\n     */\n    private rightRightCase(node);\n    /**\n     * Balance the '(parent) right heavy, (child) left heavy' condition\n     * @param node\n     */\n    private rightLeftCase(node);\n    /**\n     * Left rotation of node. Swaps right child into current location.\n     * @param node\n     */\n    private rotateLeft(node);\n    /**\n     * Right rotation of node. Swaps left child into current location.\n     * @param node\n     */\n    private rotateRight(node);\n    /**\n     * Diagnostic method for examining tree contents and structure\n     * @param node\n     */\n    getValuesAsTree(node?: TreeNode<T>): any;\n    /**\n     * Updates a value, possibly relocating it, within binary tree\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val New value to be indexed within binary tree\n     */\n    update(id: number, val: T): void;\n    /**\n     * Removes a value from the binary tree index\n     * @param id\n     */\n    remove(id: number): void;\n    /**\n     * Recursive node removal and rebalancer\n     * @param node\n     * @param val\n     */\n    private removeNode(node, id);\n    /**\n     * Utility method for updating a parent's child link when it changes\n     * @param parentId\n     * @param oldChildId\n     * @param newChildId\n     */\n    private updateChildLink(parentId, oldChildId, newChildId);\n    /**\n     * When removing a parent with only child, this does simple remap of child to grandParent.\n     * @param grandParent New parent of 'child'.\n     * @param parent Node being removed.\n     * @param child Node to reparent to grandParent.\n     */\n    private promoteChild(parent, child);\n    /**\n     * Finds a successor to a node and replaces that node with it.\n     * @param node\n     */\n    private promoteSuccessor(node);\n    /**\n     * Utility method for finding In-Order predecessor to the provided node\n     * @param node Parent node to find leaf node of greatest 'value'\n    */\n    private findGreaterLeaf(node);\n    /**\n     * Utility method for finding In-Order successor to the provided node\n     * @param node Parent Node to find leaf node of least 'value'\n     */\n    private findLesserLeaf(node);\n    /**\n     *  Interface method to support ranged queries.  Results sorted by index property.\n     * @param range Options for ranged request.\n     */\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    /**\n     * Implements ranged request operations.\n     * @param node\n     * @param range\n     */\n    private collateRequest(node, range);\n    /**\n     * Used on a branch node to return an array of id within that branch, sorted by their value\n     * @param node\n     */\n    private collateIds(node);\n    /**\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    /**\n     * Inline/Non-recusive 'single value' ($eq) lookup.\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    private locate(node, val);\n    /**\n     * Index integrity check (IRangedIndex interface function)\n     */\n    validateIndex(): boolean;\n    /**\n     * Recursive Node validation routine\n     * @param node\n     */\n    private validateNode(node);\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/loki/src/clone.d.ts",
    "content": "export declare type CloneMethod = \"parse-stringify\" | \"deep\" | \"shallow\" | \"shallow-recurse\";\n/**\n * @hidden\n */\nexport declare function clone<T>(data: T, method?: CloneMethod): T;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/loki/src/collection.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { UniqueIndex } from \"./unique_index\";\nimport { ResultSet } from \"./result_set\";\nimport { DynamicView } from \"./dynamic_view\";\nimport { IRangedIndex } from \"./ranged_indexes\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc, Dict } from \"../../common/types\";\nimport { FullTextSearch } from \"../../full-text-search/src/full_text_search\";\nimport { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\n/**\n * Collection class that handles documents of same type\n * @extends LokiEventEmitter\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class Collection<TData extends object = object, TNested extends object = object, T extends TData & TNested = TData & TNested> extends LokiEventEmitter {\n    name: string;\n    _data: Doc<T>[];\n    private _idIndex;\n    _rangedIndexes: {\n        [P in keyof T]?: Collection.RangedIndexMeta;\n    };\n    _lokimap: {\n        [$loki: number]: Doc<T>;\n    };\n    _unindexedSortComparator: string;\n    _defaultLokiOperatorPackage: string;\n    /**\n     * Unique constraints contain duplicate object references, so they are not persisted.\n     * We will keep track of properties which have unique constraints applied here, and regenerate on load.\n     */\n    _constraints: {\n        unique: {\n            [P in keyof T]?: UniqueIndex;\n        };\n    };\n    /**\n     * Transforms will be used to store frequently used query chains as a series of steps which itself can be stored along\n     * with the database.\n     */\n    _transforms: Dict<Collection.Transform<T>[]>;\n    /**\n     * In autosave scenarios we will use collection level dirty flags to determine whether save is needed.\n     * currently, if any collection is dirty we will autosave the whole database if autosave is configured.\n     * Defaulting to true since this is called from addCollection and adding a collection should trigger save.\n     */\n    _dirty: boolean;\n    private _cached;\n    /**\n     * Is collection transactional.\n     */\n    private _transactional;\n    /**\n     * Options to clone objects when inserting them.\n     */\n    _cloneObjects: boolean;\n    /**\n     * Default clone method (if enabled) is parse-stringify.\n     */\n    _cloneMethod: CloneMethod;\n    /**\n     * If set to true we will not maintain a meta property for a document.\n     */\n    private _disableMeta;\n    /**\n     * Disable track changes.\n     */\n    private _disableChangesApi;\n    /**\n     * Disable delta update object style on changes.\n     */\n    _disableDeltaChangesApi: boolean;\n    /**\n     * By default, if you insert a document with a Date value for an indexed property, we will convert that value to number.\n     */\n    private _serializableIndexes;\n    /**\n     * Name of path of used nested properties.\n     */\n    private _nestedProperties;\n    /**\n     * Option to activate a cleaner daemon - clears \"aged\" documents at set intervals.\n     */\n    _ttl: Collection.TTL;\n    private _maxId;\n    private _dynamicViews;\n    /**\n     * Changes are tracked by collection and aggregated by the db.\n     */\n    private _changes;\n    /**\n     * stages: a map of uniquely identified 'stages', which hold copies of objects to be\n     * manipulated without affecting the data in the original collection\n     */\n    private _stages;\n    private _commitLog;\n    _fullTextSearch: FullTextSearch;\n    /**\n     * @param {string} name - collection name\n     * @param {(object)} [options={}] - a configuration object\n     * @param {string[]} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {string[]} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {RangedIndexOptions} [options.rangedIndexes] - configuration object for ranged indexes\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are invoked asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes API\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {boolean} [options.serializableIndexes=true] - converts date values on binary indexed property values are serializable\n     * @param {string} [options.cloneMethod=\"deep\"] - the clone method\n     * @param {number} [options.transactional=false] - ?\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale.\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @param {string} [options.unindexedSortComparator=\"js\"] \"js\", \"abstract\", \"abstract-date\", \"loki\" or other registered comparator name\n     * @param {string} [options.defaultLokiOperatorPackage=\"js\"] \"js\", \"loki\", \"comparator\" (or user defined) query ops package\n     * @param {FullTextSearch.FieldOptions} [options.fullTextSearch=] - the full-text search options\n     * @see {@link Loki#addCollection} for normal creation of collections\n     */\n    constructor(name: string, options?: Collection.Options<TData, TNested>);\n    toJSON(): Collection.Serialized;\n    static fromJSONObject(obj: Collection.Serialized, options?: Collection.DeserializeOptions): Collection<any, object, any>;\n    /**\n     * Adds a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {array} transform - an array of transformation 'step' objects to save into the collection\n     */\n    addTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Retrieves a named transform from the collection.\n     * @param {string} name - name of the transform to lookup.\n     */\n    getTransform(name: string): Collection.Transform<T>[];\n    /**\n     * Updates a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {object} transform - a transformation object to save into collection\n     */\n    setTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Removes a named collection transform from the collection\n     * @param {string} name - name of collection transform to remove\n     */\n    removeTransform(name: string): void;\n    private setTTL(age, interval);\n    /**\n     * Create a row filter that covers all documents in the collection.\n     */\n    _prepareFullDocIndex(): number[];\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field\n     * @param indexTypeName\n     * @param comparatorName\n     */\n    ensureIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field Property to create an index on (need to look into contraining on keyof T)\n     * @param indexTypeName Name of IndexType factory within (global?) hashmap to create IRangedIndex from\n     * @param comparatorName Name of Comparator within (global?) hashmap\n     */\n    ensureRangedIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    ensureUniqueIndex(field: keyof T): UniqueIndex;\n    /**\n     * Quickly determine number of documents in collection (or query)\n     * @param {object} query - (optional) query object to count results of\n     * @returns {number} number of documents in the collection\n     */\n    count(query?: ResultSet.Query<Doc<T>>): number;\n    /**\n     * Rebuild idIndex\n     */\n    private _ensureId();\n    /**\n     * Add a dynamic view to the collection\n     * @param {string} name - name of dynamic view to add\n     * @param {object} options - (optional) options to configure dynamic view with\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=SortPriority.PASSIVE] - the sort priority\n     * @param {number} options.minRebuildInterval - minimum rebuild interval (need clarification to docs here)\n     * @returns {DynamicView} reference to the dynamic view added\n     **/\n    addDynamicView(name: string, options?: DynamicView.Options): DynamicView<T>;\n    /**\n     * Remove a dynamic view from the collection\n     * @param {string} name - name of dynamic view to remove\n     **/\n    removeDynamicView(name: string): void;\n    /**\n     * Look up dynamic view reference from within the collection\n     * @param {string} name - name of dynamic view to retrieve reference of\n     * @returns {DynamicView} A reference to the dynamic view with that name\n     **/\n    getDynamicView(name: string): DynamicView<T>;\n    /**\n     * Applies a 'mongo-like' find query object and passes all results to an update function.\n     * @param {object} filterObject - the 'mongo-like' query object\n     * @param {function} updateFunction - the update function\n     */\n    findAndUpdate(filterObject: ResultSet.Query<Doc<T>>, updateFunction: (obj: Doc<T>) => any): void;\n    /**\n     * Applies a 'mongo-like' find query object removes all documents which match that filter.\n     * @param {object} filterObject - 'mongo-like' query object\n     */\n    findAndRemove(filterObject: ResultSet.Query<Doc<T>>): void;\n    /**\n     * Adds object(s) to collection, ensure object(s) have meta properties, clone it if necessary, etc.\n     * @param {(object|array)} doc - the document (or array of documents) to be inserted\n     * @returns {(object|array)} document or documents inserted\n     */\n    insert(doc: TData): Doc<T>;\n    insert(doc: TData[]): Doc<T>[];\n    /**\n     * Adds a single object, ensures it has meta properties, clone it if necessary, etc.\n     * @param {object} doc - the document to be inserted\n     * @param {boolean} bulkInsert - quiet pre-insert and insert event emits\n     * @returns {object} document or 'undefined' if there was a problem inserting it\n     */\n    insertOne(doc: TData, bulkInsert?: boolean): Doc<T>;\n    /**\n     * Refers nested properties of an object to the root of it.\n     * @param {T} data - the object\n     * @returns {T & TNested} the object with nested properties\n     * @hidden\n     */\n    _defineNestedProperties<U extends TData>(data: U): U & TNested;\n    /**\n     * Empties the collection.\n     * @param {boolean} [removeIndices=false] - remove indices\n     */\n    clear({removeIndices: removeIndices}?: {\n        removeIndices?: boolean;\n    }): void;\n    /**\n     * Updates an object and notifies collection that the document has changed.\n     * @param {object} doc - document to update within the collection\n     */\n    update(doc: Doc<T> | Doc<T>[]): void;\n    /**\n     * Add object to collection\n     */\n    private _add(obj);\n    /**\n     * Applies a filter function and passes all results to an update function.\n     * @param {function} filterFunction - the filter function\n     * @param {function} updateFunction - the update function\n     */\n    updateWhere(filterFunction: (obj: Doc<T>) => boolean, updateFunction: (obj: Doc<T>) => Doc<T>): void;\n    /**\n     * Remove all documents matching supplied filter function.\n     * @param {function} filterFunction - the filter function\n     */\n    removeWhere(filterFunction: (obj: Doc<T>) => boolean): void;\n    removeDataOnly(): void;\n    /**\n     * Remove a document from the collection\n     * @param {number|object} doc - document to remove from collection\n     */\n    remove(doc: number | Doc<T> | Doc<T>[]): void;\n    /**\n     * Returns all changes.\n     * @returns {Collection.Change[]}\n     */\n    getChanges(): Collection.Change[];\n    /**\n     * Enables/disables changes api.\n     * @param {boolean} disableChangesApi\n     * @param {boolean} disableDeltaChangesApi\n     */\n    setChangesApi(disableChangesApi: boolean, disableDeltaChangesApi?: boolean): void;\n    /**\n     * Clears all the changes.\n     */\n    flushChanges(): void;\n    private _getObjectDelta(oldObject, newObject);\n    /**\n     * Compare changed object (which is a forced clone) with existing object and return the delta\n     */\n    private _getChangeDelta(obj, old);\n    /**\n     * Creates a clone of the current status of an object and associates operation and collection name,\n     * so the parent db can aggregate and generate a changes object for the entire db\n     */\n    private _createChange(name, op, obj, old?);\n    private _createInsertChange(obj);\n    private _createUpdateChange(obj, old);\n    private _insertMetaWithChange(obj);\n    private _updateMetaWithChange(obj, old);\n    private _insertMeta(obj);\n    private _updateMeta(obj);\n    /**\n     * Get by Id - faster than other methods because of the searching algorithm\n     * @param {int} id - $loki id of document you want to retrieve\n     * @param {boolean} returnPosition - if 'true' we will return [object, position]\n     * @returns {(object|array|null)} Object reference if document was found, null if not,\n     *     or an array if 'returnPosition' was passed.\n     */\n    get(id: number): Doc<T>;\n    get(id: number, returnPosition: boolean): Doc<T> | [Doc<T>, number];\n    /**\n     * Retrieve doc by Unique index\n     * @param {string} field - name of uniquely indexed property to use when doing lookup\n     * @param {any} value - unique value to search for\n     * @returns {object} document matching the value passed\n     */\n    by(field: keyof T, value: any): Doc<T>;\n    /**\n     * Find one object by index property, by property equal to value\n     * @param {object} query - query object used to perform search with\n     * @returns {(object|null)} First matching document, or null if none\n     */\n    findOne(query: ResultSet.Query<Doc<T>>): Doc<T>;\n    /**\n     * Chain method, used for beginning a series of chained find() and/or view() operations\n     * on a collection.\n     *\n     * @param {array} transform - Ordered array of transform step objects similar to chain\n     * @param {object} parameters - Object containing properties representing parameters to substitute\n     * @returns {ResultSet} (this) ResultSet, or data array if any map or join functions where called\n     */\n    chain(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Find method, api is similar to mongodb.\n     * for more complex queries use [chain()]{@link Collection#chain} or [where()]{@link Collection#where}.\n     * @example {@tutorial Query Examples}\n     * @param {object} query - 'mongo-like' query object\n     * @returns {array} Array of matching documents\n     */\n    find(query?: ResultSet.Query<Doc<T>>): Doc<T>[];\n    /**\n     * Find object by unindexed field by property equal to value,\n     * simply iterates and returns the first element matching the query\n     */\n    findOneUnindexed(prop: string, value: any): Doc<T>;\n    /**\n     * Transaction methods\n     */\n    /**\n     * start the transation\n     */\n    startTransaction(): void;\n    /**\n     * Commit the transaction.\n     */\n    commit(): void;\n    /**\n     * Rollback the transaction.\n     */\n    rollback(): void;\n    /**\n     * Query the collection by supplying a javascript filter function.\n     * @example\n     * let results = coll.where(function(obj) {\n       *   return obj.legs === 8;\n       * });\n     * @param {function} fun - filter function to run against all collection docs\n     * @returns {array} all documents which pass your filter function\n     */\n    where(fun: (obj: Doc<T>) => boolean): Doc<T>[];\n    /**\n     * Map Reduce operation\n     * @param {function} mapFunction - function to use as map function\n     * @param {function} reduceFunction - function to use as reduce function\n     * @returns {data} The result of your mapReduce operation\n     */\n    mapReduce<U1, U2>(mapFunction: (value: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Join two collections on specified properties\n     * @param {array} joinData - array of documents to 'join' to this collection\n     * @param {string} leftJoinProp - property name in collection\n     * @param {string} rightJoinProp - property name in joinData\n     * @param {function} mapFun - (Optional) map function to use\n     * @param dataOptions - options to data() before input to your map function\n     * @param [dataOptions.removeMeta] - allows removing meta before calling mapFun\n     * @param [dataOptions.forceClones] - forcing the return of cloned objects to your map object\n     * @param [dataOptions.forceCloneMethod] - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} Result of the mapping operation\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinProp: string | ((obj: any) => string), rightJoinProp: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * (Staging API) create a stage and/or retrieve it\n     */\n    getStage(name: string): any;\n    /**\n     * a collection of objects recording the changes applied through a commmitStage\n     */\n    /**\n     * (Staging API) create a copy of an object and insert it into a stage\n     */\n    stage<F extends TData>(stageName: string, obj: Doc<F>): F;\n    /**\n     * (Staging API) re-attach all objects to the original collection, so indexes and views can be rebuilt\n     * then create a message to be inserted in the commitlog\n     * @param {string} stageName - name of stage\n     * @param {string} message\n     */\n    commitStage(stageName: string, message: string): void;\n    /**\n     * Returns all values of a field.\n     * @param {string} field - the field name\n     * @return {any}: the array of values\n     */\n    extract(field: keyof T): any[];\n    /**\n     * Finds the minimum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the minimum value\n     */\n    min(field: keyof T): number;\n    /**\n     * Finds the maximum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the maximum value\n     */\n    max(field: keyof T): number;\n    /**\n     * Finds the minimum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    minRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Finds the maximum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    maxRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Returns all values of a field as numbers (if possible).\n     * @param {string} field - the field name\n     * @return {number[]} - the number array\n     */\n    extractNumerical(field: keyof T): number[];\n    /**\n     * Calculates the average numerical value of a field\n     * @param {string} field - the field name\n     * @returns {number} average of property in all docs in the collection\n     */\n    avg(field: keyof T): number;\n    /**\n     * Calculate the standard deviation of a field.\n     * @param {string} field - the field name\n     * @return {number} the standard deviation\n     */\n    stdDev(field: keyof T): number;\n    /**\n     * Calculates the mode of a field.\n     * @param {string} field - the field name\n     * @return {number} the mode\n     */\n    mode(field: keyof T): number;\n    /**\n     * Calculates the median of a field.\n     * @param {string} field - the field name\n     * @return {number} the median\n     */\n    median(field: keyof T): number;\n}\nexport declare namespace Collection {\n    interface Options<TData extends object, TNested extends object = {}, T extends object = TData & TNested> {\n        unique?: (keyof T)[];\n        unindexedSortComparator?: string;\n        defaultLokiOperatorPackage?: string;\n        rangedIndexes?: RangedIndexOptions;\n        serializableIndexes?: boolean;\n        asyncListeners?: boolean;\n        disableMeta?: boolean;\n        disableChangesApi?: boolean;\n        disableDeltaChangesApi?: boolean;\n        clone?: boolean;\n        serializableIndices?: boolean;\n        cloneMethod?: CloneMethod;\n        transactional?: boolean;\n        ttl?: number;\n        ttlInterval?: number;\n        nestedProperties?: (keyof TNested | {\n            name: keyof TNested;\n            path: string[];\n        })[];\n        fullTextSearch?: FullTextSearch.FieldOptions[];\n    }\n    interface RangedIndexOptions {\n        [prop: string]: RangedIndexMeta;\n    }\n    interface DeserializeOptions {\n        retainDirtyFlags?: boolean;\n        fullTextSearch?: Dict<Analyzer>;\n        [collName: string]: any | {\n            proto?: any;\n            inflate?: (src: object, dest?: object) => void;\n        };\n    }\n    interface BinaryIndex {\n        dirty: boolean;\n        values: any;\n    }\n    interface RangedIndexMeta {\n        index?: IRangedIndex<any>;\n        indexTypeName?: string;\n        comparatorName?: string;\n    }\n    interface Change {\n        name: string;\n        operation: string;\n        obj: any;\n    }\n    interface Serialized {\n        name: string;\n        unindexedSortComparator: string;\n        defaultLokiOperatorPackage: string;\n        _dynamicViews: DynamicView[];\n        _nestedProperties: {\n            name: string;\n            path: string[];\n        }[];\n        uniqueNames: string[];\n        transforms: Dict<Transform[]>;\n        rangedIndexes: RangedIndexOptions;\n        _data: Doc<any>[];\n        idIndex: number[];\n        maxId: number;\n        _dirty: boolean;\n        transactional: boolean;\n        asyncListeners: boolean;\n        disableMeta: boolean;\n        disableChangesApi: boolean;\n        disableDeltaChangesApi: boolean;\n        cloneObjects: boolean;\n        cloneMethod: CloneMethod;\n        changes: any;\n        _fullTextSearch: FullTextSearch;\n    }\n    interface CheckIndexOptions {\n        randomSampling?: boolean;\n        randomSamplingFactor?: number;\n        repair?: boolean;\n    }\n    type Transform<T extends object = object> = {\n        type: \"find\";\n        value: ResultSet.Query<Doc<T>> | string;\n    } | {\n        type: \"where\";\n        value: ((obj: Doc<T>) => boolean) | string;\n    } | {\n        type: \"simplesort\";\n        property: keyof T;\n        options?: boolean | ResultSet.SimpleSortOptions;\n    } | {\n        type: \"compoundsort\";\n        value: (keyof T | [keyof T, boolean])[];\n    } | {\n        type: \"sort\";\n        value: (a: Doc<T>, b: Doc<T>) => number;\n    } | {\n        type: \"sortByScoring\";\n        desc?: boolean;\n    } | {\n        type: \"limit\";\n        value: number;\n    } | {\n        type: \"offset\";\n        value: number;\n    } | {\n        type: \"map\";\n        value: (obj: Doc<T>, index: number, array: Doc<T>[]) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"eqJoin\";\n        joinData: Collection<any> | ResultSet<any>;\n        leftJoinKey: string | ((obj: any) => string);\n        rightJoinKey: string | ((obj: any) => string);\n        mapFun?: (left: any, right: any) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"mapReduce\";\n        mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => any;\n        reduceFunction: (array: any[]) => any;\n    } | {\n        type: \"update\";\n        value: (obj: Doc<T>) => any;\n    } | {\n        type: \"remove\";\n    };\n    interface TTL {\n        age: number;\n        ttlInterval: number;\n        daemon: any;\n    }\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/loki/src/comparators.d.ts",
    "content": "export interface ILokiComparer<T> {\n    (a: T, b: T): -1 | 0 | 1;\n}\nexport interface IComparatorMap {\n    [name: string]: ILokiComparer<any>;\n}\n/** Map/Register of named ILokiComparer functions returning -1, 0, 1 for lt/eq/gt assertions for two passed parameters */\nexport declare let ComparatorMap: IComparatorMap;\n/** Typescript-friendly factory for strongly typed 'js' comparators */\nexport declare function CreateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'abstract js' comparators */\nexport declare function CreateAbstractJavascriptComparator<T>(): ILokiComparer<T>;\n/**\n * Comparator which attempts to deal with deal with dates at comparator level.\n * Should work for dates in any of the object, string, and number formats\n */\nexport declare function CreateAbstractDateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'loki' comparators */\nexport declare function CreateLokiComparator(): ILokiComparer<any>;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/loki/src/dynamic_view.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { ResultSet } from \"./result_set\";\nimport { Collection } from \"./collection\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\n/**\n * DynamicView class is a versatile 'live' view class which can have filters and sorts applied.\n *    Collection.addDynamicView(name) instantiates this DynamicView object and notifies it\n *    whenever documents are add/updated/removed so it can remain up-to-date. (chainable)\n *\n * @example\n * let mydv = mycollection.addDynamicView('test');  // default is non-persistent\n * mydv.applyFind({ 'doors' : 4 });\n * mydv.applyWhere(function(obj) { return obj.name === 'Toyota'; });\n * let results = mydv.data();\n *\n * @extends LokiEventEmitter\n\n * @see {@link Collection#addDynamicView} to construct instances of DynamicView\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class DynamicView<T extends object = object> extends LokiEventEmitter {\n    readonly name: string;\n    private _collection;\n    private _persistent;\n    private _sortPriority;\n    private _minRebuildInterval;\n    private _rebuildPending;\n    private _resultSet;\n    private _resultData;\n    private _resultDirty;\n    private _cachedResultSet;\n    private _filterPipeline;\n    private _sortFunction;\n    private _sortCriteria;\n    private _sortCriteriaSimple;\n    private _sortByScoring;\n    private _sortDirty;\n    /**\n     * Constructor.\n     * @param {Collection} collection - a reference to the collection to work agains\n     * @param {string} name - the name of this dynamic view\n     * @param {object} options - the options\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=\"passive\"] - the sort priority\n     * @param {number} [options.minRebuildInterval=1] - minimum rebuild interval (need clarification to docs here)\n     */\n    constructor(collection: Collection<T>, name: string, options?: DynamicView.Options);\n    /**\n     * Internally used immediately after deserialization (loading)\n     *    This will clear out and reapply filterPipeline ops, recreating the view.\n     *    Since where filters do not persist correctly, this method allows\n     *    restoring the view to state where user can re-apply those where filters.\n     *\n     * @param removeWhereFilters\n     * @returns {DynamicView} This dynamic view for further chained ops.\n     * @fires DynamicView.rebuild\n     */\n    private _rematerialize({removeWhereFilters});\n    /**\n     * Makes a copy of the internal ResultSet for branched queries.\n     * Unlike this dynamic view, the branched ResultSet will not be 'live' updated,\n     * so your branched query should be immediately resolved and not held for future evaluation.\n     * @param {(string|array=)} transform - Optional name of collection transform, or an array of transform steps\n     * @param {object} parameters - optional parameters (if optional transform requires them)\n     * @returns {ResultSet} A copy of the internal ResultSet for branched queries.\n     */\n    branchResultSet(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Override of toJSON to avoid circular references.\n     */\n    toJSON(): DynamicView.Serialized;\n    static fromJSONObject(collection: Collection, obj: DynamicView.Serialized): DynamicView;\n    /**\n     * Used to clear pipeline and reset dynamic view to initial state.\n     * Existing options should be retained.\n     * @param {boolean} queueSortPhase - (default: false) if true we will async rebuild view (maybe set default to true in future?)\n     */\n    removeFilters({queueSortPhase}?: {\n        queueSortPhase?: boolean;\n    }): void;\n    /**\n     * Used to apply a sort to the dynamic view\n     * @example\n     * dv.applySort(function(obj1, obj2) {\n       *   if (obj1.name === obj2.name) return 0;\n       *   if (obj1.name > obj2.name) return 1;\n       *   if (obj1.name < obj2.name) return -1;\n       * });\n     * @param {function} comparefun - a javascript compare function used for sorting\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applySort(comparefun: (lhs: Doc<T>, rhs: Doc<T>) => number): this;\n    /**\n     * Used to specify a property used for view translation.\n     * @param {string} field - the field name\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether we should sort descending.\n     * @param {boolean} [options.disableIndexIntersect=false] - whether we should explicity not use array intersection.\n     * @param {boolean} [options.forceIndexIntersect=false] - force array intersection (if binary index exists).\n     * @param {boolean} [options.useJavascriptSorting=false] - whether results are sorted via basic javascript sort.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     * @example\n     * dv.applySimpleSort(\"name\");\n     */\n    applySimpleSort(field: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @param {Array} criteria - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {DynamicView} Reference to this DynamicView, sorted, for future chain operations.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * dv.applySortCriteria(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * dv.applySortCriteria(['age', ['name', true]]);\n     * // to sort by age (descending) and then by name (descending)\n     * dv.applySortCriteria([['age', true], ['name', true]]);\n     */\n    applySortCriteria(criteria: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Used to apply a sort by the latest full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     */\n    applySortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Marks the beginning of a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    startTransaction(): this;\n    /**\n     * Commits a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    commit(): this;\n    /**\n     * Rolls back a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    rollback(): this;\n    /**\n     * Find the index of a filter in the pipeline, by that filter's ID.\n     * @param {(string|number)} uid - The unique ID of the filter.\n     * @returns {number}: index of the referenced filter in the pipeline; -1 if not found.\n     */\n    private _indexOfFilterWithId(uid);\n    /**\n     * Add the filter object to the end of view's filter pipeline and apply the filter to the ResultSet.\n     * @param {object} filter - The filter object. Refer to applyFilter() for extra details.\n     */\n    private _addFilter(filter);\n    /**\n     * Reapply all the filters in the current pipeline.\n     *\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    reapplyFilters(): this;\n    /**\n     * Adds or updates a filter in the DynamicView filter pipeline\n     * @param {object} filter - A filter object to add to the pipeline.\n     *    The object is in the format { 'type': filter_type, 'val', filter_param, 'uid', optional_filter_id }\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFilter(filter: DynamicView.Filter<T>): this;\n    /**\n     * applyFind() - Adds or updates a mongo-style query option in the DynamicView filter pipeline\n     *\n     * @param {object} query - A mongo-style query object to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFind(query: object, uid?: string | number): this;\n    /**\n     * Adds or updates a javascript filter function in the DynamicView filter pipeline\n     * @param {function} fun - A javascript filter function to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyWhere(fun: (obj: Doc<T>) => boolean, uid?: string | number): this;\n    /**\n     * Remove the specified filter from the DynamicView filter pipeline\n     * @param {(string|number)} uid - The unique ID of the filter to be removed.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    removeFilter(uid: string | number): this;\n    /**\n     * Returns the number of documents representing the current DynamicView contents.\n     * @returns {number} The number of documents representing the current DynamicView contents.\n     */\n    count(): number;\n    /**\n     * Resolves and pending filtering and sorting, then returns document array as result.\n     * @param {object} options - optional parameters to pass to ResultSet.data() if non-persistent\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values include 'parse-stringify', 'jquery-extend-deep', 'shallow', 'shallow-assign'\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} An array of documents representing the current DynamicView contents.\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * When the view is not sorted we may still wish to be notified of rebuild events.\n     * This event will throttle and queue a single rebuild event when batches of updates affect the view.\n     */\n    private _queueRebuildEvent();\n    /**\n     * If the view is sorted we will throttle sorting to either :\n     * (1) passive - when the user calls data(), or\n     * (2) active - once they stop updating and yield js thread control\n     */\n    private _queueSortPhase();\n    /**\n     * Invoked synchronously or asynchronously to perform final sort phase (if needed)\n     */\n    private _performSortPhase(options?);\n    /**\n     * (Re)evaluating document inclusion.\n     * Called by : collection.insert() and collection.update().\n     * @param {int} objIndex - index of document to (re)run through filter pipeline.\n     * @param {boolean} isNew - true if the document was just added to the collection.\n     * @hidden\n     */\n    _evaluateDocument(objIndex: number, isNew: boolean): void;\n    /**\n     * Internal function called on collection.delete().\n     * @hidden\n     */\n    _removeDocument(objIndex: number): void;\n    /**\n     * Data transformation via user supplied functions\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: T, index: number, array: T[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n}\nexport declare namespace DynamicView {\n    interface Options {\n        persistent?: boolean;\n        sortPriority?: SortPriority;\n        minRebuildInterval?: number;\n    }\n    type SortPriority = \"passive\" | \"active\";\n    interface Serialized {\n        name: string;\n        _persistent: boolean;\n        _sortPriority: SortPriority;\n        _minRebuildInterval: number;\n        _resultSet: ResultSet<any>;\n        _filterPipeline: Filter<any>[];\n        _sortCriteria: (string | [string, boolean])[];\n        _sortCriteriaSimple: {\n            field: string;\n            options: boolean | ResultSet.SimpleSortOptions;\n        };\n        _sortByScoring: boolean;\n        _sortDirty: boolean;\n    }\n    type Filter<T extends object = object> = {\n        type: \"find\";\n        val: ResultSet.Query<Doc<T>>;\n        uid: number | string;\n    } | {\n        type: \"where\";\n        val: (obj: Doc<T>) => boolean;\n        uid: number | string;\n    };\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/loki/src/event_emitter.d.ts",
    "content": "/**\n * LokiEventEmitter is a minimalist version of EventEmitter. It enables any\n * constructor that inherits EventEmitter to emit events and trigger\n * listeners that have been added to the event through the on(event, callback) method\n *\n * @constructor LokiEventEmitter\n */\nexport declare class LokiEventEmitter {\n    /**\n     * A map, with each property being an array of callbacks.\n     */\n    protected _events: object;\n    /**\n     * Determines whether or not the callbacks associated with each event should happen in an async fashion or not.\n     * Default is false, which means events are synchronous\n     */\n    protected _asyncListeners: boolean;\n    /**\n     * Adds a listener to the queue of callbacks associated to an event\n     * @param {string|string[]} eventName - the name(s) of the event(s) to listen to\n     * @param {function} listener - callback function of listener to attach\n     * @returns {int} the index of the callback in the array of listeners for a particular event\n     */\n    on(eventName: string | string[], listener: Function): Function;\n    /**\n     * Emits a particular event\n     * with the option of passing optional parameters which are going to be processed by the callback\n     * provided signatures match (i.e. if passing emit(event, arg0, arg1) the listener should take two parameters)\n     * @param {string} eventName - the name of the event\n     * @param {object} data - optional object passed with the event\n     */\n    protected emit(eventName: string, ...data: any[]): void;\n    /**\n     * Alias of EventEmitter.on().\n     */\n    addListener(eventName: string | string[], listener: Function): Function;\n    /**\n     * Removes the listener at position 'index' from the event 'eventName'\n     * @param {string|string[]} eventName - the name(s) of the event(s) which the listener is attached to\n     * @param {function} listener - the listener callback function to remove from emitter\n     */\n    removeListener(eventName: string | string[], listener: Function): void;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/loki/src/index.d.ts",
    "content": "import { Loki } from \"./loki\";\nimport { Collection } from \"./collection\";\nexport { Loki, Collection };\nexport default Loki;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/loki/src/loki.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { Collection } from \"./collection\";\nimport { Doc, StorageAdapter } from \"../../common/types\";\nimport { IComparatorMap } from \"./comparators\";\nimport { IRangedIndexFactoryMap } from \"./ranged_indexes\";\nimport { ILokiOperatorPackageMap } from \"./operator_packages\";\nexport declare class Loki extends LokiEventEmitter {\n    filename: string;\n    private databaseVersion;\n    private engineVersion;\n    _collections: Collection[];\n    private _env;\n    private _serializationMethod;\n    private _destructureDelimiter;\n    private _persistenceMethod;\n    private _persistenceAdapter;\n    private _throttledSaves;\n    private _throttledSaveRunning;\n    private _throttledSavePending;\n    private _autosave;\n    private _autosaveInterval;\n    private _autosaveRunning;\n    private _autosaveHandler;\n    /**\n     * Constructs the main database class.\n     * @param {string} filename - name of the file to be saved to\n     * @param {object} [options={}] - options\n     * @param {Loki.Environment} [options.env] - the javascript environment\n     * @param {Loki.SerializationMethod} [options.serializationMethod=NORMAL] - the serialization method\n     * @param {string} [options.destructureDelimiter=\"$<\\n\"] - string delimiter used for destructured serialization\n     * @param {IComparatorMap} [options.comparatorMap] allows injecting or overriding registered comparators\n     * @param {IRangedIndexFactoryMap} [options.rangedIndexFactoryMap] allows injecting or overriding registered ranged index factories\n     * @param {ILokiOperatorPackageMap} [options.lokiOperatorPackageMap] allows injecting or overriding registered loki operator packages\n     */\n    constructor(filename?: string, options?: Loki.Options);\n    /**\n     * configures options related to database persistence.\n     *\n     * @param {Loki.PersistenceOptions} [options={}] - options\n     * @param {adapter} [options.adapter=auto] - an instance of a loki persistence adapter\n     * @param {boolean} [options.autosave=false] - enables autosave\n     * @param {int} [options.autosaveInterval=5000] - time interval (in milliseconds) between saves (if dirty)\n     * @param {boolean} [options.autoload=false] - enables autoload on loki instantiation\n     * @param {object} options.inflate - options that are passed to loadDatabase if autoload enabled\n     * @param {boolean} [options.throttledSaves=true] - if true, it batches multiple calls to to saveDatabase reducing number of\n     *   disk I/O operations and guaranteeing proper serialization of the calls. Default value is true.\n     * @param {Loki.PersistenceMethod} options.persistenceMethod - a persistence method which should be used (FS_STORAGE, LOCAL_STORAGE...)\n     * @returns {Promise} a Promise that resolves after initialization and (if enabled) autoloading the database\n     */\n    initializePersistence(options?: Loki.PersistenceOptions): Promise<void>;\n    /**\n     * Copies 'this' database into a new Loki instance. Object references are shared to make lightweight.\n     * @param {object} options - options\n     * @param {boolean} options.removeNonSerializable - nulls properties not safe for serialization.\n     */\n    copy(options?: Loki.CopyOptions): Loki;\n    /**\n     * Adds a collection to the database.\n     * @param {string} name - name of collection to add\n     * @param {object} [options={}] - options to configure collection with.\n     * @param {array} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {array} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {array} [options.indices=[]] - array property names to define binary indexes for\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are called asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes Api\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {string} [options.cloneMethod=CloneMethod.DEEP] - the clone method\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @returns {Collection} a reference to the collection which was just added\n     */\n    addCollection<TData extends object = object, TNested extends object = object>(name: string, options?: Collection.Options<TData, TNested>): Collection<TData, TNested>;\n    loadCollection(collection: Collection): void;\n    /**\n     * Retrieves reference to a collection by name.\n     * @param {string} name - name of collection to look up\n     * @returns {Collection} Reference to collection in database by that name, or null if not found\n     */\n    getCollection<TData extends object = object, TNested extends object = object>(name: string): Collection<TData, TNested>;\n    /**\n     * Renames an existing loki collection\n     * @param {string} oldName - name of collection to rename\n     * @param {string} newName - new name of collection\n     * @returns {Collection} reference to the newly renamed collection\n     */\n    renameCollection<TData extends object = object, TNested extends object = object>(oldName: string, newName: string): Collection<TData, TNested>;\n    listCollections(): {\n        name: string;\n        count: number;\n    }[];\n    /**\n     * Removes a collection from the database.\n     * @param {string} collectionName - name of collection to remove\n     */\n    removeCollection(collectionName: string): void;\n    /**\n     * Serialize database to a string which can be loaded via {@link Loki#loadJSON}\n     *\n     * @returns {string} Stringified representation of the loki database.\n     */\n    serialize(options?: Loki.SerializeOptions): string | string[];\n    toJSON(): Loki.Serialized;\n    /**\n     * Database level destructured JSON serialization routine to allow alternate serialization methods.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {object} options - output format options for use externally to loki\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to only output an individual collection or db (-1)\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {string|Array} A custom, restructured aggregation of independent serializations.\n     */\n    serializeDestructured(options?: Loki.SerializeDestructuredOptions): string | string[];\n    /**\n     * Collection level utility method to serialize a collection in a 'destructured' format\n     *\n     * @param {object} options - used to determine output of method\n     * @param {int} options.delimited - whether to return single delimited string or an array\n     * @param {string} options.delimiter - (optional) if delimited, this is delimiter to use\n     * @param {int} options.collectionIndex -  specify which collection to serialize data for\n     *\n     * @returns {string|array} A custom, restructured aggregation of independent serializations for a single collection.\n     */\n    serializeCollection(options?: {\n        delimited?: boolean;\n        collectionIndex?: number;\n        delimiter?: string;\n    }): string | string[];\n    /**\n     * Database level destructured JSON deserialization routine to minimize memory overhead.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {string|array} destructuredSource - destructured json or array to deserialize from\n     * @param {object} options - source format options\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to deserialize only a single partition\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {object|array} An object representation of the deserialized database, not yet applied to 'this' db or document array\n     */\n    deserializeDestructured(destructuredSource: string | string[], options?: Loki.SerializeDestructuredOptions): any;\n    /**\n     * Collection level utility function to deserializes a destructured collection.\n     *\n     * @param {string|string[]} destructuredSource - destructured representation of collection to inflate\n     * @param {object} options - used to describe format of destructuredSource input\n     * @param {int} [options.delimited=false] - whether source is delimited string or an array\n     * @param {string} options.delimiter - if delimited, this is delimiter to use (if other than default)\n     *\n     * @returns {Array} an array of documents to attach to collection.data.\n     */\n    deserializeCollection<T extends object = object>(destructuredSource: string | string[], options?: Loki.DeserializeCollectionOptions): Doc<T>[];\n    /**\n     * Inflates a loki database from a serialized JSON string\n     *\n     * @param {string} serializedDb - a serialized loki database string\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSON(serializedDb: string | string[], options?: Collection.DeserializeOptions): void;\n    /**\n     * Inflates a loki database from a JS object\n     *\n     * @param {object} dbObject - a serialized loki database object\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSONObject(dbObject: Loki, options?: Collection.DeserializeOptions): void;\n    loadJSONObject(dbObject: Loki.Serialized, options?: Collection.DeserializeOptions): void;\n    /**\n     * Emits the close event. In autosave scenarios, if the database is dirty, this will save and disable timer.\n     * Does not actually destroy the db.\n     *\n     * @returns {Promise} a Promise that resolves after closing the database succeeded\n     */\n    close(): Promise<void>;\n    /**-------------------------+\n     | Changes API               |\n     +--------------------------*/\n    /**\n     * The Changes API enables the tracking the changes occurred in the collections since the beginning of the session,\n     * so it's possible to create a differential dataset for synchronization purposes (possibly to a remote db)\n     */\n    /**\n     * (Changes API) : takes all the changes stored in each\n     * collection and creates a single array for the entire database. If an array of names\n     * of collections is passed then only the included collections will be tracked.\n     *\n     * @param {Array} [arrayOfCollectionNames=] - array of collection names. No arg means all collections are processed.\n     * @returns {Array} array of changes\n     * @see private method _createChange() in Collection\n     */\n    generateChangesNotification(arrayOfCollectionNames?: string[]): Collection.Change[];\n    /**\n     * (Changes API) - stringify changes for network transmission\n     * @returns {string} string representation of the changes\n     */\n    serializeChanges(collectionNamesArray?: string[]): string;\n    /**\n     * (Changes API) : clears all the changes in all collections.\n     */\n    clearChanges(): void;\n    /**\n     * Wait for throttledSaves to complete and invoke your callback when drained or duration is met.\n     *\n     * @param {object} options - configuration options\n     * @param {boolean} [options.recursiveWait=true] - if after queue is drained, another save was kicked off, wait for it\n     * @param {boolean} [options.recursiveWaitLimit=false] - limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDuration=2000] - cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves when save queue is drained, it is passed a sucess parameter value\n     */\n    throttledSaveDrain(options?: Loki.ThrottledDrainOptions): Promise<void>;\n    /**\n     * Internal load logic, decoupled from throttling/contention logic\n     *\n     * @param {object} options - an object containing inflation options for each collection\n     * @param {boolean} ignore_not_found - does not raise an error if database is not found\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    private _loadDatabase(options?, ignore_not_found?);\n    /**\n     * Handles manually loading from an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *    To avoid contention with any throttledSaves, we will drain the save queue first.\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @param {object} [options={}] - if throttling saves and loads, this controls how we drain save queue before loading\n     * @param {boolean} [options.recursiveWait=true] wait recursively until no saves are queued\n     * @param {boolean} [options.recursiveWaitLimit=false] limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDelay=2000] cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    loadDatabase(options?: Loki.LoadDatabaseOptions): Promise<void>;\n    private _saveDatabase();\n    /**\n     * Handles manually saving to an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @returns {Promise} a Promise that resolves after the database is persisted\n     */\n    saveDatabase(): Promise<void>;\n    /**\n     * Handles deleting a database from the underlying storage adapter\n     *\n     * @returns {Promise} a Promise that resolves after the database is deleted\n     */\n    deleteDatabase(): Promise<void>;\n    /****************\n     * Autosave API\n     ****************/\n    /**\n     * Check whether any collections are \"dirty\" meaning we need to save the (entire) database\n     * @returns {boolean} - true if database has changed since last autosave, otherwise false\n     */\n    private _autosaveDirty();\n    /**\n     * Resets dirty flags on all collections.\n     */\n    private _autosaveClearFlags();\n    /**\n     * Starts periodically saves to the underlying storage adapter.\n     */\n    private _autosaveEnable();\n    /**\n     * Stops the autosave interval timer.\n     */\n    private _autosaveDisable();\n}\nexport declare namespace Loki {\n    interface Options {\n        env?: Environment;\n        serializationMethod?: SerializationMethod;\n        destructureDelimiter?: string;\n        comparatorMap?: IComparatorMap;\n        rangedIndexFactoryMap?: IRangedIndexFactoryMap;\n        lokiOperatorPackageMap?: ILokiOperatorPackageMap;\n    }\n    interface PersistenceOptions {\n        adapter?: StorageAdapter;\n        autosave?: boolean;\n        autosaveInterval?: number;\n        autoload?: boolean;\n        throttledSaves?: boolean;\n        persistenceMethod?: Loki.PersistenceMethod;\n        inflate?: any;\n    }\n    interface CopyOptions {\n        removeNonSerializable?: boolean;\n    }\n    interface SerializeOptions {\n        serializationMethod?: SerializationMethod;\n    }\n    interface SerializeDestructuredOptions {\n        partitioned?: boolean;\n        partition?: number;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface DeserializeCollectionOptions {\n        partitioned?: boolean;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface ThrottledDrainOptions {\n        recursiveWait?: boolean;\n        recursiveWaitLimit?: boolean;\n        recursiveWaitLimitDuration?: number;\n        started?: Date;\n    }\n    interface Serialized {\n        _env: Environment;\n        _serializationMethod: SerializationMethod;\n        _autosave: boolean;\n        _autosaveInterval: number;\n        _collections: Collection[];\n        databaseVersion: number;\n        engineVersion: number;\n        filename: string;\n        _persistenceAdapter: StorageAdapter;\n        _persistenceMethod: PersistenceMethod;\n        _throttledSaves: boolean;\n    }\n    type LoadDatabaseOptions = Collection.DeserializeOptions & ThrottledDrainOptions;\n    type SerializationMethod = \"normal\" | \"pretty\" | \"destructured\";\n    type PersistenceMethod = \"fs-storage\" | \"local-storage\" | \"indexed-storage\" | \"memory-storage\" | \"adapter\";\n    type Environment = \"NATIVESCRIPT\" | \"NODEJS\" | \"CORDOVA\" | \"BROWSER\" | \"MEMORY\";\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/loki/src/operator_packages.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\n/** Hash interface for named LokiOperatorPackage registration */\nexport interface ILokiOperatorPackageMap {\n    [name: string]: LokiOperatorPackage;\n}\n/**\n * Helper function for determining 'loki' abstract equality which is a little more abstract than ==\n *     aeqHelper(5, '5') === true\n *     aeqHelper(5.0, '5') === true\n *     aeqHelper(new Date(\"1/1/2011\"), new Date(\"1/1/2011\")) === true\n *     aeqHelper({a:1}, {z:4}) === true (all objects sorted equally)\n *     aeqHelper([1, 2, 3], [1, 3]) === false\n *     aeqHelper([1, 2, 3], [1, 2, 3]) === true\n *     aeqHelper(undefined, null) === true\n * @param {any} prop1\n * @param {any} prop2\n * @returns {boolean}\n * @hidden\n */\nexport declare function aeqHelper(prop1: any, prop2: any): boolean;\n/**\n * Helper function for determining 'less-than' conditions for ops, sorting, and binary indices.\n *     In the future we might want $lt and $gt ops to use their own functionality/helper.\n *     Since binary indices on a property might need to index [12, NaN, new Date(), Infinity], we\n *     need this function (as well as gtHelper) to always ensure one value is LT, GT, or EQ to another.\n * @hidden\n */\nexport declare function ltHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @hidden\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} equal\n * @returns {boolean}\n */\nexport declare function gtHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} descending\n * @returns {number}\n * @hidden\n */\nexport declare function sortHelper(prop1: any, prop2: any, descending: boolean): number;\n/**\n * Default implementation of LokiOperatorPackage, using fastest javascript comparison operators.\n */\nexport declare class LokiOperatorPackage {\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n    $in(a: any, b: any): boolean;\n    $nin(a: any, b: any): boolean;\n    $keyin(a: string, b: object): boolean;\n    $nkeyin(a: string, b: object): boolean;\n    $definedin(a: string, b: object): boolean;\n    $undefinedin(a: string, b: object): boolean;\n    $regex(a: string, b: RegExp): boolean;\n    $containsNone(a: any, b: any): boolean;\n    $containsAny(a: any, b: any): boolean;\n    $contains(a: any, b: any): boolean;\n    $type(a: any, b: any): boolean;\n    $finite(a: number, b: boolean): boolean;\n    $size(a: any, b: any): boolean;\n    $len(a: any, b: any): boolean;\n    $where(a: any, b: any): boolean;\n    $not(a: any, b: any): boolean;\n    $and(a: any, b: any): boolean;\n    $or(a: any, b: any): boolean;\n    private doQueryOp(val, op);\n    private containsCheckFn(a);\n}\n/**\n * LokiOperatorPackage which utilizes abstract 'loki' comparisons for basic relational equality op implementations.\n */\nexport declare class LokiAbstractOperatorPackage extends LokiOperatorPackage {\n    constructor();\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * LokiOperatorPackage which utilizes provided comparator for basic relational equality op implementations.\n */\nexport declare class ComparatorOperatorPackage<T> extends LokiOperatorPackage {\n    comparator: ILokiComparer<T>;\n    constructor(comparator: ILokiComparer<T>);\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * Map/Register of named LokiOperatorPackages which implement all unindexed query ops within 'find' query objects\n */\nexport declare let LokiOperatorPackageMap: ILokiOperatorPackageMap;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/loki/src/ranged_indexes.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\nexport declare type RangedValueOperator = \"$gt\" | \"$gte\" | \"$lt\" | \"$lte\" | \"$eq\" | \"$neq\" | \"$between\";\nexport interface IRangedIndexRequest<T> {\n    op: RangedValueOperator;\n    val: T;\n    high?: T;\n}\n/** Defines interface which all loki ranged indexes need to implement */\nexport interface IRangedIndex<T> {\n    insert(id: number, val: T): void;\n    update(id: number, val: T): void;\n    remove(id: number): void;\n    restore(tree: any): void;\n    backup(): IRangedIndex<T>;\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    validateIndex(): boolean;\n}\n/** Hash Interface for global ranged index factory map*/\nexport interface IRangedIndexFactoryMap {\n    [name: string]: (name: string, comparator: ILokiComparer<any>) => IRangedIndex<any>;\n}\n/** Map/Register of named factory functions returning IRangedIndex instances */\nexport declare let RangedIndexFactoryMap: IRangedIndexFactoryMap;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/loki/src/result_set.d.ts",
    "content": "import { Collection } from \"./collection\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\nimport { Query as FullTextSearchQuery } from \"../../full-text-search/src/query_types\";\n/**\n * ResultSet class allowing chainable queries.  Intended to be instanced internally.\n *    Collection.find(), Collection.where(), and Collection.chain() instantiate this.\n *\n * @example\n *    mycollection.chain()\n *      .find({ 'doors' : 4 })\n *      .where(function(obj) { return obj.name === 'Toyota' })\n *      .data();\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class ResultSet<T extends object = object> {\n    _collection: Collection<T>;\n    _filteredRows: number[];\n    _filterInitialized: boolean;\n    private _scoring;\n    /**\n     * Constructor.\n     * @param {Collection} collection - the collection which this ResultSet will query against\n     */\n    constructor(collection: Collection<T>);\n    /**\n     * Reset the ResultSet to its initial state.\n     * @returns {ResultSet} Reference to this ResultSet, for future chain operations.\n     */\n    reset(): this;\n    /**\n     * Override of toJSON to avoid circular references\n     */\n    toJSON(): ResultSet<T>;\n    /**\n     * Allows you to limit the number of documents passed to next chain operation.\n     * A ResultSet copy() is made to avoid altering original ResultSet.\n     * @param {int} qty - The number of documents to return.\n     * @returns {ResultSet} Returns a copy of the ResultSet, limited by qty, for subsequent chain ops.\n     */\n    limit(qty: number): this;\n    /**\n     * Used for skipping 'pos' number of documents in the ResultSet.\n     * @param {int} pos - Number of documents to skip; all preceding documents are filtered out.\n     * @returns {ResultSet} Returns a copy of the ResultSet, containing docs starting at 'pos' for subsequent chain ops.\n     */\n    offset(pos: number): this;\n    /**\n     * To support reuse of ResultSet in branched query situations.\n     * @returns {ResultSet} Returns a copy of the ResultSet (set) but the underlying document references will be the same.\n     */\n    copy(): ResultSet<T>;\n    /**\n     * Executes a named collection transform or raw array of transform steps against the ResultSet.\n     * @param {(string|array)} transform - name of collection transform or raw transform array\n     * @param {object} [parameters=] - object property hash of parameters, if the transform requires them.\n     * @returns {ResultSet} either (this) ResultSet or a clone of of this ResultSet (depending on steps)\n     */\n    transform(transform: string | Collection.Transform<T>[], parameters?: object): this;\n    /**\n     * User supplied compare function is provided two documents to compare. (chainable)\n     * @example\n     *    rslt.sort(function(obj1, obj2) {\n       *      if (obj1.name === obj2.name) return 0;\n       *      if (obj1.name > obj2.name) return 1;\n       *      if (obj1.name < obj2.name) return -1;\n       *    });\n     * @param {function} comparefun - A javascript compare function used for sorting.\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    sort(comparefun: (a: Doc<T>, b: Doc<T>) => number): this;\n    /**\n     * Simpler, loose evaluation for user to sort based on a property name. (chainable).\n     * Sorting based on the same lt/gt helper functions used for binary indices.\n     * @param {string} propname - name of property to sort by.\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether to sort descending\n     * @param {string} [options.sortComparator] override default with name of comparator registered in ComparatorMap\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    simplesort(propname: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * rs.compoundsort(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * rs.compoundsort(['age', ['name', true]);\n     * @param {array} properties - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    compoundsort(properties: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Helper function for compoundsort(), performing individual object comparisons\n     * @param {Array} properties - array of property names, in order, by which to evaluate sort order\n     * @param {object} obj1 - first object to compare\n     * @param {object} obj2 - second object to compare\n     * @returns {number} 0, -1, or 1 to designate if identical (sortwise) or which should be first\n     */\n    private _compoundeval(properties, obj1, obj2);\n    /**\n     * Sorts the ResultSet based on the last full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     * @returns {ResultSet}\n     */\n    sortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Oversee the operation of OR'ed query expressions.\n     * OR'ed expression evaluation runs each expression individually against the full collection,\n     * and finally does a set OR on each expression's results.\n     * Each evaluation can utilize a binary index to prevent multiple linear array scans.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findOr(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $or(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Oversee the operation of AND'ed query expressions.\n     * AND'ed expression evaluation runs each expression progressively against the full collection,\n     * internally utilizing existing chained ResultSet functionality.\n     * Only the first filter can utilize a binary index.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findAnd(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $and(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Used for querying via a mongo-style query object.\n     *\n     * @param {object} query - A mongo-style query object used for filtering current results.\n     * @param {boolean} firstOnly - (Optional) Used by collection.findOne() - flag if this was invoked via findOne()\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    find(query?: ResultSet.Query<Doc<T>>, firstOnly?: boolean): this;\n    /**\n     * Used for filtering via a javascript filter function.\n     * @param {function} fun - A javascript function used for filtering current results by.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    where(fun: (obj: Doc<T>) => boolean): this;\n    /**\n     * Returns the number of documents in the ResultSet.\n     * @returns {number} The number of documents in the ResultSet.\n     */\n    count(): number;\n    /**\n     * Terminates the chain and returns array of filtered documents\n     * @param {object} options\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values 'parse-stringify', 'deep', and 'shallow' and\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} Array of documents in the ResultSet\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * Used to run an update operation on all documents currently in the ResultSet.\n     * @param {function} updateFunction - User supplied updateFunction(obj) will be executed for each document object.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    update(updateFunction: (obj: Doc<T>) => Doc<T>): this;\n    /**\n     * Removes all document objects which are currently in ResultSet from collection (as well as ResultSet)\n     * @returns {ResultSet} this (empty) ResultSet for further chain ops.\n     */\n    remove(): this;\n    /**\n     * data transformation via user supplied functions\n     *\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns {value} The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Left joining two sets of data. Join keys can be defined or calculated properties\n     * eqJoin expects the right join key values to be unique.  Otherwise left data will be joined on the last joinData object with that key\n     * @param {Array|ResultSet|Collection} joinData - Data array to join to.\n     * @param {(string|function)} leftJoinKey - Property name in this result set to join on or a function to produce a value to join on\n     * @param {(string|function)} rightJoinKey - Property name in the joinData to join on or a function to produce a value to join on\n     * @param {function} [mapFun=] - a function that receives each matching pair and maps them into output objects - function(left,right){return joinedObject}\n     * @param {object} [dataOptions=] - optional options to apply to data() calls for left and right sides\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} A ResultSet with data in the format [{left: leftObj, right: rightObj}]\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinKey: string | ((obj: any) => string), rightJoinKey: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * Applies a map function into a new collection for further chaining.\n     * @param {function} mapFun - javascript map function\n     * @param {object} [dataOptions=] - options to data() before input to your map function\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - Allows overriding the default or collection specified cloning method\n     * @return {ResultSet}\n     */\n    map<U extends object>(mapFun: (obj: Doc<T>, index: number, array: Doc<T>[]) => U, dataOptions?: ResultSet.DataOptions): ResultSet<U>;\n}\nexport declare namespace ResultSet {\n    interface DataOptions {\n        forceClones?: boolean;\n        forceCloneMethod?: CloneMethod;\n        removeMeta?: boolean;\n    }\n    interface SimpleSortOptions {\n        desc?: boolean;\n        sortComparator?: string;\n    }\n    type ContainsHelperType<R> = R extends string ? string | string[] : R extends any[] ? R[number] | R[number][] : R extends object ? keyof R | (keyof R)[] : never;\n    type LokiOps<R> = {\n        $eq?: R;\n    } | {\n        $ne?: R;\n    } | {\n        $gt?: R;\n    } | {\n        $gte?: R;\n    } | {\n        $lt?: R;\n    } | {\n        $lte?: R;\n    } | {\n        $between?: [R, R];\n    } | {\n        $in?: R[];\n    } | {\n        $nin?: R[];\n    } | {\n        $keyin?: object;\n    } | {\n        $nkeyin?: object;\n    } | {\n        $definedin?: object;\n    } | {\n        $undefinedin?: object;\n    } | {\n        $regex?: RegExp | string | [string, string];\n    } | {\n        $containsNone?: ContainsHelperType<R>;\n    } | {\n        $containsAny?: ContainsHelperType<R>;\n    } | {\n        $contains?: ContainsHelperType<R>;\n    } | {\n        $type?: string;\n    } | {\n        $finite?: boolean;\n    } | {\n        $size?: number;\n    } | {\n        $len?: number;\n    } | {\n        $where?: (val?: R) => boolean;\n    };\n    type Query<T> = {\n        [P in keyof T]?: LokiOps<T[P]> | T[P];\n    } & {\n        $and?: Query<T>[];\n    } & {\n        $or?: Query<T>[];\n    } & {\n        $fts?: FullTextSearchQuery;\n    };\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/loki/src/unique_index.d.ts",
    "content": "export declare class UniqueIndex {\n    private _field;\n    private _lokiMap;\n    private _valMap;\n    /**\n     * Constructs an unique index object.\n     * @param {string} propertyField - the property field to index\n     */\n    constructor(propertyField: string);\n    /**\n     * Sets a document's unique index.\n     * @param {number} id loki id to associate with value\n     * @param {*} value  value to associate with id\n     */\n    set(id: number, value: any): void;\n    /**\n     * Returns the $loki id of an unique value.\n     * @param {*} value the value to retrieve a loki id match for\n     */\n    get(value: any): number;\n    /**\n     * Updates a document's unique index.\n     * @param {number} id (loki) id of document to update the value to\n     * @param {*} value value to associate with loki id\n     */\n    update(id: number, value: any): void;\n    /**\n     * Removes an unique index.\n     * @param {number} id (loki) id to remove from index\n     */\n    remove(id: number): void;\n    /**\n     * Clears the unique index.\n     */\n    clear(): void;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/memory-storage/src/index.d.ts",
    "content": "import { MemoryStorage } from \"./memory_storage\";\nexport { MemoryStorage };\nexport default MemoryStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/memory-storage/src/memory_storage.d.ts",
    "content": "import { Dict, StorageAdapter } from \"../../common/types\";\n/**\n * An in-memory persistence adapter for an in-memory database.\n * This simple 'key/value' adapter is intended for unit testing and diagnostics.\n */\nexport declare class MemoryStorage implements StorageAdapter {\n    hashStore: Dict<{\n        savecount: number;\n        lastsave: Date;\n        value: string;\n    }>;\n    options: MemoryStorage.Options;\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} options - memory storage options\n     * @param {boolean} [options.asyncResponses=false] - whether callbacks are invoked asynchronously (default: false)\n     * @param {int} [options.asyncTimeout=50] - timeout in ms to queue callbacks (default: 50)\n     */\n    constructor(options?: MemoryStorage.Options);\n    /**\n     * Loads a serialized database from its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * Saves a serialized database to its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {string} dbstring - the database content\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a database from its in-memory store.\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport declare namespace MemoryStorage {\n    interface Options {\n        asyncResponses?: boolean;\n        asyncTimeout?: number;\n    }\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/partitioning-adapter/src/index.d.ts",
    "content": "import { PartitioningAdapter } from \"./partitioning_adapter\";\nexport { PartitioningAdapter };\nexport default PartitioningAdapter;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-de/types/partitioning-adapter/src/partitioning_adapter.d.ts",
    "content": "import { Loki } from \"../../loki/src/loki\";\nimport { StorageAdapter } from \"../../common/types\";\n/**\n * An adapter for adapters. Converts a non reference mode adapter into a reference mode adapter\n * which can perform destructuring and partitioning. Each collection will be stored in its own key/save and\n * only dirty collections will be saved. If you  turn on paging with default page size of 25megs and save\n * a 75 meg collection it should use up roughly 3 save slots (key/value pairs sent to inner adapter).\n * A dirty collection that spans three pages will save all three pages again\n * Paging mode was added mainly because Chrome has issues saving 'too large' of a string within a\n * single IndexedDB row. If a single document update causes the collection to be flagged as dirty, all\n * of that collection's pages will be written on next save.\n */\nexport declare class PartitioningAdapter implements StorageAdapter {\n    mode: string;\n    private _adapter;\n    private _dbref;\n    private _dbname;\n    private _pageIterator;\n    private _paging;\n    private _pageSize;\n    private _delimiter;\n    private _dirtyPartitions;\n    /**\n     * Registers the partitioning adapter as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the partitioning storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} adapter - reference to a 'non-reference' mode loki adapter instance.\n     * @param {boolean} paging - (default: false) set to true to enable paging collection data.\n     * @param {number} pageSize - (default : 25MB) you can use this to limit size of strings passed to inner adapter.\n     * @param {string} delimiter - allows you to override the default delimiter\n     */\n    constructor(adapter: StorageAdapter, {paging, pageSize, delimiter}?: {\n        paging?: boolean;\n        pageSize?: number;\n        delimiter?: string;\n    });\n    /**\n     * Loads a database which was partitioned into several key/value saves.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Used to sequentially load each collection partition, one at a time.\n     *\n     * @param {int} partition - ordinal collection position to load next\n     * @returns {Promise} a Promise that resolves after the next partition is loaded\n     */\n    private _loadNextPartition(partition);\n    /**\n     * Used to sequentially load the next page of collection partition, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next page is loaded\n     */\n    private _loadNextPage();\n    /**\n     * Saves a database by partioning into separate key/value saves.\n     * (Loki 'reference mode' persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {object} dbref - reference to database which we will partition and save.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     *\n     */\n    exportDatabase(dbname: string, dbref: Loki): Promise<void>;\n    /**\n     * Helper method used internally to save each dirty collection, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPartition();\n    /**\n     * Helper method used internally to generate and save the next page of the current (dirty) partition.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPage();\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/lokidb.full-text-search-language-en.js",
    "content": "(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"@lokidb/full-text-search-language\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"@lokidb/full-text-search-language-en\", [\"@lokidb/full-text-search-language\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"@lokidb/full-text-search-language-en\"] = factory(require(\"@lokidb/full-text-search-language\"));\n\telse\n\t\t{ root[\"@lokidb/full-text-search-language-en\"] = factory(root[\"@lokidb/full-text-search-language\"]); root[\"LokiFullTextSearchLanguageEn\"] = root[\"@lokidb/full-text-search-language-en\"].default; }\n})(typeof self !== 'undefined' ? self : this, function(__WEBPACK_EXTERNAL_MODULE__0__) {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// define __esModule on exports\n/******/ \t__webpack_require__.r = function(exports) {\n/******/ \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n/******/ \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n/******/ \t\t}\n/******/ \t\tObject.defineProperty(exports, '__esModule', { value: true });\n/******/ \t};\n/******/\n/******/ \t// create a fake namespace object\n/******/ \t// mode & 1: value is a module id, require it\n/******/ \t// mode & 2: merge all properties of value into the ns\n/******/ \t// mode & 4: return value when already ns object\n/******/ \t// mode & 8|1: behave like require\n/******/ \t__webpack_require__.t = function(value, mode) {\n/******/ \t\tif(mode & 1) value = __webpack_require__(value);\n/******/ \t\tif(mode & 8) return value;\n/******/ \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n/******/ \t\tvar ns = Object.create(null);\n/******/ \t\t__webpack_require__.r(ns);\n/******/ \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n/******/ \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n/******/ \t\treturn ns;\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 1);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, exports) {\n\nmodule.exports = __WEBPACK_EXTERNAL_MODULE__0__;\n\n/***/ }),\n/* 1 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n\n// EXTERNAL MODULE: external \"@lokidb/full-text-search-language\"\nvar full_text_search_language_ = __webpack_require__(0);\n\n// CONCATENATED MODULE: ./packages/full-text-search-language-en/src/english_analyzer.ts\n\nclass EnglishStemmer {\n    constructor() {\n        // Write everything in the constructor to reduce code size and increase performance.\n        // The original implementation uses a ES5 anonymous function class.\n        const step2list = {\n            \"ational\": \"ate\",\n            \"tional\": \"tion\",\n            \"enci\": \"ence\",\n            \"anci\": \"ance\",\n            \"izer\": \"ize\",\n            \"bli\": \"ble\",\n            \"alli\": \"al\",\n            \"entli\": \"ent\",\n            \"eli\": \"e\",\n            \"ousli\": \"ous\",\n            \"ization\": \"ize\",\n            \"ation\": \"ate\",\n            \"ator\": \"ate\",\n            \"alism\": \"al\",\n            \"iveness\": \"ive\",\n            \"fulness\": \"ful\",\n            \"ousness\": \"ous\",\n            \"aliti\": \"al\",\n            \"iviti\": \"ive\",\n            \"biliti\": \"ble\",\n            \"logi\": \"log\"\n        };\n        const step3list = {\n            \"icate\": \"ic\",\n            \"ative\": \"\",\n            \"alize\": \"al\",\n            \"iciti\": \"ic\",\n            \"ical\": \"ic\",\n            \"ful\": \"\",\n            \"ness\": \"\"\n        };\n        const c = \"[^aeiou]\"; // consonant\n        const v = \"[aeiouy]\"; // vowel\n        const C = c + \"[^aeiouy]*\"; // consonant sequence\n        const V = v + \"[aeiou]*\"; // vowel sequence\n        const mgr0 = \"^(\" + C + \")?\" + V + C; // [C]VC... is m>0\n        const meq1 = \"^(\" + C + \")?\" + V + C + \"(\" + V + \")?$\"; // [C]VC[V] is m=1\n        const mgr1 = \"^(\" + C + \")?\" + V + C + V + C; // [C]VCVC... is m>1\n        const s_v = \"^(\" + C + \")?\" + v; // vowel in stem\n        const re_mgr0 = new RegExp(mgr0);\n        const re_mgr1 = new RegExp(mgr1);\n        const re_meq1 = new RegExp(meq1);\n        const re_s_v = new RegExp(s_v);\n        const re_1a = /^(.+?)(ss|i)es$/;\n        const re2_1a = /^(.+?)([^s])s$/;\n        const re_1b = /^(.+?)eed$/;\n        const re2_1b = /^(.+?)(ed|ing)$/;\n        const re_1b_2 = /.$/;\n        const re2_1b_2 = /(at|bl|iz)$/;\n        const re3_1b_2 = new RegExp(\"([^aeiouylsz])\\\\1$\");\n        const re4_1b_2 = new RegExp(`^${C}${v}[^aeiouwxy]$`);\n        const re_1c = /^(.+?[^aeiou])y$/;\n        const re_2 = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;\n        const re_3 = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;\n        const re_4 = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;\n        const re2_4 = /^(.+?)([st])(ion)$/;\n        const re_5 = /^(.+?)e$/;\n        const re_5_1 = /ll$/;\n        const re3_5 = new RegExp(\"^\" + C + v + \"[^aeiouwxy]$\");\n        this.porterStemmer = (w) => {\n            let stem;\n            let suffix;\n            let firstch;\n            let re;\n            let re2;\n            let re3;\n            let re4;\n            if (w.length < 3) {\n                return w;\n            }\n            firstch = w.substr(0, 1);\n            if (firstch === \"y\") {\n                w = firstch.toUpperCase() + w.substr(1);\n            }\n            // Step 1a\n            re = re_1a;\n            re2 = re2_1a;\n            if (re.test(w)) {\n                w = w.replace(re, \"$1$2\");\n            }\n            else if (re2.test(w)) {\n                w = w.replace(re2, \"$1$2\");\n            }\n            // Step 1b\n            re = re_1b;\n            re2 = re2_1b;\n            if (re.test(w)) {\n                const fp = re.exec(w);\n                re = re_mgr0;\n                if (re.test(fp[1])) {\n                    re = re_1b_2;\n                    w = w.replace(re, \"\");\n                }\n            }\n            else if (re2.test(w)) {\n                const fp = re2.exec(w);\n                stem = fp[1];\n                re2 = re_s_v;\n                if (re2.test(stem)) {\n                    w = stem;\n                    re2 = re2_1b_2;\n                    re3 = re3_1b_2;\n                    re4 = re4_1b_2;\n                    if (re2.test(w)) {\n                        w = w + \"e\";\n                    }\n                    else if (re3.test(w)) {\n                        re = re_1b_2;\n                        w = w.replace(re, \"\");\n                    }\n                    else if (re4.test(w)) {\n                        w = w + \"e\";\n                    }\n                }\n            }\n            // Step 1c - replace suffix y or Y by i if preceded by a non-vowel which is not the first letter of the word (so cry -> cri, by -> by, say -> say)\n            re = re_1c;\n            if (re.test(w)) {\n                const fp = re.exec(w);\n                stem = fp[1];\n                w = stem + \"i\";\n            }\n            // Step 2\n            re = re_2;\n            if (re.test(w)) {\n                const fp = re.exec(w);\n                stem = fp[1];\n                suffix = fp[2];\n                re = re_mgr0;\n                if (re.test(stem)) {\n                    w = stem + step2list[suffix];\n                }\n            }\n            // Step 3\n            re = re_3;\n            if (re.test(w)) {\n                const fp = re.exec(w);\n                stem = fp[1];\n                suffix = fp[2];\n                re = re_mgr0;\n                if (re.test(stem)) {\n                    w = stem + step3list[suffix];\n                }\n            }\n            // Step 4\n            re = re_4;\n            re2 = re2_4;\n            if (re.test(w)) {\n                const fp = re.exec(w);\n                stem = fp[1];\n                re = re_mgr1;\n                if (re.test(stem)) {\n                    w = stem;\n                }\n            }\n            else if (re2.test(w)) {\n                const fp = re2.exec(w);\n                stem = fp[1] + fp[2];\n                re2 = re_mgr1;\n                if (re2.test(stem)) {\n                    w = stem;\n                }\n            }\n            // Step 5\n            re = re_5;\n            if (re.test(w)) {\n                const fp = re.exec(w);\n                stem = fp[1];\n                re = re_mgr1;\n                re2 = re_meq1;\n                re3 = re3_5;\n                if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) {\n                    w = stem;\n                }\n            }\n            re = re_5_1;\n            re2 = re_mgr1;\n            if (re.test(w) && re2.test(w)) {\n                re = re_1b_2;\n                w = w.replace(re, \"\");\n            }\n            // and turn initial Y back to y\n            if (firstch === \"y\") {\n                w = firstch.toLowerCase() + w.substr(1);\n            }\n            return w;\n        };\n    }\n}\n// Split at whitespace and dashes.\nfunction splitter(str) {\n    let trimmedTokens = [];\n    let tokens = str.split(/[\\s-]+/);\n    for (let i = 0; i < tokens.length; i++) {\n        if (tokens[i] !== \"\") {\n            trimmedTokens.push(tokens[i].toLowerCase());\n        }\n    }\n    return trimmedTokens;\n}\nconst st = new EnglishStemmer();\nfunction stemmer(token) {\n    return st.porterStemmer(token);\n}\nconst trimmer = Object(full_text_search_language_[\"generateTrimmer\"])(\"A-Za-z\\xAA\\xBA\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\u02B8\\u02E0-\\u02E4\\u1D00-\\u1D25\\u1D2C-\\u1D5C\\u1D62-\\u1D65\\u1D6B-\\u1D77\\u1D79-\\u1DBE\\u1E00-\\u1EFF\\u2071\\u207F\\u2090-\\u209C\\u212A\\u212B\\u2132\\u214E\\u2160-\\u2188\\u2C60-\\u2C7F\\uA722-\\uA787\\uA78B-\\uA7AD\\uA7B0-\\uA7B7\\uA7F7-\\uA7FF\\uAB30-\\uAB5A\\uAB5C-\\uAB64\\uFB00-\\uFB06\\uFF21-\\uFF3A\\uFF41-\\uFF5A\");\nconst stopWordFilter = Object(full_text_search_language_[\"generateStopWordFilter\"])([\"a\", \"able\", \"about\", \"across\", \"after\", \"all\", \"almost\", \"also\", \"am\", \"among\", \"an\", \"and\", \"any\", \"are\", \"as\", \"at\", \"be\", \"because\", \"been\", \"but\", \"by\", \"can\", \"cannot\", \"could\", \"dear\", \"did\", \"do\", \"does\", \"either\", \"else\", \"ever\", \"every\", \"for\", \"from\", \"get\", \"got\", \"had\", \"has\", \"have\", \"he\", \"her\", \"hers\", \"him\", \"his\", \"how\", \"however\", \"i\", \"if\", \"in\", \"into\", \"is\", \"it\", \"its\", \"just\", \"least\", \"let\", \"like\", \"likely\", \"may\", \"me\", \"might\", \"most\", \"must\", \"my\", \"neither\", \"no\", \"nor\", \"not\", \"of\", \"off\", \"often\", \"on\", \"only\", \"or\", \"other\", \"our\", \"own\", \"rather\", \"said\", \"say\", \"says\", \"she\", \"should\", \"since\", \"so\", \"some\", \"than\", \"that\", \"the\", \"their\", \"them\", \"then\", \"there\", \"these\", \"they\", \"this\", \"tis\", \"to\", \"too\", \"twas\", \"us\", \"wants\", \"was\", \"we\", \"were\", \"what\", \"when\", \"where\", \"which\", \"while\", \"who\", \"whom\", \"why\", \"will\", \"with\", \"would\", \"yet\", \"you\", \"your\"]);\n// Export the analyzer.\nclass EnglishAnalyzer {\n    constructor() {\n        this.tokenizer = splitter;\n        this.token_filter = [trimmer, stemmer, stopWordFilter];\n    }\n}\n\n// CONCATENATED MODULE: ./packages/full-text-search-language-en/src/index.ts\n/* concated harmony reexport */__webpack_require__.d(__webpack_exports__, \"EnglishAnalyzer\", function() { return EnglishAnalyzer; });\n\n\n/* harmony default export */ var src = __webpack_exports__[\"default\"] = (EnglishAnalyzer);\n\n\n/***/ })\n/******/ ]);\n});\n//# sourceMappingURL=lokidb.full-text-search-language-en.js.map"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/common/plugin.d.ts",
    "content": "/**\n * @hidden\n */\nexport declare const PLUGINS: void;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/common/types.d.ts",
    "content": "/**\n * @hidden\n */\nimport { Loki } from \"../loki/src/loki\";\nexport interface StorageAdapter {\n    loadDatabase(dbname: string): Promise<any>;\n    saveDatabase?(dbname: string, serialization: string): Promise<void>;\n    deleteDatabase?(dbname: string): Promise<void>;\n    mode?: string;\n    exportDatabase?(dbname: string, dbref: Loki): Promise<void>;\n}\nexport declare type Doc<T extends object = object> = T & {\n    $loki: number;\n    meta?: {\n        created: number;\n        revision: number;\n        version: number;\n        updated?: number;\n    };\n};\nexport interface Dict<T> {\n    [index: string]: T;\n    [index: number]: T;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/fs-storage/src/fs_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists using node fs module.\n */\nexport declare class FSStorage implements StorageAdapter {\n    /**\n     * Registers the fs storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the fs storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * Load data from file, will throw an error if the file does not exist\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Save data to file, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Delete the database file, will throw an error if the\n     * file can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/fs-storage/src/index.d.ts",
    "content": "import { FSStorage } from \"./fs_storage\";\nexport { FSStorage };\nexport default FSStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search/src/analyzer/analyzer.d.ts",
    "content": "import { CharacterFilter } from \"./character_filter\";\nimport { Tokenizer, whitespaceTokenizer } from \"./tokenizer\";\nimport { lowercaseTokenFilter, TokenFilter } from \"./token_filter\";\n/**\n * A analyzer converts a string into tokens which are added to the inverted index for searching.\n */\nexport interface Analyzer {\n    /**\n     * The character filters of the analyzer.\n     */\n    char_filter?: CharacterFilter[];\n    /**\n     * The tokenizer of the analyzer.\n     */\n    tokenizer: Tokenizer;\n    /**\n     * The token filters of the analyzer.\n     */\n    token_filter?: TokenFilter[];\n}\n/**\n * Analyzes a given string.\n * @param {Analyzer} analyzer - the analyzer\n * @param {string} str - the string\n * @returns {string[]} - the tokens\n */\nexport declare function analyze(analyzer: Analyzer, str: string): string[];\n/**\n * An analyzer with the whitespace tokenizer and the lowercase token filter.\n */\nexport declare class StandardAnalyzer implements Analyzer {\n    tokenizer: typeof whitespaceTokenizer;\n    token_filter: (typeof lowercaseTokenFilter)[];\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search/src/analyzer/character_filter.d.ts",
    "content": "/**\n * A character filter is used to preprocess a string before it is passed to a tokenizer.\n */\nexport declare type CharacterFilter = (value: string) => string;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search/src/analyzer/token_filter.d.ts",
    "content": "/**\n * A token filter takes tokens from a tokenizer and modify, delete or add tokens.\n */\nexport declare type TokenFilter = (value: string, index: number, array: string[]) => string;\n/**\n * Converts a token to lowercase.\n * @param {string} token - the token\n * @returns {string} - the lowercased token\n */\nexport declare function lowercaseTokenFilter(token: string): string;\n/**\n * Converts a token to uppercase.\n * @param {string} token - the token\n * @returns {string} - the uppercased token\n */\nexport declare function uppercaseTokenFilter(token: string): string;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search/src/analyzer/tokenizer.d.ts",
    "content": "/**\n * A tokenizer splits a string into individual tokens.\n */\nexport declare type Tokenizer = (value: string) => string[];\n/**\n * Splits a string at whitespace characters into tokens.\n * @param {string} value - the string\n * @returns {string[]} - the tokens\n */\nexport declare function whitespaceTokenizer(value: string): string[];\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search/src/full_text_search.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\nimport { Scorer } from \"./scorer\";\nimport { Analyzer } from \"./analyzer/analyzer\";\nexport declare class FullTextSearch {\n    private _id;\n    private _docs;\n    private _idxSearcher;\n    private _invIdxs;\n    /**\n     * Registers the full-text search as plugin.\n     */\n    static register(): void;\n    /**\n     * Initialize the full-text search for the given fields.\n     * @param {object[]} fieldOptions - the field options\n     * @param {string} fieldOptions.field - the name of the property field\n     * @param {boolean=true} fieldOptions.store - flag to indicate if the full-text search should be stored on serialization or\n     *  rebuild on deserialization\n     * @param {boolean=true} fieldOptions.optimizeChanges - flag to optimize updating and deleting of documents\n     *    (requires more memory but performs faster)\n     * @param {Analyzer} fieldOptions.analyzer - an analyzer for the field\n     * @param {string} [id] - the property name of the document index\n     */\n    constructor(fieldOptions?: FullTextSearch.FieldOptions[], id?: string);\n    addDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    removeDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    updateDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    clear(): void;\n    search(query: Query): Scorer.ScoreResults;\n    toJSON(): FullTextSearch.Serialization;\n    static fromJSONObject(serialized: FullTextSearch.Serialization, analyzers?: Dict<Analyzer>): FullTextSearch;\n}\nexport declare namespace FullTextSearch {\n    interface FieldOptions extends InvertedIndex.FieldOptions {\n        field: string;\n    }\n    interface Serialization {\n        id: string;\n        ii: Dict<InvertedIndex.Serialization>;\n    }\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search/src/fuzzy/automaton.d.ts",
    "content": "/**\n * Transition with dest, min and max.\n * @hidden\n */\nexport declare type Transition = [number, number, number];\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MIN_CODE_POINT = 0;\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MAX_CODE_POINT = 1114111;\n/**\n * From org/apache/lucene/util/automaton/Automaton.java\n * @hidden\n */\nexport declare class Automaton {\n    private _stateTransitions;\n    private _accept;\n    private _nextState;\n    private _currState;\n    private _transitions;\n    constructor();\n    isAccept(n: number): boolean;\n    createState(): number;\n    setAccept(state: number, accept: boolean): void;\n    finishState(): void;\n    private _finishCurrentState();\n    getStartPoints(): number[];\n    step(state: number, label: number): number;\n    getNumStates(): number;\n    addTransition(source: number, dest: number, min: number, max: number): void;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search/src/fuzzy/lev1t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev1TParametricDescription.java\n * @hidden\n */\nexport declare class Lev1TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search/src/fuzzy/lev2t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev2TParametricDescription.java\n * @hidden\n */\nexport declare class Lev2TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search/src/fuzzy/levenshtein_automata.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java\n * @hidden\n */\nexport declare class LevenshteinAutomata {\n    private _word;\n    private _numRanges;\n    private _rangeLower;\n    private _rangeUpper;\n    private _description;\n    private _alphabet;\n    private _editDistance;\n    constructor(input: number[], editDistance: number);\n    /**\n     * Transforms the NDFA to a DFA.\n     * @returns {Automaton}\n     */\n    toAutomaton(): Automaton;\n    private _getVector(x, pos, end);\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search/src/fuzzy/long.d.ts",
    "content": "/**\n * Class supports 64Bit integer operations.\n * A cut-down version of dcodeIO/long.js.\n * @hidden\n */\nexport declare class Long {\n    private _low;\n    private _high;\n    constructor(low?: number, high?: number);\n    /**\n     * Returns this long with bits arithmetically shifted to the right by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftRight(numBits: number): Long;\n    /**\n     * Returns this long with bits arithmetically shifted to the left by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftLeft(numBits: number): Long;\n    /**\n     * Returns the bitwise AND of this Long and the specified.\n     * @param {Long} other - the other Long\n     * @returns {Long} the long\n     */\n    and(other: Long): Long;\n    /**\n     * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.\n     * @returns {number}\n     */\n    toInt(): number;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search/src/fuzzy/parametric_description.d.ts",
    "content": "import { Long } from \"./long\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java#ParametricDescription\n * @hidden\n */\nexport declare class ParametricDescription {\n    protected _w: number;\n    private _n;\n    private _minErrors;\n    constructor(w: number, n: number, minErrors: number[]);\n    /**\n     * Return the number of states needed to compute a Levenshtein DFA\n     */\n    size(): number;\n    /**\n     * Returns true if the <code>state</code> in any Levenshtein DFA is an accept state (final state).\n     */\n    isAccept(absState: number): boolean;\n    /**\n     * Returns the position in the input word for a given <code>state</code>.\n     * This is the minimal boundary for the state.\n     */\n    getPosition(absState: number): number;\n    static unpack(data: Long[], index: number, bitsPerValue: number): number;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search/src/fuzzy/run_automaton.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/RunAutomaton.java\n * @hidden\n */\nexport declare class RunAutomaton {\n    private _points;\n    private _accept;\n    private _transitions;\n    private _classmap;\n    constructor(automaton: Automaton);\n    getCharClass(c: number): number;\n    step(state: number, c: number): number;\n    isAccept(state: number): boolean;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search/src/index.d.ts",
    "content": "import { FullTextSearch } from \"./full_text_search\";\nimport { analyze, StandardAnalyzer } from \"./analyzer/analyzer\";\nimport { whitespaceTokenizer } from \"./analyzer/tokenizer\";\nimport { lowercaseTokenFilter, uppercaseTokenFilter } from \"./analyzer/token_filter\";\nexport { FullTextSearch, analyze, StandardAnalyzer, whitespaceTokenizer, lowercaseTokenFilter, uppercaseTokenFilter };\nexport default FullTextSearch;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search/src/index_searcher.d.ts",
    "content": "import { Scorer } from \"./scorer\";\nimport { InvertedIndex } from \"./inverted_index\";\nimport { Query } from \"./query_types\";\nimport { Dict } from \"../../common/types\";\n/**\n * @hidden\n */\nexport declare class IndexSearcher {\n    private _invIdxs;\n    private _docs;\n    private _scorer;\n    /**\n     * Constructs an index searcher.\n     * @param {Dict<InvertedIndex>} invIdxs - the inverted indexes\n     * @param {Set<number>} docs - the ids of the documents\n     */\n    constructor(invIdxs: Dict<InvertedIndex>, docs: Set<InvertedIndex.DocumentIndex>);\n    search(query: Query): Scorer.ScoreResults;\n    setDirty(): void;\n    private _recursive(query, doScoring);\n    private _getUnique(queries, doScoring, queryResults);\n    private _getAll(queries, doScoring, queryResults?);\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search/src/inverted_index.d.ts",
    "content": "import { Analyzer } from \"./analyzer/analyzer\";\n/**\n * Converts a string into an array of code points.\n * @param str - the string\n * @returns {number[]} to code points\n * @hidden\n */\nexport declare function toCodePoints(str: string): number[];\n/**\n * Inverted index class handles featured text search for specific document fields.\n * @hidden\n */\nexport declare class InvertedIndex {\n    analyzer: Analyzer;\n    docCount: number;\n    docStore: Map<InvertedIndex.DocumentIndex, InvertedIndex.DocStore>;\n    totalFieldLength: number;\n    root: InvertedIndex.Index;\n    private _store;\n    private _optimizeChanges;\n    /**\n     * @param {boolean} [options.store=true] - inverted index will be stored at serialization rather than rebuilt on load\n     * @param {boolean} [options.optimizeChanges=true] - flag to store additional metadata inside the index for better\n     *  performance if an existing field is updated or removed\n     * @param {Analyzer} [options.analyzer=] - the analyzer of this inverted index\n     */\n    constructor(options?: InvertedIndex.FieldOptions);\n    /**\n     * Adds defined fields of a document to the inverted index.\n     * @param {string} field - the field to add\n     * @param {number} docId - the doc id of the field\n     */\n    insert(field: string, docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Removes all relevant terms of a document from the inverted index.\n     * @param {number} docId - the document.\n     */\n    remove(docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Gets the term index of a term.\n     * @param {string} term - the term\n     * @param {object} root - the term index to start from\n     * @param {number} start - the position of the term string to start from\n     * @return {object} - The term index or null if the term is not in the term tree.\n     */\n    static getTermIndex(term: number[], root: InvertedIndex.Index, start?: number): InvertedIndex.Index;\n    /**\n     * Extends a term index to all available term leafs.\n     * @param {object} idx - the term index to start from\n     * @param {number[]} [term=[]] - the current term\n     * @param {Array} termIndices - all extended indices with their term\n     * @returns {Array} - Array with term indices and extension\n     */\n    static extendTermIndex(idx: InvertedIndex.Index, term?: number[], termIndices?: InvertedIndex.IndexTerm[]): InvertedIndex.IndexTerm[];\n    /**\n     * Serialize the inverted index.\n     * @returns {{docStore: *, _fields: *, index: *}}\n     */\n    toJSON(): InvertedIndex.Serialization;\n    /**\n     * Deserialize the inverted index.\n     * @param {{docStore: *, _fields: *, index: *}} serialized - The serialized inverted index.\n     * @param {Analyzer} analyzer[undefined] - an analyzer\n     */\n    static fromJSONObject(serialized: InvertedIndex.Serialization, analyzer?: Analyzer): InvertedIndex;\n    private static _serializeIndex(idx);\n    private static _deserializeIndex(serialized);\n    /**\n     * Set parent of to each index and regenerate the indexRef.\n     * @param {Index} index - the index\n     * @param {Index} parent - the parent\n     */\n    private _regenerate(index, parent);\n    /**\n     * Iterate over the whole inverted index and remove the document.\n     * Delete branch if not needed anymore.\n     * Function is needed if index is used without optimization.\n     * @param {Index} idx - the index\n     * @param {number} docId - the doc id\n     * @returns {boolean} true if index is empty\n     */\n    private _remove(idx, docId);\n}\nexport declare namespace InvertedIndex {\n    interface FieldOptions {\n        store?: boolean;\n        optimizeChanges?: boolean;\n        analyzer?: Analyzer;\n    }\n    type Index = Map<number, any> & {\n        dc?: Map<DocumentIndex, number>;\n        df?: number;\n        pa?: Index;\n    };\n    type IndexTerm = {\n        index: Index;\n        term: number[];\n    };\n    interface SerializedIndex {\n        d?: {\n            df: number;\n            dc: [DocumentIndex, number][];\n        };\n        k?: number[];\n        v?: SerializedIndex[];\n    }\n    type Serialization = SpareSerialization | FullSerialization;\n    type SpareSerialization = {\n        _store: false;\n        _optimizeChanges: boolean;\n    };\n    type FullSerialization = {\n        _store: true;\n        _optimizeChanges: boolean;\n        docCount: number;\n        docStore: [DocumentIndex, DocStore][];\n        totalFieldLength: number;\n        root: SerializedIndex;\n    };\n    interface DocStore {\n        fieldLength?: number;\n        indexRef?: Index[];\n    }\n    type DocumentIndex = number | string;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search/src/query_types.d.ts",
    "content": "/**\n * Base query to enable boost to a query type.\n */\nexport interface BaseQuery<Type> {\n    type: Type;\n    boost?: number;\n}\n/**\n * A query which finds documents where a document field contains a term.\n */\nexport interface TermQuery extends BaseQuery<\"term\"> {\n    field: string;\n    value: string;\n}\n/**\n * A query which finds documents where a document field contains any of the terms.\n */\nexport interface TermsQuery extends BaseQuery<\"terms\"> {\n    field: string;\n    value: string[];\n}\n/**\n * A query which finds documents where the wildcard term can be applied at an existing document field term.\n */\nexport interface WildcardQuery extends BaseQuery<\"wildcard\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which finds documents where the fuzzy term can be transformed into an existing document field term within a\n * given edit distance.\n */\nexport interface FuzzyQuery extends BaseQuery<\"fuzzy\"> {\n    field: string;\n    value: string;\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query which matches documents containing the prefix of a term inside a field.\n */\nexport interface PrefixQuery extends BaseQuery<\"prefix\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which matches all documents with a given field.\n */\nexport interface ExistsQuery extends BaseQuery<\"exists\"> {\n    field: string;\n}\n/**\n * A query which tokenizes the given text into tokens and performs a sub query for each token. The results are combined\n * using a boolean operator.\n */\nexport interface MatchQuery extends BaseQuery<\"match\"> {\n    field: string;\n    value: string;\n    minimum_should_match?: number | string;\n    operator?: \"and\" | \"or\";\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query that matches all documents and giving them a constant score equal to the query boost.\n*/\nexport interface MatchQueryAll extends BaseQuery<\"match_all\"> {\n}\n/**\n * A query that wraps sub queries and returns a constant score equal to the query boost for every document in the filter.\n */\nexport interface ConstantScoreQuery extends BaseQuery<\"constant_score\"> {\n    filter: QueryTypes[];\n}\n/**\n * A query that matches documents matching boolean combinations of sub queries.\n */\nexport interface BoolQuery extends BaseQuery<\"bool\"> {\n    must?: QueryTypes[];\n    filter?: QueryTypes[];\n    should?: QueryTypes[];\n    not?: QueryTypes[];\n    minimum_should_match?: number | string;\n}\n/**\n * Union type of possible query types.\n */\nexport declare type QueryTypes = BoolQuery | ConstantScoreQuery | TermQuery | TermsQuery | WildcardQuery | FuzzyQuery | MatchQuery | MatchQueryAll | PrefixQuery | ExistsQuery;\n/**\n * The main query with the actually full-text search query and the scoring parameters.\n */\nexport interface Query {\n    query: QueryTypes;\n    calculate_scoring?: boolean;\n    explain?: boolean;\n    bm25?: {\n        k1: number;\n        b: number;\n    };\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search/src/scorer.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\n/**\n * @hidden\n */\nexport declare class Scorer {\n    private _invIdxs;\n    private _cache;\n    constructor(invIdxs: Dict<InvertedIndex>);\n    setDirty(): void;\n    score(fieldName: string, boost: number, termIdx: InvertedIndex.Index, doScoring: boolean | null, queryResults: Scorer.QueryResults, term: number[], df?: number): void;\n    scoreConstant(boost: number, docId: InvertedIndex.DocumentIndex, queryResults: Scorer.QueryResults): Scorer.QueryResults;\n    finalScore(query: Query, queryResults: Scorer.QueryResults): Scorer.ScoreResults;\n    private static _calculateFieldLength(fieldLength);\n    private _getCache(fieldName);\n    /**\n     * Returns the idf by either calculate it or use a cached one.\n     * @param {string} fieldName - the name of the field\n     * @param {number} docFreq - the doc frequency of the term\n     * @returns {number} the idf\n     * @private\n     */\n    private _idf(fieldName, docFreq);\n    private _avgFieldLength(fieldName);\n}\nexport declare namespace Scorer {\n    interface IDFCache {\n        idfs: Dict<number>;\n        avgFieldLength: number;\n    }\n    interface QueryResult {\n        tf?: number;\n        idf?: number;\n        boost: number;\n        fieldName?: string;\n        term?: number[];\n    }\n    type QueryResults = Map<InvertedIndex.DocumentIndex, QueryResult[]>;\n    interface BM25Explanation {\n        boost: number;\n        score: number;\n        docID: number;\n        fieldName: string;\n        index: string;\n        idf: number;\n        tfNorm: number;\n        tf: number;\n        fieldLength: number;\n        avgFieldLength: number;\n    }\n    interface ConstantExplanation {\n        boost: number;\n        score: number;\n    }\n    type ScoreExplanation = BM25Explanation | ConstantExplanation;\n    type ScoreResult = {\n        score: number;\n        explanation?: ScoreExplanation[];\n    };\n    type ScoreResults = Dict<ScoreResult>;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search-language/src/index.d.ts",
    "content": "export { generateStopWordFilter, generateTrimmer, Among, SnowballProgram } from \"./language\";\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search-language/src/language.d.ts",
    "content": "export declare function generateTrimmer(wordCharacters: string): (token: string) => string;\nexport declare function generateStopWordFilter(stopWords: string[]): (token: string) => string;\nexport declare class Among {\n    s_size: number;\n    s: number[];\n    substring_i: number;\n    result: number;\n    method: any;\n    constructor(s: string, substring_i: number, result: number, method?: any);\n}\nexport declare class SnowballProgram {\n    current: string;\n    bra: number;\n    ket: number;\n    limit: number;\n    cursor: number;\n    limit_backward: number;\n    constructor();\n    setCurrent(word: string): void;\n    getCurrent(): string;\n    in_grouping(s: number[], min: number, max: number): boolean;\n    in_grouping_b(s: number[], min: number, max: number): boolean;\n    out_grouping(s: number[], min: number, max: number): boolean;\n    out_grouping_b(s: number[], min: number, max: number): boolean;\n    eq_s(s_size: number, s: string): boolean;\n    eq_s_b(s_size: number, s: string): boolean;\n    find_among(v: Among[], v_size: number): number;\n    find_among_b(v: Among[], v_size: number): number;\n    replace_s(c_bra: number, c_ket: number, s: string): number;\n    slice_check(): void;\n    slice_from(s: string): void;\n    slice_del(): void;\n    insert(c_bra: number, c_ket: number, s: string): void;\n    slice_to(): string;\n    eq_v_b(s: string): boolean;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search-language-de/src/german_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class GermanAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search-language-de/src/index.d.ts",
    "content": "import { GermanAnalyzer } from \"./german_analyzer\";\nexport { GermanAnalyzer };\nexport default GermanAnalyzer;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search-language-en/src/english_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class EnglishAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/full-text-search-language-en/src/index.d.ts",
    "content": "import { EnglishAnalyzer } from \"./english_analyzer\";\nexport { EnglishAnalyzer };\nexport default EnglishAnalyzer;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/indexed-storage/src/index.d.ts",
    "content": "import { IndexedStorage } from \"./indexed_storage\";\nexport { IndexedStorage };\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/indexed-storage/src/indexed_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * Loki persistence adapter class for indexedDb.\n *     This class fulfills abstract adapter interface which can be applied to other storage methods.\n *     Utilizes the included LokiCatalog app/key/value database for actual database persistence.\n *     IndexedDb storage is provided per-domain, so we implement app/key/value database to\n *     allow separate contexts for separate apps within a domain.\n */\nexport declare class IndexedStorage implements StorageAdapter {\n    private _appname;\n    private catalog;\n    /**\n     * Registers the indexed storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the indexed storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {string} [appname=loki] - Application name context can be used to distinguish subdomains, \"loki\" by default\n     */\n    constructor(appname?: string);\n    /**\n     * Retrieves a serialized db string from the catalog.\n     *\n     * @example\n     * // LOAD\n     * var idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * var db = new loki(\"test\", { adapter: idbAdapter });\n     *   db.base(function(result) {\n       *   console.log(\"done\");\n       * });\n     *\n     * @param {string} dbname - the name of the database to retrieve.\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<{}>;\n    /**\n     * Saves a serialized db to the catalog.\n     *\n     * @example\n     * // SAVE : will save App/Key/Val as \"finance\"/\"test\"/{serializedDb}\n     * let idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * let db = new loki(\"test\", { adapter: idbAdapter });\n     * let coll = db.addCollection(\"testColl\");\n     * coll.insert({test: \"val\"});\n     * db.saveDatabase();  // could pass callback if needed for async complete\n     *\n     * @param {string} dbname - the name to give the serialized database within the catalog.\n     * @param {string} dbstring - the serialized db string to save.\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a serialized db from the catalog.\n     *\n     * @example\n     * // DELETE DATABASE\n     * // delete \"finance\"/\"test\" value from catalog\n     * idbAdapter.deleteDatabase(\"test\", function {\n       *   // database deleted\n       * });\n     *\n     * @param {string} dbname - the name of the database to delete from the catalog.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n    /**\n     * Removes all database partitions and pages with the base filename passed in.\n     * This utility method does not (yet) guarantee async deletions will be completed before returning\n     *\n     * @param {string} dbname - the base filename which container, partitions, or pages are derived\n     */\n    deleteDatabasePartitions(dbname: string): void;\n    /**\n     * Retrieves object array of catalog entries for current app.\n     *\n     * @example\n     * idbAdapter.getDatabaseList(function(result) {\n       *   // result is array of string names for that appcontext (\"finance\")\n       *   result.forEach(function(str) {\n       *     console.log(str);\n       *   });\n       * });\n     *\n     * @param {function} callback - should accept array of database names in the catalog for current app.\n     */\n    getDatabaseList(callback: (names: string[]) => void): void;\n    /**\n     * Allows retrieval of list of all keys in catalog along with size\n     * @param {function} callback - (Optional) callback to accept result array.\n     */\n    getCatalogSummary(callback: (entry: Entry[]) => void): void;\n}\nexport interface Entry {\n    app: string;\n    key: string;\n    size: number;\n}\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/local-storage/src/index.d.ts",
    "content": "import { LocalStorage } from \"./local_storage\";\nexport { LocalStorage };\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/local-storage/src/local_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists to web browser's local storage object\n * @constructor LocalStorageAdapter\n */\nexport declare class LocalStorage implements StorageAdapter {\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * loadDatabase() - Load data from localstorage\n     * @param {string} dbname - the name of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * saveDatabase() - save data to localstorage, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was saved\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * deleteDatabase() - delete the database from localstorage, will throw an error if it\n     * can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/loki/src/avl_index.d.ts",
    "content": "import { IRangedIndex, IRangedIndexRequest } from \"./ranged_indexes\";\nimport { ILokiComparer } from \"./comparators\";\n/**\n * Treenode type for binary search tree (BST) implementation.\n *\n * To support duplicates, we may need to either repurpose parent to\n * point to 'elder' sibling or add a siblingId to point to owner of\n * node represented in tree.\n */\nexport declare type TreeNode<T> = {\n    id: number;\n    value: T;\n    parent: number | null;\n    balance: number;\n    height: number;\n    left: number | null;\n    right: number | null;\n    siblings: number[];\n};\nexport interface ITreeNodeHash<T> {\n    [id: number]: TreeNode<T>;\n}\n/**\n * LokiDB AVL Balanced Binary Tree Index implementation.\n * To support duplicates, we use siblings (array) in tree nodes.\n * Basic AVL components guided by William Fiset tutorials at :\n * https://github.com/williamfiset/data-structures/blob/master/com/williamfiset/datastructures/balancedtree/AVLTreeRecursive.java\n * https://www.youtube.com/watch?v=g4y2h70D6Nk&list=PLDV1Zeh2NRsD06x59fxczdWLhDDszUHKt\n */\nexport declare class AvlTreeIndex<T> implements IRangedIndex<T> {\n    name: string;\n    comparator: ILokiComparer<T>;\n    nodes: ITreeNodeHash<T>;\n    apex: number | null;\n    /**\n     * Initializes index with property name and a comparer function.\n     */\n    constructor(name: string, comparator: ILokiComparer<T>);\n    backup(): AvlTreeIndex<T>;\n    restore(tree: AvlTreeIndex<T>): void;\n    /**\n     * Used for inserting a new value into the BinaryTreeIndex\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val Value to be indexed and inserted into binary tree\n     */\n    insert(id: number, val: T): void;\n    /**\n     * Recursively inserts a treenode and re-balances if needed.\n     * @param current\n     * @param node\n     */\n    insertNode(current: TreeNode<T>, node: TreeNode<T>): number;\n    /**\n     * Updates height and balance (calculation) for tree node\n     * @param node\n     */\n    private updateBalance(node);\n    /**\n     * Balance the 'double left-heavy' condition\n     * @param node\n     */\n    private leftLeftCase(node);\n    /**\n     * Balance the '(parent) left heavy, (child) right heavy' condition\n     * @param node\n     */\n    private leftRightCase(node);\n    /**\n     * Balance the 'double right-heavy' condition\n     * @param node\n     */\n    private rightRightCase(node);\n    /**\n     * Balance the '(parent) right heavy, (child) left heavy' condition\n     * @param node\n     */\n    private rightLeftCase(node);\n    /**\n     * Left rotation of node. Swaps right child into current location.\n     * @param node\n     */\n    private rotateLeft(node);\n    /**\n     * Right rotation of node. Swaps left child into current location.\n     * @param node\n     */\n    private rotateRight(node);\n    /**\n     * Diagnostic method for examining tree contents and structure\n     * @param node\n     */\n    getValuesAsTree(node?: TreeNode<T>): any;\n    /**\n     * Updates a value, possibly relocating it, within binary tree\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val New value to be indexed within binary tree\n     */\n    update(id: number, val: T): void;\n    /**\n     * Removes a value from the binary tree index\n     * @param id\n     */\n    remove(id: number): void;\n    /**\n     * Recursive node removal and rebalancer\n     * @param node\n     * @param val\n     */\n    private removeNode(node, id);\n    /**\n     * Utility method for updating a parent's child link when it changes\n     * @param parentId\n     * @param oldChildId\n     * @param newChildId\n     */\n    private updateChildLink(parentId, oldChildId, newChildId);\n    /**\n     * When removing a parent with only child, this does simple remap of child to grandParent.\n     * @param grandParent New parent of 'child'.\n     * @param parent Node being removed.\n     * @param child Node to reparent to grandParent.\n     */\n    private promoteChild(parent, child);\n    /**\n     * Finds a successor to a node and replaces that node with it.\n     * @param node\n     */\n    private promoteSuccessor(node);\n    /**\n     * Utility method for finding In-Order predecessor to the provided node\n     * @param node Parent node to find leaf node of greatest 'value'\n    */\n    private findGreaterLeaf(node);\n    /**\n     * Utility method for finding In-Order successor to the provided node\n     * @param node Parent Node to find leaf node of least 'value'\n     */\n    private findLesserLeaf(node);\n    /**\n     *  Interface method to support ranged queries.  Results sorted by index property.\n     * @param range Options for ranged request.\n     */\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    /**\n     * Implements ranged request operations.\n     * @param node\n     * @param range\n     */\n    private collateRequest(node, range);\n    /**\n     * Used on a branch node to return an array of id within that branch, sorted by their value\n     * @param node\n     */\n    private collateIds(node);\n    /**\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    /**\n     * Inline/Non-recusive 'single value' ($eq) lookup.\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    private locate(node, val);\n    /**\n     * Index integrity check (IRangedIndex interface function)\n     */\n    validateIndex(): boolean;\n    /**\n     * Recursive Node validation routine\n     * @param node\n     */\n    private validateNode(node);\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/loki/src/clone.d.ts",
    "content": "export declare type CloneMethod = \"parse-stringify\" | \"deep\" | \"shallow\" | \"shallow-recurse\";\n/**\n * @hidden\n */\nexport declare function clone<T>(data: T, method?: CloneMethod): T;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/loki/src/collection.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { UniqueIndex } from \"./unique_index\";\nimport { ResultSet } from \"./result_set\";\nimport { DynamicView } from \"./dynamic_view\";\nimport { IRangedIndex } from \"./ranged_indexes\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc, Dict } from \"../../common/types\";\nimport { FullTextSearch } from \"../../full-text-search/src/full_text_search\";\nimport { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\n/**\n * Collection class that handles documents of same type\n * @extends LokiEventEmitter\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class Collection<TData extends object = object, TNested extends object = object, T extends TData & TNested = TData & TNested> extends LokiEventEmitter {\n    name: string;\n    _data: Doc<T>[];\n    private _idIndex;\n    _rangedIndexes: {\n        [P in keyof T]?: Collection.RangedIndexMeta;\n    };\n    _lokimap: {\n        [$loki: number]: Doc<T>;\n    };\n    _unindexedSortComparator: string;\n    _defaultLokiOperatorPackage: string;\n    /**\n     * Unique constraints contain duplicate object references, so they are not persisted.\n     * We will keep track of properties which have unique constraints applied here, and regenerate on load.\n     */\n    _constraints: {\n        unique: {\n            [P in keyof T]?: UniqueIndex;\n        };\n    };\n    /**\n     * Transforms will be used to store frequently used query chains as a series of steps which itself can be stored along\n     * with the database.\n     */\n    _transforms: Dict<Collection.Transform<T>[]>;\n    /**\n     * In autosave scenarios we will use collection level dirty flags to determine whether save is needed.\n     * currently, if any collection is dirty we will autosave the whole database if autosave is configured.\n     * Defaulting to true since this is called from addCollection and adding a collection should trigger save.\n     */\n    _dirty: boolean;\n    private _cached;\n    /**\n     * Is collection transactional.\n     */\n    private _transactional;\n    /**\n     * Options to clone objects when inserting them.\n     */\n    _cloneObjects: boolean;\n    /**\n     * Default clone method (if enabled) is parse-stringify.\n     */\n    _cloneMethod: CloneMethod;\n    /**\n     * If set to true we will not maintain a meta property for a document.\n     */\n    private _disableMeta;\n    /**\n     * Disable track changes.\n     */\n    private _disableChangesApi;\n    /**\n     * Disable delta update object style on changes.\n     */\n    _disableDeltaChangesApi: boolean;\n    /**\n     * By default, if you insert a document with a Date value for an indexed property, we will convert that value to number.\n     */\n    private _serializableIndexes;\n    /**\n     * Name of path of used nested properties.\n     */\n    private _nestedProperties;\n    /**\n     * Option to activate a cleaner daemon - clears \"aged\" documents at set intervals.\n     */\n    _ttl: Collection.TTL;\n    private _maxId;\n    private _dynamicViews;\n    /**\n     * Changes are tracked by collection and aggregated by the db.\n     */\n    private _changes;\n    /**\n     * stages: a map of uniquely identified 'stages', which hold copies of objects to be\n     * manipulated without affecting the data in the original collection\n     */\n    private _stages;\n    private _commitLog;\n    _fullTextSearch: FullTextSearch;\n    /**\n     * @param {string} name - collection name\n     * @param {(object)} [options={}] - a configuration object\n     * @param {string[]} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {string[]} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {RangedIndexOptions} [options.rangedIndexes] - configuration object for ranged indexes\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are invoked asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes API\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {boolean} [options.serializableIndexes=true] - converts date values on binary indexed property values are serializable\n     * @param {string} [options.cloneMethod=\"deep\"] - the clone method\n     * @param {number} [options.transactional=false] - ?\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale.\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @param {string} [options.unindexedSortComparator=\"js\"] \"js\", \"abstract\", \"abstract-date\", \"loki\" or other registered comparator name\n     * @param {string} [options.defaultLokiOperatorPackage=\"js\"] \"js\", \"loki\", \"comparator\" (or user defined) query ops package\n     * @param {FullTextSearch.FieldOptions} [options.fullTextSearch=] - the full-text search options\n     * @see {@link Loki#addCollection} for normal creation of collections\n     */\n    constructor(name: string, options?: Collection.Options<TData, TNested>);\n    toJSON(): Collection.Serialized;\n    static fromJSONObject(obj: Collection.Serialized, options?: Collection.DeserializeOptions): Collection<any, object, any>;\n    /**\n     * Adds a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {array} transform - an array of transformation 'step' objects to save into the collection\n     */\n    addTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Retrieves a named transform from the collection.\n     * @param {string} name - name of the transform to lookup.\n     */\n    getTransform(name: string): Collection.Transform<T>[];\n    /**\n     * Updates a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {object} transform - a transformation object to save into collection\n     */\n    setTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Removes a named collection transform from the collection\n     * @param {string} name - name of collection transform to remove\n     */\n    removeTransform(name: string): void;\n    private setTTL(age, interval);\n    /**\n     * Create a row filter that covers all documents in the collection.\n     */\n    _prepareFullDocIndex(): number[];\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field\n     * @param indexTypeName\n     * @param comparatorName\n     */\n    ensureIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field Property to create an index on (need to look into contraining on keyof T)\n     * @param indexTypeName Name of IndexType factory within (global?) hashmap to create IRangedIndex from\n     * @param comparatorName Name of Comparator within (global?) hashmap\n     */\n    ensureRangedIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    ensureUniqueIndex(field: keyof T): UniqueIndex;\n    /**\n     * Quickly determine number of documents in collection (or query)\n     * @param {object} query - (optional) query object to count results of\n     * @returns {number} number of documents in the collection\n     */\n    count(query?: ResultSet.Query<Doc<T>>): number;\n    /**\n     * Rebuild idIndex\n     */\n    private _ensureId();\n    /**\n     * Add a dynamic view to the collection\n     * @param {string} name - name of dynamic view to add\n     * @param {object} options - (optional) options to configure dynamic view with\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=SortPriority.PASSIVE] - the sort priority\n     * @param {number} options.minRebuildInterval - minimum rebuild interval (need clarification to docs here)\n     * @returns {DynamicView} reference to the dynamic view added\n     **/\n    addDynamicView(name: string, options?: DynamicView.Options): DynamicView<T>;\n    /**\n     * Remove a dynamic view from the collection\n     * @param {string} name - name of dynamic view to remove\n     **/\n    removeDynamicView(name: string): void;\n    /**\n     * Look up dynamic view reference from within the collection\n     * @param {string} name - name of dynamic view to retrieve reference of\n     * @returns {DynamicView} A reference to the dynamic view with that name\n     **/\n    getDynamicView(name: string): DynamicView<T>;\n    /**\n     * Applies a 'mongo-like' find query object and passes all results to an update function.\n     * @param {object} filterObject - the 'mongo-like' query object\n     * @param {function} updateFunction - the update function\n     */\n    findAndUpdate(filterObject: ResultSet.Query<Doc<T>>, updateFunction: (obj: Doc<T>) => any): void;\n    /**\n     * Applies a 'mongo-like' find query object removes all documents which match that filter.\n     * @param {object} filterObject - 'mongo-like' query object\n     */\n    findAndRemove(filterObject: ResultSet.Query<Doc<T>>): void;\n    /**\n     * Adds object(s) to collection, ensure object(s) have meta properties, clone it if necessary, etc.\n     * @param {(object|array)} doc - the document (or array of documents) to be inserted\n     * @returns {(object|array)} document or documents inserted\n     */\n    insert(doc: TData): Doc<T>;\n    insert(doc: TData[]): Doc<T>[];\n    /**\n     * Adds a single object, ensures it has meta properties, clone it if necessary, etc.\n     * @param {object} doc - the document to be inserted\n     * @param {boolean} bulkInsert - quiet pre-insert and insert event emits\n     * @returns {object} document or 'undefined' if there was a problem inserting it\n     */\n    insertOne(doc: TData, bulkInsert?: boolean): Doc<T>;\n    /**\n     * Refers nested properties of an object to the root of it.\n     * @param {T} data - the object\n     * @returns {T & TNested} the object with nested properties\n     * @hidden\n     */\n    _defineNestedProperties<U extends TData>(data: U): U & TNested;\n    /**\n     * Empties the collection.\n     * @param {boolean} [removeIndices=false] - remove indices\n     */\n    clear({removeIndices: removeIndices}?: {\n        removeIndices?: boolean;\n    }): void;\n    /**\n     * Updates an object and notifies collection that the document has changed.\n     * @param {object} doc - document to update within the collection\n     */\n    update(doc: Doc<T> | Doc<T>[]): void;\n    /**\n     * Add object to collection\n     */\n    private _add(obj);\n    /**\n     * Applies a filter function and passes all results to an update function.\n     * @param {function} filterFunction - the filter function\n     * @param {function} updateFunction - the update function\n     */\n    updateWhere(filterFunction: (obj: Doc<T>) => boolean, updateFunction: (obj: Doc<T>) => Doc<T>): void;\n    /**\n     * Remove all documents matching supplied filter function.\n     * @param {function} filterFunction - the filter function\n     */\n    removeWhere(filterFunction: (obj: Doc<T>) => boolean): void;\n    removeDataOnly(): void;\n    /**\n     * Remove a document from the collection\n     * @param {number|object} doc - document to remove from collection\n     */\n    remove(doc: number | Doc<T> | Doc<T>[]): void;\n    /**\n     * Returns all changes.\n     * @returns {Collection.Change[]}\n     */\n    getChanges(): Collection.Change[];\n    /**\n     * Enables/disables changes api.\n     * @param {boolean} disableChangesApi\n     * @param {boolean} disableDeltaChangesApi\n     */\n    setChangesApi(disableChangesApi: boolean, disableDeltaChangesApi?: boolean): void;\n    /**\n     * Clears all the changes.\n     */\n    flushChanges(): void;\n    private _getObjectDelta(oldObject, newObject);\n    /**\n     * Compare changed object (which is a forced clone) with existing object and return the delta\n     */\n    private _getChangeDelta(obj, old);\n    /**\n     * Creates a clone of the current status of an object and associates operation and collection name,\n     * so the parent db can aggregate and generate a changes object for the entire db\n     */\n    private _createChange(name, op, obj, old?);\n    private _createInsertChange(obj);\n    private _createUpdateChange(obj, old);\n    private _insertMetaWithChange(obj);\n    private _updateMetaWithChange(obj, old);\n    private _insertMeta(obj);\n    private _updateMeta(obj);\n    /**\n     * Get by Id - faster than other methods because of the searching algorithm\n     * @param {int} id - $loki id of document you want to retrieve\n     * @param {boolean} returnPosition - if 'true' we will return [object, position]\n     * @returns {(object|array|null)} Object reference if document was found, null if not,\n     *     or an array if 'returnPosition' was passed.\n     */\n    get(id: number): Doc<T>;\n    get(id: number, returnPosition: boolean): Doc<T> | [Doc<T>, number];\n    /**\n     * Retrieve doc by Unique index\n     * @param {string} field - name of uniquely indexed property to use when doing lookup\n     * @param {any} value - unique value to search for\n     * @returns {object} document matching the value passed\n     */\n    by(field: keyof T, value: any): Doc<T>;\n    /**\n     * Find one object by index property, by property equal to value\n     * @param {object} query - query object used to perform search with\n     * @returns {(object|null)} First matching document, or null if none\n     */\n    findOne(query: ResultSet.Query<Doc<T>>): Doc<T>;\n    /**\n     * Chain method, used for beginning a series of chained find() and/or view() operations\n     * on a collection.\n     *\n     * @param {array} transform - Ordered array of transform step objects similar to chain\n     * @param {object} parameters - Object containing properties representing parameters to substitute\n     * @returns {ResultSet} (this) ResultSet, or data array if any map or join functions where called\n     */\n    chain(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Find method, api is similar to mongodb.\n     * for more complex queries use [chain()]{@link Collection#chain} or [where()]{@link Collection#where}.\n     * @example {@tutorial Query Examples}\n     * @param {object} query - 'mongo-like' query object\n     * @returns {array} Array of matching documents\n     */\n    find(query?: ResultSet.Query<Doc<T>>): Doc<T>[];\n    /**\n     * Find object by unindexed field by property equal to value,\n     * simply iterates and returns the first element matching the query\n     */\n    findOneUnindexed(prop: string, value: any): Doc<T>;\n    /**\n     * Transaction methods\n     */\n    /**\n     * start the transation\n     */\n    startTransaction(): void;\n    /**\n     * Commit the transaction.\n     */\n    commit(): void;\n    /**\n     * Rollback the transaction.\n     */\n    rollback(): void;\n    /**\n     * Query the collection by supplying a javascript filter function.\n     * @example\n     * let results = coll.where(function(obj) {\n       *   return obj.legs === 8;\n       * });\n     * @param {function} fun - filter function to run against all collection docs\n     * @returns {array} all documents which pass your filter function\n     */\n    where(fun: (obj: Doc<T>) => boolean): Doc<T>[];\n    /**\n     * Map Reduce operation\n     * @param {function} mapFunction - function to use as map function\n     * @param {function} reduceFunction - function to use as reduce function\n     * @returns {data} The result of your mapReduce operation\n     */\n    mapReduce<U1, U2>(mapFunction: (value: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Join two collections on specified properties\n     * @param {array} joinData - array of documents to 'join' to this collection\n     * @param {string} leftJoinProp - property name in collection\n     * @param {string} rightJoinProp - property name in joinData\n     * @param {function} mapFun - (Optional) map function to use\n     * @param dataOptions - options to data() before input to your map function\n     * @param [dataOptions.removeMeta] - allows removing meta before calling mapFun\n     * @param [dataOptions.forceClones] - forcing the return of cloned objects to your map object\n     * @param [dataOptions.forceCloneMethod] - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} Result of the mapping operation\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinProp: string | ((obj: any) => string), rightJoinProp: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * (Staging API) create a stage and/or retrieve it\n     */\n    getStage(name: string): any;\n    /**\n     * a collection of objects recording the changes applied through a commmitStage\n     */\n    /**\n     * (Staging API) create a copy of an object and insert it into a stage\n     */\n    stage<F extends TData>(stageName: string, obj: Doc<F>): F;\n    /**\n     * (Staging API) re-attach all objects to the original collection, so indexes and views can be rebuilt\n     * then create a message to be inserted in the commitlog\n     * @param {string} stageName - name of stage\n     * @param {string} message\n     */\n    commitStage(stageName: string, message: string): void;\n    /**\n     * Returns all values of a field.\n     * @param {string} field - the field name\n     * @return {any}: the array of values\n     */\n    extract(field: keyof T): any[];\n    /**\n     * Finds the minimum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the minimum value\n     */\n    min(field: keyof T): number;\n    /**\n     * Finds the maximum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the maximum value\n     */\n    max(field: keyof T): number;\n    /**\n     * Finds the minimum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    minRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Finds the maximum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    maxRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Returns all values of a field as numbers (if possible).\n     * @param {string} field - the field name\n     * @return {number[]} - the number array\n     */\n    extractNumerical(field: keyof T): number[];\n    /**\n     * Calculates the average numerical value of a field\n     * @param {string} field - the field name\n     * @returns {number} average of property in all docs in the collection\n     */\n    avg(field: keyof T): number;\n    /**\n     * Calculate the standard deviation of a field.\n     * @param {string} field - the field name\n     * @return {number} the standard deviation\n     */\n    stdDev(field: keyof T): number;\n    /**\n     * Calculates the mode of a field.\n     * @param {string} field - the field name\n     * @return {number} the mode\n     */\n    mode(field: keyof T): number;\n    /**\n     * Calculates the median of a field.\n     * @param {string} field - the field name\n     * @return {number} the median\n     */\n    median(field: keyof T): number;\n}\nexport declare namespace Collection {\n    interface Options<TData extends object, TNested extends object = {}, T extends object = TData & TNested> {\n        unique?: (keyof T)[];\n        unindexedSortComparator?: string;\n        defaultLokiOperatorPackage?: string;\n        rangedIndexes?: RangedIndexOptions;\n        serializableIndexes?: boolean;\n        asyncListeners?: boolean;\n        disableMeta?: boolean;\n        disableChangesApi?: boolean;\n        disableDeltaChangesApi?: boolean;\n        clone?: boolean;\n        serializableIndices?: boolean;\n        cloneMethod?: CloneMethod;\n        transactional?: boolean;\n        ttl?: number;\n        ttlInterval?: number;\n        nestedProperties?: (keyof TNested | {\n            name: keyof TNested;\n            path: string[];\n        })[];\n        fullTextSearch?: FullTextSearch.FieldOptions[];\n    }\n    interface RangedIndexOptions {\n        [prop: string]: RangedIndexMeta;\n    }\n    interface DeserializeOptions {\n        retainDirtyFlags?: boolean;\n        fullTextSearch?: Dict<Analyzer>;\n        [collName: string]: any | {\n            proto?: any;\n            inflate?: (src: object, dest?: object) => void;\n        };\n    }\n    interface BinaryIndex {\n        dirty: boolean;\n        values: any;\n    }\n    interface RangedIndexMeta {\n        index?: IRangedIndex<any>;\n        indexTypeName?: string;\n        comparatorName?: string;\n    }\n    interface Change {\n        name: string;\n        operation: string;\n        obj: any;\n    }\n    interface Serialized {\n        name: string;\n        unindexedSortComparator: string;\n        defaultLokiOperatorPackage: string;\n        _dynamicViews: DynamicView[];\n        _nestedProperties: {\n            name: string;\n            path: string[];\n        }[];\n        uniqueNames: string[];\n        transforms: Dict<Transform[]>;\n        rangedIndexes: RangedIndexOptions;\n        _data: Doc<any>[];\n        idIndex: number[];\n        maxId: number;\n        _dirty: boolean;\n        transactional: boolean;\n        asyncListeners: boolean;\n        disableMeta: boolean;\n        disableChangesApi: boolean;\n        disableDeltaChangesApi: boolean;\n        cloneObjects: boolean;\n        cloneMethod: CloneMethod;\n        changes: any;\n        _fullTextSearch: FullTextSearch;\n    }\n    interface CheckIndexOptions {\n        randomSampling?: boolean;\n        randomSamplingFactor?: number;\n        repair?: boolean;\n    }\n    type Transform<T extends object = object> = {\n        type: \"find\";\n        value: ResultSet.Query<Doc<T>> | string;\n    } | {\n        type: \"where\";\n        value: ((obj: Doc<T>) => boolean) | string;\n    } | {\n        type: \"simplesort\";\n        property: keyof T;\n        options?: boolean | ResultSet.SimpleSortOptions;\n    } | {\n        type: \"compoundsort\";\n        value: (keyof T | [keyof T, boolean])[];\n    } | {\n        type: \"sort\";\n        value: (a: Doc<T>, b: Doc<T>) => number;\n    } | {\n        type: \"sortByScoring\";\n        desc?: boolean;\n    } | {\n        type: \"limit\";\n        value: number;\n    } | {\n        type: \"offset\";\n        value: number;\n    } | {\n        type: \"map\";\n        value: (obj: Doc<T>, index: number, array: Doc<T>[]) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"eqJoin\";\n        joinData: Collection<any> | ResultSet<any>;\n        leftJoinKey: string | ((obj: any) => string);\n        rightJoinKey: string | ((obj: any) => string);\n        mapFun?: (left: any, right: any) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"mapReduce\";\n        mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => any;\n        reduceFunction: (array: any[]) => any;\n    } | {\n        type: \"update\";\n        value: (obj: Doc<T>) => any;\n    } | {\n        type: \"remove\";\n    };\n    interface TTL {\n        age: number;\n        ttlInterval: number;\n        daemon: any;\n    }\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/loki/src/comparators.d.ts",
    "content": "export interface ILokiComparer<T> {\n    (a: T, b: T): -1 | 0 | 1;\n}\nexport interface IComparatorMap {\n    [name: string]: ILokiComparer<any>;\n}\n/** Map/Register of named ILokiComparer functions returning -1, 0, 1 for lt/eq/gt assertions for two passed parameters */\nexport declare let ComparatorMap: IComparatorMap;\n/** Typescript-friendly factory for strongly typed 'js' comparators */\nexport declare function CreateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'abstract js' comparators */\nexport declare function CreateAbstractJavascriptComparator<T>(): ILokiComparer<T>;\n/**\n * Comparator which attempts to deal with deal with dates at comparator level.\n * Should work for dates in any of the object, string, and number formats\n */\nexport declare function CreateAbstractDateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'loki' comparators */\nexport declare function CreateLokiComparator(): ILokiComparer<any>;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/loki/src/dynamic_view.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { ResultSet } from \"./result_set\";\nimport { Collection } from \"./collection\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\n/**\n * DynamicView class is a versatile 'live' view class which can have filters and sorts applied.\n *    Collection.addDynamicView(name) instantiates this DynamicView object and notifies it\n *    whenever documents are add/updated/removed so it can remain up-to-date. (chainable)\n *\n * @example\n * let mydv = mycollection.addDynamicView('test');  // default is non-persistent\n * mydv.applyFind({ 'doors' : 4 });\n * mydv.applyWhere(function(obj) { return obj.name === 'Toyota'; });\n * let results = mydv.data();\n *\n * @extends LokiEventEmitter\n\n * @see {@link Collection#addDynamicView} to construct instances of DynamicView\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class DynamicView<T extends object = object> extends LokiEventEmitter {\n    readonly name: string;\n    private _collection;\n    private _persistent;\n    private _sortPriority;\n    private _minRebuildInterval;\n    private _rebuildPending;\n    private _resultSet;\n    private _resultData;\n    private _resultDirty;\n    private _cachedResultSet;\n    private _filterPipeline;\n    private _sortFunction;\n    private _sortCriteria;\n    private _sortCriteriaSimple;\n    private _sortByScoring;\n    private _sortDirty;\n    /**\n     * Constructor.\n     * @param {Collection} collection - a reference to the collection to work agains\n     * @param {string} name - the name of this dynamic view\n     * @param {object} options - the options\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=\"passive\"] - the sort priority\n     * @param {number} [options.minRebuildInterval=1] - minimum rebuild interval (need clarification to docs here)\n     */\n    constructor(collection: Collection<T>, name: string, options?: DynamicView.Options);\n    /**\n     * Internally used immediately after deserialization (loading)\n     *    This will clear out and reapply filterPipeline ops, recreating the view.\n     *    Since where filters do not persist correctly, this method allows\n     *    restoring the view to state where user can re-apply those where filters.\n     *\n     * @param removeWhereFilters\n     * @returns {DynamicView} This dynamic view for further chained ops.\n     * @fires DynamicView.rebuild\n     */\n    private _rematerialize({removeWhereFilters});\n    /**\n     * Makes a copy of the internal ResultSet for branched queries.\n     * Unlike this dynamic view, the branched ResultSet will not be 'live' updated,\n     * so your branched query should be immediately resolved and not held for future evaluation.\n     * @param {(string|array=)} transform - Optional name of collection transform, or an array of transform steps\n     * @param {object} parameters - optional parameters (if optional transform requires them)\n     * @returns {ResultSet} A copy of the internal ResultSet for branched queries.\n     */\n    branchResultSet(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Override of toJSON to avoid circular references.\n     */\n    toJSON(): DynamicView.Serialized;\n    static fromJSONObject(collection: Collection, obj: DynamicView.Serialized): DynamicView;\n    /**\n     * Used to clear pipeline and reset dynamic view to initial state.\n     * Existing options should be retained.\n     * @param {boolean} queueSortPhase - (default: false) if true we will async rebuild view (maybe set default to true in future?)\n     */\n    removeFilters({queueSortPhase}?: {\n        queueSortPhase?: boolean;\n    }): void;\n    /**\n     * Used to apply a sort to the dynamic view\n     * @example\n     * dv.applySort(function(obj1, obj2) {\n       *   if (obj1.name === obj2.name) return 0;\n       *   if (obj1.name > obj2.name) return 1;\n       *   if (obj1.name < obj2.name) return -1;\n       * });\n     * @param {function} comparefun - a javascript compare function used for sorting\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applySort(comparefun: (lhs: Doc<T>, rhs: Doc<T>) => number): this;\n    /**\n     * Used to specify a property used for view translation.\n     * @param {string} field - the field name\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether we should sort descending.\n     * @param {boolean} [options.disableIndexIntersect=false] - whether we should explicity not use array intersection.\n     * @param {boolean} [options.forceIndexIntersect=false] - force array intersection (if binary index exists).\n     * @param {boolean} [options.useJavascriptSorting=false] - whether results are sorted via basic javascript sort.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     * @example\n     * dv.applySimpleSort(\"name\");\n     */\n    applySimpleSort(field: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @param {Array} criteria - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {DynamicView} Reference to this DynamicView, sorted, for future chain operations.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * dv.applySortCriteria(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * dv.applySortCriteria(['age', ['name', true]]);\n     * // to sort by age (descending) and then by name (descending)\n     * dv.applySortCriteria([['age', true], ['name', true]]);\n     */\n    applySortCriteria(criteria: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Used to apply a sort by the latest full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     */\n    applySortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Marks the beginning of a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    startTransaction(): this;\n    /**\n     * Commits a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    commit(): this;\n    /**\n     * Rolls back a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    rollback(): this;\n    /**\n     * Find the index of a filter in the pipeline, by that filter's ID.\n     * @param {(string|number)} uid - The unique ID of the filter.\n     * @returns {number}: index of the referenced filter in the pipeline; -1 if not found.\n     */\n    private _indexOfFilterWithId(uid);\n    /**\n     * Add the filter object to the end of view's filter pipeline and apply the filter to the ResultSet.\n     * @param {object} filter - The filter object. Refer to applyFilter() for extra details.\n     */\n    private _addFilter(filter);\n    /**\n     * Reapply all the filters in the current pipeline.\n     *\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    reapplyFilters(): this;\n    /**\n     * Adds or updates a filter in the DynamicView filter pipeline\n     * @param {object} filter - A filter object to add to the pipeline.\n     *    The object is in the format { 'type': filter_type, 'val', filter_param, 'uid', optional_filter_id }\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFilter(filter: DynamicView.Filter<T>): this;\n    /**\n     * applyFind() - Adds or updates a mongo-style query option in the DynamicView filter pipeline\n     *\n     * @param {object} query - A mongo-style query object to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFind(query: object, uid?: string | number): this;\n    /**\n     * Adds or updates a javascript filter function in the DynamicView filter pipeline\n     * @param {function} fun - A javascript filter function to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyWhere(fun: (obj: Doc<T>) => boolean, uid?: string | number): this;\n    /**\n     * Remove the specified filter from the DynamicView filter pipeline\n     * @param {(string|number)} uid - The unique ID of the filter to be removed.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    removeFilter(uid: string | number): this;\n    /**\n     * Returns the number of documents representing the current DynamicView contents.\n     * @returns {number} The number of documents representing the current DynamicView contents.\n     */\n    count(): number;\n    /**\n     * Resolves and pending filtering and sorting, then returns document array as result.\n     * @param {object} options - optional parameters to pass to ResultSet.data() if non-persistent\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values include 'parse-stringify', 'jquery-extend-deep', 'shallow', 'shallow-assign'\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} An array of documents representing the current DynamicView contents.\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * When the view is not sorted we may still wish to be notified of rebuild events.\n     * This event will throttle and queue a single rebuild event when batches of updates affect the view.\n     */\n    private _queueRebuildEvent();\n    /**\n     * If the view is sorted we will throttle sorting to either :\n     * (1) passive - when the user calls data(), or\n     * (2) active - once they stop updating and yield js thread control\n     */\n    private _queueSortPhase();\n    /**\n     * Invoked synchronously or asynchronously to perform final sort phase (if needed)\n     */\n    private _performSortPhase(options?);\n    /**\n     * (Re)evaluating document inclusion.\n     * Called by : collection.insert() and collection.update().\n     * @param {int} objIndex - index of document to (re)run through filter pipeline.\n     * @param {boolean} isNew - true if the document was just added to the collection.\n     * @hidden\n     */\n    _evaluateDocument(objIndex: number, isNew: boolean): void;\n    /**\n     * Internal function called on collection.delete().\n     * @hidden\n     */\n    _removeDocument(objIndex: number): void;\n    /**\n     * Data transformation via user supplied functions\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: T, index: number, array: T[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n}\nexport declare namespace DynamicView {\n    interface Options {\n        persistent?: boolean;\n        sortPriority?: SortPriority;\n        minRebuildInterval?: number;\n    }\n    type SortPriority = \"passive\" | \"active\";\n    interface Serialized {\n        name: string;\n        _persistent: boolean;\n        _sortPriority: SortPriority;\n        _minRebuildInterval: number;\n        _resultSet: ResultSet<any>;\n        _filterPipeline: Filter<any>[];\n        _sortCriteria: (string | [string, boolean])[];\n        _sortCriteriaSimple: {\n            field: string;\n            options: boolean | ResultSet.SimpleSortOptions;\n        };\n        _sortByScoring: boolean;\n        _sortDirty: boolean;\n    }\n    type Filter<T extends object = object> = {\n        type: \"find\";\n        val: ResultSet.Query<Doc<T>>;\n        uid: number | string;\n    } | {\n        type: \"where\";\n        val: (obj: Doc<T>) => boolean;\n        uid: number | string;\n    };\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/loki/src/event_emitter.d.ts",
    "content": "/**\n * LokiEventEmitter is a minimalist version of EventEmitter. It enables any\n * constructor that inherits EventEmitter to emit events and trigger\n * listeners that have been added to the event through the on(event, callback) method\n *\n * @constructor LokiEventEmitter\n */\nexport declare class LokiEventEmitter {\n    /**\n     * A map, with each property being an array of callbacks.\n     */\n    protected _events: object;\n    /**\n     * Determines whether or not the callbacks associated with each event should happen in an async fashion or not.\n     * Default is false, which means events are synchronous\n     */\n    protected _asyncListeners: boolean;\n    /**\n     * Adds a listener to the queue of callbacks associated to an event\n     * @param {string|string[]} eventName - the name(s) of the event(s) to listen to\n     * @param {function} listener - callback function of listener to attach\n     * @returns {int} the index of the callback in the array of listeners for a particular event\n     */\n    on(eventName: string | string[], listener: Function): Function;\n    /**\n     * Emits a particular event\n     * with the option of passing optional parameters which are going to be processed by the callback\n     * provided signatures match (i.e. if passing emit(event, arg0, arg1) the listener should take two parameters)\n     * @param {string} eventName - the name of the event\n     * @param {object} data - optional object passed with the event\n     */\n    protected emit(eventName: string, ...data: any[]): void;\n    /**\n     * Alias of EventEmitter.on().\n     */\n    addListener(eventName: string | string[], listener: Function): Function;\n    /**\n     * Removes the listener at position 'index' from the event 'eventName'\n     * @param {string|string[]} eventName - the name(s) of the event(s) which the listener is attached to\n     * @param {function} listener - the listener callback function to remove from emitter\n     */\n    removeListener(eventName: string | string[], listener: Function): void;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/loki/src/index.d.ts",
    "content": "import { Loki } from \"./loki\";\nimport { Collection } from \"./collection\";\nexport { Loki, Collection };\nexport default Loki;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/loki/src/loki.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { Collection } from \"./collection\";\nimport { Doc, StorageAdapter } from \"../../common/types\";\nimport { IComparatorMap } from \"./comparators\";\nimport { IRangedIndexFactoryMap } from \"./ranged_indexes\";\nimport { ILokiOperatorPackageMap } from \"./operator_packages\";\nexport declare class Loki extends LokiEventEmitter {\n    filename: string;\n    private databaseVersion;\n    private engineVersion;\n    _collections: Collection[];\n    private _env;\n    private _serializationMethod;\n    private _destructureDelimiter;\n    private _persistenceMethod;\n    private _persistenceAdapter;\n    private _throttledSaves;\n    private _throttledSaveRunning;\n    private _throttledSavePending;\n    private _autosave;\n    private _autosaveInterval;\n    private _autosaveRunning;\n    private _autosaveHandler;\n    /**\n     * Constructs the main database class.\n     * @param {string} filename - name of the file to be saved to\n     * @param {object} [options={}] - options\n     * @param {Loki.Environment} [options.env] - the javascript environment\n     * @param {Loki.SerializationMethod} [options.serializationMethod=NORMAL] - the serialization method\n     * @param {string} [options.destructureDelimiter=\"$<\\n\"] - string delimiter used for destructured serialization\n     * @param {IComparatorMap} [options.comparatorMap] allows injecting or overriding registered comparators\n     * @param {IRangedIndexFactoryMap} [options.rangedIndexFactoryMap] allows injecting or overriding registered ranged index factories\n     * @param {ILokiOperatorPackageMap} [options.lokiOperatorPackageMap] allows injecting or overriding registered loki operator packages\n     */\n    constructor(filename?: string, options?: Loki.Options);\n    /**\n     * configures options related to database persistence.\n     *\n     * @param {Loki.PersistenceOptions} [options={}] - options\n     * @param {adapter} [options.adapter=auto] - an instance of a loki persistence adapter\n     * @param {boolean} [options.autosave=false] - enables autosave\n     * @param {int} [options.autosaveInterval=5000] - time interval (in milliseconds) between saves (if dirty)\n     * @param {boolean} [options.autoload=false] - enables autoload on loki instantiation\n     * @param {object} options.inflate - options that are passed to loadDatabase if autoload enabled\n     * @param {boolean} [options.throttledSaves=true] - if true, it batches multiple calls to to saveDatabase reducing number of\n     *   disk I/O operations and guaranteeing proper serialization of the calls. Default value is true.\n     * @param {Loki.PersistenceMethod} options.persistenceMethod - a persistence method which should be used (FS_STORAGE, LOCAL_STORAGE...)\n     * @returns {Promise} a Promise that resolves after initialization and (if enabled) autoloading the database\n     */\n    initializePersistence(options?: Loki.PersistenceOptions): Promise<void>;\n    /**\n     * Copies 'this' database into a new Loki instance. Object references are shared to make lightweight.\n     * @param {object} options - options\n     * @param {boolean} options.removeNonSerializable - nulls properties not safe for serialization.\n     */\n    copy(options?: Loki.CopyOptions): Loki;\n    /**\n     * Adds a collection to the database.\n     * @param {string} name - name of collection to add\n     * @param {object} [options={}] - options to configure collection with.\n     * @param {array} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {array} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {array} [options.indices=[]] - array property names to define binary indexes for\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are called asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes Api\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {string} [options.cloneMethod=CloneMethod.DEEP] - the clone method\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @returns {Collection} a reference to the collection which was just added\n     */\n    addCollection<TData extends object = object, TNested extends object = object>(name: string, options?: Collection.Options<TData, TNested>): Collection<TData, TNested>;\n    loadCollection(collection: Collection): void;\n    /**\n     * Retrieves reference to a collection by name.\n     * @param {string} name - name of collection to look up\n     * @returns {Collection} Reference to collection in database by that name, or null if not found\n     */\n    getCollection<TData extends object = object, TNested extends object = object>(name: string): Collection<TData, TNested>;\n    /**\n     * Renames an existing loki collection\n     * @param {string} oldName - name of collection to rename\n     * @param {string} newName - new name of collection\n     * @returns {Collection} reference to the newly renamed collection\n     */\n    renameCollection<TData extends object = object, TNested extends object = object>(oldName: string, newName: string): Collection<TData, TNested>;\n    listCollections(): {\n        name: string;\n        count: number;\n    }[];\n    /**\n     * Removes a collection from the database.\n     * @param {string} collectionName - name of collection to remove\n     */\n    removeCollection(collectionName: string): void;\n    /**\n     * Serialize database to a string which can be loaded via {@link Loki#loadJSON}\n     *\n     * @returns {string} Stringified representation of the loki database.\n     */\n    serialize(options?: Loki.SerializeOptions): string | string[];\n    toJSON(): Loki.Serialized;\n    /**\n     * Database level destructured JSON serialization routine to allow alternate serialization methods.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {object} options - output format options for use externally to loki\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to only output an individual collection or db (-1)\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {string|Array} A custom, restructured aggregation of independent serializations.\n     */\n    serializeDestructured(options?: Loki.SerializeDestructuredOptions): string | string[];\n    /**\n     * Collection level utility method to serialize a collection in a 'destructured' format\n     *\n     * @param {object} options - used to determine output of method\n     * @param {int} options.delimited - whether to return single delimited string or an array\n     * @param {string} options.delimiter - (optional) if delimited, this is delimiter to use\n     * @param {int} options.collectionIndex -  specify which collection to serialize data for\n     *\n     * @returns {string|array} A custom, restructured aggregation of independent serializations for a single collection.\n     */\n    serializeCollection(options?: {\n        delimited?: boolean;\n        collectionIndex?: number;\n        delimiter?: string;\n    }): string | string[];\n    /**\n     * Database level destructured JSON deserialization routine to minimize memory overhead.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {string|array} destructuredSource - destructured json or array to deserialize from\n     * @param {object} options - source format options\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to deserialize only a single partition\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {object|array} An object representation of the deserialized database, not yet applied to 'this' db or document array\n     */\n    deserializeDestructured(destructuredSource: string | string[], options?: Loki.SerializeDestructuredOptions): any;\n    /**\n     * Collection level utility function to deserializes a destructured collection.\n     *\n     * @param {string|string[]} destructuredSource - destructured representation of collection to inflate\n     * @param {object} options - used to describe format of destructuredSource input\n     * @param {int} [options.delimited=false] - whether source is delimited string or an array\n     * @param {string} options.delimiter - if delimited, this is delimiter to use (if other than default)\n     *\n     * @returns {Array} an array of documents to attach to collection.data.\n     */\n    deserializeCollection<T extends object = object>(destructuredSource: string | string[], options?: Loki.DeserializeCollectionOptions): Doc<T>[];\n    /**\n     * Inflates a loki database from a serialized JSON string\n     *\n     * @param {string} serializedDb - a serialized loki database string\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSON(serializedDb: string | string[], options?: Collection.DeserializeOptions): void;\n    /**\n     * Inflates a loki database from a JS object\n     *\n     * @param {object} dbObject - a serialized loki database object\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSONObject(dbObject: Loki, options?: Collection.DeserializeOptions): void;\n    loadJSONObject(dbObject: Loki.Serialized, options?: Collection.DeserializeOptions): void;\n    /**\n     * Emits the close event. In autosave scenarios, if the database is dirty, this will save and disable timer.\n     * Does not actually destroy the db.\n     *\n     * @returns {Promise} a Promise that resolves after closing the database succeeded\n     */\n    close(): Promise<void>;\n    /**-------------------------+\n     | Changes API               |\n     +--------------------------*/\n    /**\n     * The Changes API enables the tracking the changes occurred in the collections since the beginning of the session,\n     * so it's possible to create a differential dataset for synchronization purposes (possibly to a remote db)\n     */\n    /**\n     * (Changes API) : takes all the changes stored in each\n     * collection and creates a single array for the entire database. If an array of names\n     * of collections is passed then only the included collections will be tracked.\n     *\n     * @param {Array} [arrayOfCollectionNames=] - array of collection names. No arg means all collections are processed.\n     * @returns {Array} array of changes\n     * @see private method _createChange() in Collection\n     */\n    generateChangesNotification(arrayOfCollectionNames?: string[]): Collection.Change[];\n    /**\n     * (Changes API) - stringify changes for network transmission\n     * @returns {string} string representation of the changes\n     */\n    serializeChanges(collectionNamesArray?: string[]): string;\n    /**\n     * (Changes API) : clears all the changes in all collections.\n     */\n    clearChanges(): void;\n    /**\n     * Wait for throttledSaves to complete and invoke your callback when drained or duration is met.\n     *\n     * @param {object} options - configuration options\n     * @param {boolean} [options.recursiveWait=true] - if after queue is drained, another save was kicked off, wait for it\n     * @param {boolean} [options.recursiveWaitLimit=false] - limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDuration=2000] - cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves when save queue is drained, it is passed a sucess parameter value\n     */\n    throttledSaveDrain(options?: Loki.ThrottledDrainOptions): Promise<void>;\n    /**\n     * Internal load logic, decoupled from throttling/contention logic\n     *\n     * @param {object} options - an object containing inflation options for each collection\n     * @param {boolean} ignore_not_found - does not raise an error if database is not found\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    private _loadDatabase(options?, ignore_not_found?);\n    /**\n     * Handles manually loading from an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *    To avoid contention with any throttledSaves, we will drain the save queue first.\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @param {object} [options={}] - if throttling saves and loads, this controls how we drain save queue before loading\n     * @param {boolean} [options.recursiveWait=true] wait recursively until no saves are queued\n     * @param {boolean} [options.recursiveWaitLimit=false] limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDelay=2000] cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    loadDatabase(options?: Loki.LoadDatabaseOptions): Promise<void>;\n    private _saveDatabase();\n    /**\n     * Handles manually saving to an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @returns {Promise} a Promise that resolves after the database is persisted\n     */\n    saveDatabase(): Promise<void>;\n    /**\n     * Handles deleting a database from the underlying storage adapter\n     *\n     * @returns {Promise} a Promise that resolves after the database is deleted\n     */\n    deleteDatabase(): Promise<void>;\n    /****************\n     * Autosave API\n     ****************/\n    /**\n     * Check whether any collections are \"dirty\" meaning we need to save the (entire) database\n     * @returns {boolean} - true if database has changed since last autosave, otherwise false\n     */\n    private _autosaveDirty();\n    /**\n     * Resets dirty flags on all collections.\n     */\n    private _autosaveClearFlags();\n    /**\n     * Starts periodically saves to the underlying storage adapter.\n     */\n    private _autosaveEnable();\n    /**\n     * Stops the autosave interval timer.\n     */\n    private _autosaveDisable();\n}\nexport declare namespace Loki {\n    interface Options {\n        env?: Environment;\n        serializationMethod?: SerializationMethod;\n        destructureDelimiter?: string;\n        comparatorMap?: IComparatorMap;\n        rangedIndexFactoryMap?: IRangedIndexFactoryMap;\n        lokiOperatorPackageMap?: ILokiOperatorPackageMap;\n    }\n    interface PersistenceOptions {\n        adapter?: StorageAdapter;\n        autosave?: boolean;\n        autosaveInterval?: number;\n        autoload?: boolean;\n        throttledSaves?: boolean;\n        persistenceMethod?: Loki.PersistenceMethod;\n        inflate?: any;\n    }\n    interface CopyOptions {\n        removeNonSerializable?: boolean;\n    }\n    interface SerializeOptions {\n        serializationMethod?: SerializationMethod;\n    }\n    interface SerializeDestructuredOptions {\n        partitioned?: boolean;\n        partition?: number;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface DeserializeCollectionOptions {\n        partitioned?: boolean;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface ThrottledDrainOptions {\n        recursiveWait?: boolean;\n        recursiveWaitLimit?: boolean;\n        recursiveWaitLimitDuration?: number;\n        started?: Date;\n    }\n    interface Serialized {\n        _env: Environment;\n        _serializationMethod: SerializationMethod;\n        _autosave: boolean;\n        _autosaveInterval: number;\n        _collections: Collection[];\n        databaseVersion: number;\n        engineVersion: number;\n        filename: string;\n        _persistenceAdapter: StorageAdapter;\n        _persistenceMethod: PersistenceMethod;\n        _throttledSaves: boolean;\n    }\n    type LoadDatabaseOptions = Collection.DeserializeOptions & ThrottledDrainOptions;\n    type SerializationMethod = \"normal\" | \"pretty\" | \"destructured\";\n    type PersistenceMethod = \"fs-storage\" | \"local-storage\" | \"indexed-storage\" | \"memory-storage\" | \"adapter\";\n    type Environment = \"NATIVESCRIPT\" | \"NODEJS\" | \"CORDOVA\" | \"BROWSER\" | \"MEMORY\";\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/loki/src/operator_packages.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\n/** Hash interface for named LokiOperatorPackage registration */\nexport interface ILokiOperatorPackageMap {\n    [name: string]: LokiOperatorPackage;\n}\n/**\n * Helper function for determining 'loki' abstract equality which is a little more abstract than ==\n *     aeqHelper(5, '5') === true\n *     aeqHelper(5.0, '5') === true\n *     aeqHelper(new Date(\"1/1/2011\"), new Date(\"1/1/2011\")) === true\n *     aeqHelper({a:1}, {z:4}) === true (all objects sorted equally)\n *     aeqHelper([1, 2, 3], [1, 3]) === false\n *     aeqHelper([1, 2, 3], [1, 2, 3]) === true\n *     aeqHelper(undefined, null) === true\n * @param {any} prop1\n * @param {any} prop2\n * @returns {boolean}\n * @hidden\n */\nexport declare function aeqHelper(prop1: any, prop2: any): boolean;\n/**\n * Helper function for determining 'less-than' conditions for ops, sorting, and binary indices.\n *     In the future we might want $lt and $gt ops to use their own functionality/helper.\n *     Since binary indices on a property might need to index [12, NaN, new Date(), Infinity], we\n *     need this function (as well as gtHelper) to always ensure one value is LT, GT, or EQ to another.\n * @hidden\n */\nexport declare function ltHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @hidden\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} equal\n * @returns {boolean}\n */\nexport declare function gtHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} descending\n * @returns {number}\n * @hidden\n */\nexport declare function sortHelper(prop1: any, prop2: any, descending: boolean): number;\n/**\n * Default implementation of LokiOperatorPackage, using fastest javascript comparison operators.\n */\nexport declare class LokiOperatorPackage {\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n    $in(a: any, b: any): boolean;\n    $nin(a: any, b: any): boolean;\n    $keyin(a: string, b: object): boolean;\n    $nkeyin(a: string, b: object): boolean;\n    $definedin(a: string, b: object): boolean;\n    $undefinedin(a: string, b: object): boolean;\n    $regex(a: string, b: RegExp): boolean;\n    $containsNone(a: any, b: any): boolean;\n    $containsAny(a: any, b: any): boolean;\n    $contains(a: any, b: any): boolean;\n    $type(a: any, b: any): boolean;\n    $finite(a: number, b: boolean): boolean;\n    $size(a: any, b: any): boolean;\n    $len(a: any, b: any): boolean;\n    $where(a: any, b: any): boolean;\n    $not(a: any, b: any): boolean;\n    $and(a: any, b: any): boolean;\n    $or(a: any, b: any): boolean;\n    private doQueryOp(val, op);\n    private containsCheckFn(a);\n}\n/**\n * LokiOperatorPackage which utilizes abstract 'loki' comparisons for basic relational equality op implementations.\n */\nexport declare class LokiAbstractOperatorPackage extends LokiOperatorPackage {\n    constructor();\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * LokiOperatorPackage which utilizes provided comparator for basic relational equality op implementations.\n */\nexport declare class ComparatorOperatorPackage<T> extends LokiOperatorPackage {\n    comparator: ILokiComparer<T>;\n    constructor(comparator: ILokiComparer<T>);\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * Map/Register of named LokiOperatorPackages which implement all unindexed query ops within 'find' query objects\n */\nexport declare let LokiOperatorPackageMap: ILokiOperatorPackageMap;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/loki/src/ranged_indexes.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\nexport declare type RangedValueOperator = \"$gt\" | \"$gte\" | \"$lt\" | \"$lte\" | \"$eq\" | \"$neq\" | \"$between\";\nexport interface IRangedIndexRequest<T> {\n    op: RangedValueOperator;\n    val: T;\n    high?: T;\n}\n/** Defines interface which all loki ranged indexes need to implement */\nexport interface IRangedIndex<T> {\n    insert(id: number, val: T): void;\n    update(id: number, val: T): void;\n    remove(id: number): void;\n    restore(tree: any): void;\n    backup(): IRangedIndex<T>;\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    validateIndex(): boolean;\n}\n/** Hash Interface for global ranged index factory map*/\nexport interface IRangedIndexFactoryMap {\n    [name: string]: (name: string, comparator: ILokiComparer<any>) => IRangedIndex<any>;\n}\n/** Map/Register of named factory functions returning IRangedIndex instances */\nexport declare let RangedIndexFactoryMap: IRangedIndexFactoryMap;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/loki/src/result_set.d.ts",
    "content": "import { Collection } from \"./collection\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\nimport { Query as FullTextSearchQuery } from \"../../full-text-search/src/query_types\";\n/**\n * ResultSet class allowing chainable queries.  Intended to be instanced internally.\n *    Collection.find(), Collection.where(), and Collection.chain() instantiate this.\n *\n * @example\n *    mycollection.chain()\n *      .find({ 'doors' : 4 })\n *      .where(function(obj) { return obj.name === 'Toyota' })\n *      .data();\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class ResultSet<T extends object = object> {\n    _collection: Collection<T>;\n    _filteredRows: number[];\n    _filterInitialized: boolean;\n    private _scoring;\n    /**\n     * Constructor.\n     * @param {Collection} collection - the collection which this ResultSet will query against\n     */\n    constructor(collection: Collection<T>);\n    /**\n     * Reset the ResultSet to its initial state.\n     * @returns {ResultSet} Reference to this ResultSet, for future chain operations.\n     */\n    reset(): this;\n    /**\n     * Override of toJSON to avoid circular references\n     */\n    toJSON(): ResultSet<T>;\n    /**\n     * Allows you to limit the number of documents passed to next chain operation.\n     * A ResultSet copy() is made to avoid altering original ResultSet.\n     * @param {int} qty - The number of documents to return.\n     * @returns {ResultSet} Returns a copy of the ResultSet, limited by qty, for subsequent chain ops.\n     */\n    limit(qty: number): this;\n    /**\n     * Used for skipping 'pos' number of documents in the ResultSet.\n     * @param {int} pos - Number of documents to skip; all preceding documents are filtered out.\n     * @returns {ResultSet} Returns a copy of the ResultSet, containing docs starting at 'pos' for subsequent chain ops.\n     */\n    offset(pos: number): this;\n    /**\n     * To support reuse of ResultSet in branched query situations.\n     * @returns {ResultSet} Returns a copy of the ResultSet (set) but the underlying document references will be the same.\n     */\n    copy(): ResultSet<T>;\n    /**\n     * Executes a named collection transform or raw array of transform steps against the ResultSet.\n     * @param {(string|array)} transform - name of collection transform or raw transform array\n     * @param {object} [parameters=] - object property hash of parameters, if the transform requires them.\n     * @returns {ResultSet} either (this) ResultSet or a clone of of this ResultSet (depending on steps)\n     */\n    transform(transform: string | Collection.Transform<T>[], parameters?: object): this;\n    /**\n     * User supplied compare function is provided two documents to compare. (chainable)\n     * @example\n     *    rslt.sort(function(obj1, obj2) {\n       *      if (obj1.name === obj2.name) return 0;\n       *      if (obj1.name > obj2.name) return 1;\n       *      if (obj1.name < obj2.name) return -1;\n       *    });\n     * @param {function} comparefun - A javascript compare function used for sorting.\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    sort(comparefun: (a: Doc<T>, b: Doc<T>) => number): this;\n    /**\n     * Simpler, loose evaluation for user to sort based on a property name. (chainable).\n     * Sorting based on the same lt/gt helper functions used for binary indices.\n     * @param {string} propname - name of property to sort by.\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether to sort descending\n     * @param {string} [options.sortComparator] override default with name of comparator registered in ComparatorMap\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    simplesort(propname: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * rs.compoundsort(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * rs.compoundsort(['age', ['name', true]);\n     * @param {array} properties - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    compoundsort(properties: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Helper function for compoundsort(), performing individual object comparisons\n     * @param {Array} properties - array of property names, in order, by which to evaluate sort order\n     * @param {object} obj1 - first object to compare\n     * @param {object} obj2 - second object to compare\n     * @returns {number} 0, -1, or 1 to designate if identical (sortwise) or which should be first\n     */\n    private _compoundeval(properties, obj1, obj2);\n    /**\n     * Sorts the ResultSet based on the last full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     * @returns {ResultSet}\n     */\n    sortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Oversee the operation of OR'ed query expressions.\n     * OR'ed expression evaluation runs each expression individually against the full collection,\n     * and finally does a set OR on each expression's results.\n     * Each evaluation can utilize a binary index to prevent multiple linear array scans.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findOr(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $or(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Oversee the operation of AND'ed query expressions.\n     * AND'ed expression evaluation runs each expression progressively against the full collection,\n     * internally utilizing existing chained ResultSet functionality.\n     * Only the first filter can utilize a binary index.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findAnd(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $and(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Used for querying via a mongo-style query object.\n     *\n     * @param {object} query - A mongo-style query object used for filtering current results.\n     * @param {boolean} firstOnly - (Optional) Used by collection.findOne() - flag if this was invoked via findOne()\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    find(query?: ResultSet.Query<Doc<T>>, firstOnly?: boolean): this;\n    /**\n     * Used for filtering via a javascript filter function.\n     * @param {function} fun - A javascript function used for filtering current results by.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    where(fun: (obj: Doc<T>) => boolean): this;\n    /**\n     * Returns the number of documents in the ResultSet.\n     * @returns {number} The number of documents in the ResultSet.\n     */\n    count(): number;\n    /**\n     * Terminates the chain and returns array of filtered documents\n     * @param {object} options\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values 'parse-stringify', 'deep', and 'shallow' and\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} Array of documents in the ResultSet\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * Used to run an update operation on all documents currently in the ResultSet.\n     * @param {function} updateFunction - User supplied updateFunction(obj) will be executed for each document object.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    update(updateFunction: (obj: Doc<T>) => Doc<T>): this;\n    /**\n     * Removes all document objects which are currently in ResultSet from collection (as well as ResultSet)\n     * @returns {ResultSet} this (empty) ResultSet for further chain ops.\n     */\n    remove(): this;\n    /**\n     * data transformation via user supplied functions\n     *\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns {value} The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Left joining two sets of data. Join keys can be defined or calculated properties\n     * eqJoin expects the right join key values to be unique.  Otherwise left data will be joined on the last joinData object with that key\n     * @param {Array|ResultSet|Collection} joinData - Data array to join to.\n     * @param {(string|function)} leftJoinKey - Property name in this result set to join on or a function to produce a value to join on\n     * @param {(string|function)} rightJoinKey - Property name in the joinData to join on or a function to produce a value to join on\n     * @param {function} [mapFun=] - a function that receives each matching pair and maps them into output objects - function(left,right){return joinedObject}\n     * @param {object} [dataOptions=] - optional options to apply to data() calls for left and right sides\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} A ResultSet with data in the format [{left: leftObj, right: rightObj}]\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinKey: string | ((obj: any) => string), rightJoinKey: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * Applies a map function into a new collection for further chaining.\n     * @param {function} mapFun - javascript map function\n     * @param {object} [dataOptions=] - options to data() before input to your map function\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - Allows overriding the default or collection specified cloning method\n     * @return {ResultSet}\n     */\n    map<U extends object>(mapFun: (obj: Doc<T>, index: number, array: Doc<T>[]) => U, dataOptions?: ResultSet.DataOptions): ResultSet<U>;\n}\nexport declare namespace ResultSet {\n    interface DataOptions {\n        forceClones?: boolean;\n        forceCloneMethod?: CloneMethod;\n        removeMeta?: boolean;\n    }\n    interface SimpleSortOptions {\n        desc?: boolean;\n        sortComparator?: string;\n    }\n    type ContainsHelperType<R> = R extends string ? string | string[] : R extends any[] ? R[number] | R[number][] : R extends object ? keyof R | (keyof R)[] : never;\n    type LokiOps<R> = {\n        $eq?: R;\n    } | {\n        $ne?: R;\n    } | {\n        $gt?: R;\n    } | {\n        $gte?: R;\n    } | {\n        $lt?: R;\n    } | {\n        $lte?: R;\n    } | {\n        $between?: [R, R];\n    } | {\n        $in?: R[];\n    } | {\n        $nin?: R[];\n    } | {\n        $keyin?: object;\n    } | {\n        $nkeyin?: object;\n    } | {\n        $definedin?: object;\n    } | {\n        $undefinedin?: object;\n    } | {\n        $regex?: RegExp | string | [string, string];\n    } | {\n        $containsNone?: ContainsHelperType<R>;\n    } | {\n        $containsAny?: ContainsHelperType<R>;\n    } | {\n        $contains?: ContainsHelperType<R>;\n    } | {\n        $type?: string;\n    } | {\n        $finite?: boolean;\n    } | {\n        $size?: number;\n    } | {\n        $len?: number;\n    } | {\n        $where?: (val?: R) => boolean;\n    };\n    type Query<T> = {\n        [P in keyof T]?: LokiOps<T[P]> | T[P];\n    } & {\n        $and?: Query<T>[];\n    } & {\n        $or?: Query<T>[];\n    } & {\n        $fts?: FullTextSearchQuery;\n    };\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/loki/src/unique_index.d.ts",
    "content": "export declare class UniqueIndex {\n    private _field;\n    private _lokiMap;\n    private _valMap;\n    /**\n     * Constructs an unique index object.\n     * @param {string} propertyField - the property field to index\n     */\n    constructor(propertyField: string);\n    /**\n     * Sets a document's unique index.\n     * @param {number} id loki id to associate with value\n     * @param {*} value  value to associate with id\n     */\n    set(id: number, value: any): void;\n    /**\n     * Returns the $loki id of an unique value.\n     * @param {*} value the value to retrieve a loki id match for\n     */\n    get(value: any): number;\n    /**\n     * Updates a document's unique index.\n     * @param {number} id (loki) id of document to update the value to\n     * @param {*} value value to associate with loki id\n     */\n    update(id: number, value: any): void;\n    /**\n     * Removes an unique index.\n     * @param {number} id (loki) id to remove from index\n     */\n    remove(id: number): void;\n    /**\n     * Clears the unique index.\n     */\n    clear(): void;\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/memory-storage/src/index.d.ts",
    "content": "import { MemoryStorage } from \"./memory_storage\";\nexport { MemoryStorage };\nexport default MemoryStorage;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/memory-storage/src/memory_storage.d.ts",
    "content": "import { Dict, StorageAdapter } from \"../../common/types\";\n/**\n * An in-memory persistence adapter for an in-memory database.\n * This simple 'key/value' adapter is intended for unit testing and diagnostics.\n */\nexport declare class MemoryStorage implements StorageAdapter {\n    hashStore: Dict<{\n        savecount: number;\n        lastsave: Date;\n        value: string;\n    }>;\n    options: MemoryStorage.Options;\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} options - memory storage options\n     * @param {boolean} [options.asyncResponses=false] - whether callbacks are invoked asynchronously (default: false)\n     * @param {int} [options.asyncTimeout=50] - timeout in ms to queue callbacks (default: 50)\n     */\n    constructor(options?: MemoryStorage.Options);\n    /**\n     * Loads a serialized database from its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * Saves a serialized database to its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {string} dbstring - the database content\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a database from its in-memory store.\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport declare namespace MemoryStorage {\n    interface Options {\n        asyncResponses?: boolean;\n        asyncTimeout?: number;\n    }\n}\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/partitioning-adapter/src/index.d.ts",
    "content": "import { PartitioningAdapter } from \"./partitioning_adapter\";\nexport { PartitioningAdapter };\nexport default PartitioningAdapter;\n"
  },
  {
    "path": "dist/packages/full-text-search-language-en/types/partitioning-adapter/src/partitioning_adapter.d.ts",
    "content": "import { Loki } from \"../../loki/src/loki\";\nimport { StorageAdapter } from \"../../common/types\";\n/**\n * An adapter for adapters. Converts a non reference mode adapter into a reference mode adapter\n * which can perform destructuring and partitioning. Each collection will be stored in its own key/save and\n * only dirty collections will be saved. If you  turn on paging with default page size of 25megs and save\n * a 75 meg collection it should use up roughly 3 save slots (key/value pairs sent to inner adapter).\n * A dirty collection that spans three pages will save all three pages again\n * Paging mode was added mainly because Chrome has issues saving 'too large' of a string within a\n * single IndexedDB row. If a single document update causes the collection to be flagged as dirty, all\n * of that collection's pages will be written on next save.\n */\nexport declare class PartitioningAdapter implements StorageAdapter {\n    mode: string;\n    private _adapter;\n    private _dbref;\n    private _dbname;\n    private _pageIterator;\n    private _paging;\n    private _pageSize;\n    private _delimiter;\n    private _dirtyPartitions;\n    /**\n     * Registers the partitioning adapter as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the partitioning storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} adapter - reference to a 'non-reference' mode loki adapter instance.\n     * @param {boolean} paging - (default: false) set to true to enable paging collection data.\n     * @param {number} pageSize - (default : 25MB) you can use this to limit size of strings passed to inner adapter.\n     * @param {string} delimiter - allows you to override the default delimiter\n     */\n    constructor(adapter: StorageAdapter, {paging, pageSize, delimiter}?: {\n        paging?: boolean;\n        pageSize?: number;\n        delimiter?: string;\n    });\n    /**\n     * Loads a database which was partitioned into several key/value saves.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Used to sequentially load each collection partition, one at a time.\n     *\n     * @param {int} partition - ordinal collection position to load next\n     * @returns {Promise} a Promise that resolves after the next partition is loaded\n     */\n    private _loadNextPartition(partition);\n    /**\n     * Used to sequentially load the next page of collection partition, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next page is loaded\n     */\n    private _loadNextPage();\n    /**\n     * Saves a database by partioning into separate key/value saves.\n     * (Loki 'reference mode' persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {object} dbref - reference to database which we will partition and save.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     *\n     */\n    exportDatabase(dbname: string, dbref: Loki): Promise<void>;\n    /**\n     * Helper method used internally to save each dirty collection, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPartition();\n    /**\n     * Helper method used internally to generate and save the next page of the current (dirty) partition.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPage();\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/lokidb.indexed-storage.js",
    "content": "(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"@lokidb/indexed-storage\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"@lokidb/indexed-storage\"] = factory();\n\telse\n\t\t{ root[\"@lokidb/indexed-storage\"] = factory(); root[\"LokiIndexedStorage\"] = root[\"@lokidb/indexed-storage\"].default; }\n})(typeof self !== 'undefined' ? self : this, function() {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// define __esModule on exports\n/******/ \t__webpack_require__.r = function(exports) {\n/******/ \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n/******/ \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n/******/ \t\t}\n/******/ \t\tObject.defineProperty(exports, '__esModule', { value: true });\n/******/ \t};\n/******/\n/******/ \t// create a fake namespace object\n/******/ \t// mode & 1: value is a module id, require it\n/******/ \t// mode & 2: merge all properties of value into the ns\n/******/ \t// mode & 4: return value when already ns object\n/******/ \t// mode & 8|1: behave like require\n/******/ \t__webpack_require__.t = function(value, mode) {\n/******/ \t\tif(mode & 1) value = __webpack_require__(value);\n/******/ \t\tif(mode & 8) return value;\n/******/ \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n/******/ \t\tvar ns = Object.create(null);\n/******/ \t\t__webpack_require__.r(ns);\n/******/ \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n/******/ \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n/******/ \t\treturn ns;\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 1);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return PLUGINS; });\nfunction getGlobal() {\n    let glob;\n    (function (global) {\n        glob = global;\n    })(global !== undefined && global || this);\n    return glob;\n}\nfunction create() {\n    const global = getGlobal();\n    const sym = Symbol.for(\"LOKI\");\n    if (global[sym] === undefined) {\n        global[sym] = {};\n    }\n    return global[sym];\n}\n/**\n * @hidden\n */\nconst PLUGINS = create();\n\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(2)))\n\n/***/ }),\n/* 1 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n\n// EXTERNAL MODULE: ./packages/common/plugin.ts\nvar common_plugin = __webpack_require__(0);\n\n// CONCATENATED MODULE: ./packages/indexed-storage/src/indexed_storage.ts\n\n/**\n * Loki persistence adapter class for indexedDb.\n *     This class fulfills abstract adapter interface which can be applied to other storage methods.\n *     Utilizes the included LokiCatalog app/key/value database for actual database persistence.\n *     IndexedDb storage is provided per-domain, so we implement app/key/value database to\n *     allow separate contexts for separate apps within a domain.\n */\nclass indexed_storage_IndexedStorage {\n    /**\n     * Registers the indexed storage as plugin.\n     */\n    static register() {\n        common_plugin[\"a\" /* PLUGINS */][\"IndexedStorage\"] = indexed_storage_IndexedStorage;\n    }\n    /**\n     * Deregisters the indexed storage as plugin.\n     */\n    static deregister() {\n        delete common_plugin[\"a\" /* PLUGINS */][\"IndexedStorage\"];\n    }\n    /**\n     * @param {string} [appname=loki] - Application name context can be used to distinguish subdomains, \"loki\" by default\n     */\n    constructor(appname = \"loki\") {\n        this._appname = appname;\n        // keep reference to catalog class for base AKV operations\n        this.catalog = null;\n    }\n    /**\n     * Retrieves a serialized db string from the catalog.\n     *\n     * @example\n     * // LOAD\n     * var idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * var db = new loki(\"test\", { adapter: idbAdapter });\n     *   db.base(function(result) {\n       *   console.log(\"done\");\n       * });\n     *\n     * @param {string} dbname - the name of the database to retrieve.\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname) {\n        const appName = this._appname;\n        const adapter = this;\n        // lazy open/create db reference so dont -need- callback in constructor\n        if (this.catalog === null || this.catalog.db === null) {\n            return new Promise((resolve) => {\n                adapter.catalog = new LokiCatalog((cat) => {\n                    adapter.catalog = cat;\n                    resolve(adapter.loadDatabase(dbname));\n                });\n            });\n        }\n        // lookup up db string in AKV db\n        return new Promise((resolve, reject) => {\n            this.catalog.getAppKey(appName, dbname, (result) => {\n                if (result.id === 0) {\n                    reject(null);\n                    return;\n                }\n                resolve(result.val);\n            });\n        });\n    }\n    /**\n     * Saves a serialized db to the catalog.\n     *\n     * @example\n     * // SAVE : will save App/Key/Val as \"finance\"/\"test\"/{serializedDb}\n     * let idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * let db = new loki(\"test\", { adapter: idbAdapter });\n     * let coll = db.addCollection(\"testColl\");\n     * coll.insert({test: \"val\"});\n     * db.saveDatabase();  // could pass callback if needed for async complete\n     *\n     * @param {string} dbname - the name to give the serialized database within the catalog.\n     * @param {string} dbstring - the serialized db string to save.\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname, dbstring) {\n        const appName = this._appname;\n        const adapter = this;\n        let resolve;\n        let reject;\n        const result = new Promise((res, rej) => {\n            resolve = res;\n            reject = rej;\n        });\n        function saveCallback(result) {\n            if (result && result.success === true) {\n                resolve();\n            }\n            else {\n                reject(new Error(\"Error saving database\"));\n            }\n        }\n        // lazy open/create db reference so dont -need- callback in constructor\n        if (this.catalog === null || this.catalog.db === null) {\n            this.catalog = new LokiCatalog((cat) => {\n                adapter.catalog = cat;\n                // now that catalog has been initialized, set (add/update) the AKV entry\n                cat.setAppKey(appName, dbname, dbstring, saveCallback);\n            });\n            return result;\n        }\n        // set (add/update) entry to AKV database\n        this.catalog.setAppKey(appName, dbname, dbstring, saveCallback);\n        return result;\n    }\n    /**\n     * Deletes a serialized db from the catalog.\n     *\n     * @example\n     * // DELETE DATABASE\n     * // delete \"finance\"/\"test\" value from catalog\n     * idbAdapter.deleteDatabase(\"test\", function {\n       *   // database deleted\n       * });\n     *\n     * @param {string} dbname - the name of the database to delete from the catalog.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname) {\n        const appName = this._appname;\n        const adapter = this;\n        // lazy open/create db reference and pass callback ahead\n        if (this.catalog === null || this.catalog.db === null) {\n            return new Promise((resolve) => {\n                adapter.catalog = new LokiCatalog((cat) => {\n                    adapter.catalog = cat;\n                    resolve(adapter.deleteDatabase(dbname));\n                });\n            });\n        }\n        // catalog was already initialized, so just lookup object and delete by id\n        return new Promise((resolve) => {\n            this.catalog.getAppKey(appName, dbname, (result) => {\n                const id = result.id;\n                if (id !== 0) {\n                    adapter.catalog.deleteAppKey(id);\n                }\n                resolve();\n            });\n        });\n    }\n    /**\n     * Removes all database partitions and pages with the base filename passed in.\n     * This utility method does not (yet) guarantee async deletions will be completed before returning\n     *\n     * @param {string} dbname - the base filename which container, partitions, or pages are derived\n     */\n    deleteDatabasePartitions(dbname) {\n        this.getDatabaseList((result) => {\n            result.forEach((str) => {\n                if (str.startsWith(dbname)) {\n                    this.deleteDatabase(str);\n                }\n            });\n        });\n    }\n    /**\n     * Retrieves object array of catalog entries for current app.\n     *\n     * @example\n     * idbAdapter.getDatabaseList(function(result) {\n       *   // result is array of string names for that appcontext (\"finance\")\n       *   result.forEach(function(str) {\n       *     console.log(str);\n       *   });\n       * });\n     *\n     * @param {function} callback - should accept array of database names in the catalog for current app.\n     */\n    getDatabaseList(callback) {\n        const appName = this._appname;\n        const adapter = this;\n        // lazy open/create db reference so dont -need- callback in constructor\n        if (this.catalog === null || this.catalog.db === null) {\n            this.catalog = new LokiCatalog((cat) => {\n                adapter.catalog = cat;\n                adapter.getDatabaseList(callback);\n            });\n            return;\n        }\n        // catalog already initialized\n        // get all keys for current appName, and transpose results so just string array\n        this.catalog.getAppKeys(appName, (results) => {\n            const names = [];\n            for (let idx = 0; idx < results.length; idx++) {\n                names.push(results[idx].key);\n            }\n            if (typeof (callback) === \"function\") {\n                callback(names);\n            }\n            else {\n                names.forEach(() => {\n                    // console.log(obj);\n                });\n            }\n        });\n    }\n    /**\n     * Allows retrieval of list of all keys in catalog along with size\n     * @param {function} callback - (Optional) callback to accept result array.\n     */\n    getCatalogSummary(callback) {\n        const adapter = this;\n        // lazy open/create db reference\n        if (this.catalog === null || this.catalog.db === null) {\n            this.catalog = new LokiCatalog((cat) => {\n                adapter.catalog = cat;\n                adapter.getCatalogSummary(callback);\n            });\n            return;\n        }\n        // catalog already initialized\n        // get all keys for current appName, and transpose results so just string array\n        this.catalog.getAllKeys((results) => {\n            const entries = [];\n            let obj;\n            let size;\n            let oapp;\n            let okey;\n            let oval;\n            for (let idx = 0; idx < results.length; idx++) {\n                obj = results[idx];\n                oapp = obj.app || \"\";\n                okey = obj.key || \"\";\n                oval = obj.val || \"\";\n                // app and key are composited into an appkey column so we will mult by 2\n                size = oapp.length * 2 + okey.length * 2 + oval.length + 1;\n                entries.push({\n                    \"app\": obj.app,\n                    \"key\": obj.key,\n                    \"size\": size\n                });\n            }\n            if (typeof (callback) === \"function\") {\n                callback(entries);\n            }\n            else {\n                entries.forEach(() => {\n                    // console.log(obj);\n                });\n            }\n        });\n    }\n}\n/**\n * LokiCatalog - underlying App/Key/Value catalog persistence\n *    This non-interface class implements the actual persistence.\n *    Used by the LokiIndexedStorage class.\n */\nclass LokiCatalog {\n    constructor(callback) {\n        this.db = null;\n        this.initializeLokiCatalog(callback);\n    }\n    initializeLokiCatalog(callback) {\n        const openRequest = indexedDB.open(\"LokiCatalog\", 1);\n        const cat = this;\n        // If database doesn't exist yet or its version is lower than our version specified above (2nd param in line above)\n        openRequest.onupgradeneeded = (e) => {\n            const thisDB = e.target.result;\n            if (thisDB.objectStoreNames.contains(\"LokiAKV\")) {\n                thisDB.deleteObjectStore(\"LokiAKV\");\n            }\n            if (!thisDB.objectStoreNames.contains(\"LokiAKV\")) {\n                const objectStore = thisDB.createObjectStore(\"LokiAKV\", {\n                    keyPath: \"id\",\n                    autoIncrement: true\n                });\n                objectStore.createIndex(\"app\", \"app\", {\n                    unique: false\n                });\n                objectStore.createIndex(\"key\", \"key\", {\n                    unique: false\n                });\n                // hack to simulate composite key since overhead is low (main size should be in val field)\n                // user (me) required to duplicate the app and key into comma delimited appkey field off object\n                // This will allow retrieving single record with that composite key as well as\n                // still supporting opening cursors on app or key alone\n                objectStore.createIndex(\"appkey\", \"appkey\", {\n                    unique: true\n                });\n            }\n        };\n        openRequest.onsuccess = (e) => {\n            cat.db = e.target.result;\n            if (typeof (callback) === \"function\")\n                callback(cat);\n        };\n        openRequest.onerror = (e) => {\n            throw e;\n        };\n    }\n    getAppKey(app, key, callback) {\n        const transaction = this.db.transaction([\"LokiAKV\"], \"readonly\");\n        const store = transaction.objectStore(\"LokiAKV\");\n        const index = store.index(\"appkey\");\n        const appkey = app + \",\" + key;\n        const request = index.get(appkey);\n        request.onsuccess = (((usercallback) => (e) => {\n            let lres = e.target.result;\n            if (lres === null || lres === undefined) {\n                lres = {\n                    id: 0,\n                    success: false\n                };\n            }\n            if (typeof (usercallback) === \"function\") {\n                usercallback(lres);\n            }\n            else {\n                // console.log(lres);\n            }\n        }))(callback);\n        request.onerror = (((usercallback) => (e) => {\n            if (typeof (usercallback) === \"function\") {\n                usercallback({\n                    id: 0,\n                    success: false\n                });\n            }\n            else {\n                throw e;\n            }\n        }))(callback);\n    }\n    getAppKeyById(id, callback, data) {\n        const transaction = this.db.transaction([\"LokiAKV\"], \"readonly\");\n        const store = transaction.objectStore(\"LokiAKV\");\n        const request = store.get(id);\n        request.onsuccess = (((data, usercallback) => (e) => {\n            if (typeof (usercallback) === \"function\") {\n                usercallback(e.target.result, data);\n            }\n            else {\n                // console.log(e.target.result);\n            }\n        }))(data, callback);\n    }\n    setAppKey(app, key, val, callback) {\n        const transaction = this.db.transaction([\"LokiAKV\"], \"readwrite\");\n        const store = transaction.objectStore(\"LokiAKV\");\n        const index = store.index(\"appkey\");\n        const appkey = app + \",\" + key;\n        const request = index.get(appkey);\n        // first try to retrieve an existing object by that key\n        // need to do this because to update an object you need to have id in object, otherwise it will append id with new autocounter and clash the unique index appkey\n        request.onsuccess = (e) => {\n            let res = e.target.result;\n            if (res === null || res === undefined) {\n                res = {\n                    app,\n                    key,\n                    appkey: app + \",\" + key,\n                    val\n                };\n            }\n            else {\n                res.val = val;\n            }\n            const requestPut = store.put(res);\n            requestPut.onerror = (((usercallback) => () => {\n                if (typeof (usercallback) === \"function\") {\n                    usercallback({\n                        success: false\n                    });\n                }\n                else {\n                    // console.error(\"LokiCatalog.setAppKey (set) onerror\");\n                    // console.error(request.error);\n                }\n            }))(callback);\n            requestPut.onsuccess = (((usercallback) => () => {\n                if (typeof (usercallback) === \"function\") {\n                    usercallback({\n                        success: true\n                    });\n                }\n            }))(callback);\n        };\n        request.onerror = (((usercallback) => () => {\n            if (typeof (usercallback) === \"function\") {\n                usercallback({\n                    success: false\n                });\n            }\n            else {\n                // console.error(\"LokiCatalog.setAppKey (get) onerror\");\n                // console.error(request.error);\n            }\n        }))(callback);\n    }\n    deleteAppKey(id, callback) {\n        const transaction = this.db.transaction([\"LokiAKV\"], \"readwrite\");\n        const store = transaction.objectStore(\"LokiAKV\");\n        const request = store.delete(id);\n        request.onsuccess = (((usercallback) => () => {\n            if (typeof (usercallback) === \"function\")\n                usercallback({\n                    success: true\n                });\n        }))(callback);\n        request.onerror = (((usercallback) => () => {\n            if (typeof (usercallback) === \"function\") {\n                usercallback(false);\n            }\n            else {\n                // console.error(\"LokiCatalog.deleteAppKey raised onerror\");\n                // console.error(request.error);\n            }\n        }))(callback);\n    }\n    getAppKeys(app, callback) {\n        const transaction = this.db.transaction([\"LokiAKV\"], \"readonly\");\n        const store = transaction.objectStore(\"LokiAKV\");\n        const index = store.index(\"app\");\n        // We want cursor to all values matching our (single) app param\n        const singleKeyRange = IDBKeyRange.only(app);\n        // To use one of the key ranges, pass it in as the first argument of openCursor()/openKeyCursor()\n        const cursor = index.openCursor(singleKeyRange);\n        // cursor internally, pushing results into this.data[] and return\n        // this.data[] when done (similar to service)\n        const localdata = [];\n        cursor.onsuccess = (((data, callback) => (e) => {\n            const cursor = e.target.result;\n            if (cursor) {\n                const currObject = cursor.value;\n                data.push(currObject);\n                cursor.continue();\n            }\n            else {\n                if (typeof (callback) === \"function\") {\n                    callback(data);\n                }\n                else {\n                    // console.log(data);\n                }\n            }\n        }))(localdata, callback);\n        cursor.onerror = (((usercallback) => () => {\n            if (typeof (usercallback) === \"function\") {\n                usercallback(null);\n            }\n            else {\n                // console.error(\"LokiCatalog.getAppKeys raised onerror\");\n                // console.error(e);\n            }\n        }))(callback);\n    }\n    // Hide \"cursoring\" and return array of { id: id, key: key }\n    getAllKeys(callback) {\n        const transaction = this.db.transaction([\"LokiAKV\"], \"readonly\");\n        const store = transaction.objectStore(\"LokiAKV\");\n        const cursor = store.openCursor();\n        const localdata = [];\n        cursor.onsuccess = (((data, callback) => (e) => {\n            const cursor = e.target.result;\n            if (cursor) {\n                const currObject = cursor.value;\n                data.push(currObject);\n                cursor.continue();\n            }\n            else {\n                if (typeof (callback) === \"function\") {\n                    callback(data);\n                }\n                else {\n                    // console.log(data);\n                }\n            }\n        }))(localdata, callback);\n        cursor.onerror = (((usercallback) => () => {\n            if (typeof (usercallback) === \"function\")\n                usercallback(null);\n        }))(callback);\n    }\n}\n/* harmony default export */ var indexed_storage = (indexed_storage_IndexedStorage);\n\n// CONCATENATED MODULE: ./packages/indexed-storage/src/index.ts\n/* concated harmony reexport */__webpack_require__.d(__webpack_exports__, \"IndexedStorage\", function() { return indexed_storage_IndexedStorage; });\n\n\n/* harmony default export */ var src = __webpack_exports__[\"default\"] = (indexed_storage_IndexedStorage);\n\n\n/***/ }),\n/* 2 */\n/***/ (function(module, exports) {\n\nvar g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || Function(\"return this\")() || (1, eval)(\"this\");\n} catch (e) {\n\t// This works if the window reference is available\n\tif (typeof window === \"object\") g = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n\n\n/***/ })\n/******/ ]);\n});\n//# sourceMappingURL=lokidb.indexed-storage.js.map"
  },
  {
    "path": "dist/packages/indexed-storage/types/common/plugin.d.ts",
    "content": "/**\n * @hidden\n */\nexport declare const PLUGINS: void;\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/common/types.d.ts",
    "content": "/**\n * @hidden\n */\nimport { Loki } from \"../loki/src/loki\";\nexport interface StorageAdapter {\n    loadDatabase(dbname: string): Promise<any>;\n    saveDatabase?(dbname: string, serialization: string): Promise<void>;\n    deleteDatabase?(dbname: string): Promise<void>;\n    mode?: string;\n    exportDatabase?(dbname: string, dbref: Loki): Promise<void>;\n}\nexport declare type Doc<T extends object = object> = T & {\n    $loki: number;\n    meta?: {\n        created: number;\n        revision: number;\n        version: number;\n        updated?: number;\n    };\n};\nexport interface Dict<T> {\n    [index: string]: T;\n    [index: number]: T;\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/fs-storage/src/fs_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists using node fs module.\n */\nexport declare class FSStorage implements StorageAdapter {\n    /**\n     * Registers the fs storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the fs storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * Load data from file, will throw an error if the file does not exist\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Save data to file, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Delete the database file, will throw an error if the\n     * file can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/fs-storage/src/index.d.ts",
    "content": "import { FSStorage } from \"./fs_storage\";\nexport { FSStorage };\nexport default FSStorage;\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search/src/analyzer/analyzer.d.ts",
    "content": "import { CharacterFilter } from \"./character_filter\";\nimport { Tokenizer, whitespaceTokenizer } from \"./tokenizer\";\nimport { lowercaseTokenFilter, TokenFilter } from \"./token_filter\";\n/**\n * A analyzer converts a string into tokens which are added to the inverted index for searching.\n */\nexport interface Analyzer {\n    /**\n     * The character filters of the analyzer.\n     */\n    char_filter?: CharacterFilter[];\n    /**\n     * The tokenizer of the analyzer.\n     */\n    tokenizer: Tokenizer;\n    /**\n     * The token filters of the analyzer.\n     */\n    token_filter?: TokenFilter[];\n}\n/**\n * Analyzes a given string.\n * @param {Analyzer} analyzer - the analyzer\n * @param {string} str - the string\n * @returns {string[]} - the tokens\n */\nexport declare function analyze(analyzer: Analyzer, str: string): string[];\n/**\n * An analyzer with the whitespace tokenizer and the lowercase token filter.\n */\nexport declare class StandardAnalyzer implements Analyzer {\n    tokenizer: typeof whitespaceTokenizer;\n    token_filter: (typeof lowercaseTokenFilter)[];\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search/src/analyzer/character_filter.d.ts",
    "content": "/**\n * A character filter is used to preprocess a string before it is passed to a tokenizer.\n */\nexport declare type CharacterFilter = (value: string) => string;\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search/src/analyzer/token_filter.d.ts",
    "content": "/**\n * A token filter takes tokens from a tokenizer and modify, delete or add tokens.\n */\nexport declare type TokenFilter = (value: string, index: number, array: string[]) => string;\n/**\n * Converts a token to lowercase.\n * @param {string} token - the token\n * @returns {string} - the lowercased token\n */\nexport declare function lowercaseTokenFilter(token: string): string;\n/**\n * Converts a token to uppercase.\n * @param {string} token - the token\n * @returns {string} - the uppercased token\n */\nexport declare function uppercaseTokenFilter(token: string): string;\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search/src/analyzer/tokenizer.d.ts",
    "content": "/**\n * A tokenizer splits a string into individual tokens.\n */\nexport declare type Tokenizer = (value: string) => string[];\n/**\n * Splits a string at whitespace characters into tokens.\n * @param {string} value - the string\n * @returns {string[]} - the tokens\n */\nexport declare function whitespaceTokenizer(value: string): string[];\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search/src/full_text_search.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\nimport { Scorer } from \"./scorer\";\nimport { Analyzer } from \"./analyzer/analyzer\";\nexport declare class FullTextSearch {\n    private _id;\n    private _docs;\n    private _idxSearcher;\n    private _invIdxs;\n    /**\n     * Registers the full-text search as plugin.\n     */\n    static register(): void;\n    /**\n     * Initialize the full-text search for the given fields.\n     * @param {object[]} fieldOptions - the field options\n     * @param {string} fieldOptions.field - the name of the property field\n     * @param {boolean=true} fieldOptions.store - flag to indicate if the full-text search should be stored on serialization or\n     *  rebuild on deserialization\n     * @param {boolean=true} fieldOptions.optimizeChanges - flag to optimize updating and deleting of documents\n     *    (requires more memory but performs faster)\n     * @param {Analyzer} fieldOptions.analyzer - an analyzer for the field\n     * @param {string} [id] - the property name of the document index\n     */\n    constructor(fieldOptions?: FullTextSearch.FieldOptions[], id?: string);\n    addDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    removeDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    updateDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    clear(): void;\n    search(query: Query): Scorer.ScoreResults;\n    toJSON(): FullTextSearch.Serialization;\n    static fromJSONObject(serialized: FullTextSearch.Serialization, analyzers?: Dict<Analyzer>): FullTextSearch;\n}\nexport declare namespace FullTextSearch {\n    interface FieldOptions extends InvertedIndex.FieldOptions {\n        field: string;\n    }\n    interface Serialization {\n        id: string;\n        ii: Dict<InvertedIndex.Serialization>;\n    }\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search/src/fuzzy/automaton.d.ts",
    "content": "/**\n * Transition with dest, min and max.\n * @hidden\n */\nexport declare type Transition = [number, number, number];\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MIN_CODE_POINT = 0;\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MAX_CODE_POINT = 1114111;\n/**\n * From org/apache/lucene/util/automaton/Automaton.java\n * @hidden\n */\nexport declare class Automaton {\n    private _stateTransitions;\n    private _accept;\n    private _nextState;\n    private _currState;\n    private _transitions;\n    constructor();\n    isAccept(n: number): boolean;\n    createState(): number;\n    setAccept(state: number, accept: boolean): void;\n    finishState(): void;\n    private _finishCurrentState();\n    getStartPoints(): number[];\n    step(state: number, label: number): number;\n    getNumStates(): number;\n    addTransition(source: number, dest: number, min: number, max: number): void;\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search/src/fuzzy/lev1t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev1TParametricDescription.java\n * @hidden\n */\nexport declare class Lev1TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search/src/fuzzy/lev2t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev2TParametricDescription.java\n * @hidden\n */\nexport declare class Lev2TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search/src/fuzzy/levenshtein_automata.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java\n * @hidden\n */\nexport declare class LevenshteinAutomata {\n    private _word;\n    private _numRanges;\n    private _rangeLower;\n    private _rangeUpper;\n    private _description;\n    private _alphabet;\n    private _editDistance;\n    constructor(input: number[], editDistance: number);\n    /**\n     * Transforms the NDFA to a DFA.\n     * @returns {Automaton}\n     */\n    toAutomaton(): Automaton;\n    private _getVector(x, pos, end);\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search/src/fuzzy/long.d.ts",
    "content": "/**\n * Class supports 64Bit integer operations.\n * A cut-down version of dcodeIO/long.js.\n * @hidden\n */\nexport declare class Long {\n    private _low;\n    private _high;\n    constructor(low?: number, high?: number);\n    /**\n     * Returns this long with bits arithmetically shifted to the right by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftRight(numBits: number): Long;\n    /**\n     * Returns this long with bits arithmetically shifted to the left by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftLeft(numBits: number): Long;\n    /**\n     * Returns the bitwise AND of this Long and the specified.\n     * @param {Long} other - the other Long\n     * @returns {Long} the long\n     */\n    and(other: Long): Long;\n    /**\n     * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.\n     * @returns {number}\n     */\n    toInt(): number;\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search/src/fuzzy/parametric_description.d.ts",
    "content": "import { Long } from \"./long\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java#ParametricDescription\n * @hidden\n */\nexport declare class ParametricDescription {\n    protected _w: number;\n    private _n;\n    private _minErrors;\n    constructor(w: number, n: number, minErrors: number[]);\n    /**\n     * Return the number of states needed to compute a Levenshtein DFA\n     */\n    size(): number;\n    /**\n     * Returns true if the <code>state</code> in any Levenshtein DFA is an accept state (final state).\n     */\n    isAccept(absState: number): boolean;\n    /**\n     * Returns the position in the input word for a given <code>state</code>.\n     * This is the minimal boundary for the state.\n     */\n    getPosition(absState: number): number;\n    static unpack(data: Long[], index: number, bitsPerValue: number): number;\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search/src/fuzzy/run_automaton.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/RunAutomaton.java\n * @hidden\n */\nexport declare class RunAutomaton {\n    private _points;\n    private _accept;\n    private _transitions;\n    private _classmap;\n    constructor(automaton: Automaton);\n    getCharClass(c: number): number;\n    step(state: number, c: number): number;\n    isAccept(state: number): boolean;\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search/src/index.d.ts",
    "content": "import { FullTextSearch } from \"./full_text_search\";\nimport { analyze, StandardAnalyzer } from \"./analyzer/analyzer\";\nimport { whitespaceTokenizer } from \"./analyzer/tokenizer\";\nimport { lowercaseTokenFilter, uppercaseTokenFilter } from \"./analyzer/token_filter\";\nexport { FullTextSearch, analyze, StandardAnalyzer, whitespaceTokenizer, lowercaseTokenFilter, uppercaseTokenFilter };\nexport default FullTextSearch;\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search/src/index_searcher.d.ts",
    "content": "import { Scorer } from \"./scorer\";\nimport { InvertedIndex } from \"./inverted_index\";\nimport { Query } from \"./query_types\";\nimport { Dict } from \"../../common/types\";\n/**\n * @hidden\n */\nexport declare class IndexSearcher {\n    private _invIdxs;\n    private _docs;\n    private _scorer;\n    /**\n     * Constructs an index searcher.\n     * @param {Dict<InvertedIndex>} invIdxs - the inverted indexes\n     * @param {Set<number>} docs - the ids of the documents\n     */\n    constructor(invIdxs: Dict<InvertedIndex>, docs: Set<InvertedIndex.DocumentIndex>);\n    search(query: Query): Scorer.ScoreResults;\n    setDirty(): void;\n    private _recursive(query, doScoring);\n    private _getUnique(queries, doScoring, queryResults);\n    private _getAll(queries, doScoring, queryResults?);\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search/src/inverted_index.d.ts",
    "content": "import { Analyzer } from \"./analyzer/analyzer\";\n/**\n * Converts a string into an array of code points.\n * @param str - the string\n * @returns {number[]} to code points\n * @hidden\n */\nexport declare function toCodePoints(str: string): number[];\n/**\n * Inverted index class handles featured text search for specific document fields.\n * @hidden\n */\nexport declare class InvertedIndex {\n    analyzer: Analyzer;\n    docCount: number;\n    docStore: Map<InvertedIndex.DocumentIndex, InvertedIndex.DocStore>;\n    totalFieldLength: number;\n    root: InvertedIndex.Index;\n    private _store;\n    private _optimizeChanges;\n    /**\n     * @param {boolean} [options.store=true] - inverted index will be stored at serialization rather than rebuilt on load\n     * @param {boolean} [options.optimizeChanges=true] - flag to store additional metadata inside the index for better\n     *  performance if an existing field is updated or removed\n     * @param {Analyzer} [options.analyzer=] - the analyzer of this inverted index\n     */\n    constructor(options?: InvertedIndex.FieldOptions);\n    /**\n     * Adds defined fields of a document to the inverted index.\n     * @param {string} field - the field to add\n     * @param {number} docId - the doc id of the field\n     */\n    insert(field: string, docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Removes all relevant terms of a document from the inverted index.\n     * @param {number} docId - the document.\n     */\n    remove(docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Gets the term index of a term.\n     * @param {string} term - the term\n     * @param {object} root - the term index to start from\n     * @param {number} start - the position of the term string to start from\n     * @return {object} - The term index or null if the term is not in the term tree.\n     */\n    static getTermIndex(term: number[], root: InvertedIndex.Index, start?: number): InvertedIndex.Index;\n    /**\n     * Extends a term index to all available term leafs.\n     * @param {object} idx - the term index to start from\n     * @param {number[]} [term=[]] - the current term\n     * @param {Array} termIndices - all extended indices with their term\n     * @returns {Array} - Array with term indices and extension\n     */\n    static extendTermIndex(idx: InvertedIndex.Index, term?: number[], termIndices?: InvertedIndex.IndexTerm[]): InvertedIndex.IndexTerm[];\n    /**\n     * Serialize the inverted index.\n     * @returns {{docStore: *, _fields: *, index: *}}\n     */\n    toJSON(): InvertedIndex.Serialization;\n    /**\n     * Deserialize the inverted index.\n     * @param {{docStore: *, _fields: *, index: *}} serialized - The serialized inverted index.\n     * @param {Analyzer} analyzer[undefined] - an analyzer\n     */\n    static fromJSONObject(serialized: InvertedIndex.Serialization, analyzer?: Analyzer): InvertedIndex;\n    private static _serializeIndex(idx);\n    private static _deserializeIndex(serialized);\n    /**\n     * Set parent of to each index and regenerate the indexRef.\n     * @param {Index} index - the index\n     * @param {Index} parent - the parent\n     */\n    private _regenerate(index, parent);\n    /**\n     * Iterate over the whole inverted index and remove the document.\n     * Delete branch if not needed anymore.\n     * Function is needed if index is used without optimization.\n     * @param {Index} idx - the index\n     * @param {number} docId - the doc id\n     * @returns {boolean} true if index is empty\n     */\n    private _remove(idx, docId);\n}\nexport declare namespace InvertedIndex {\n    interface FieldOptions {\n        store?: boolean;\n        optimizeChanges?: boolean;\n        analyzer?: Analyzer;\n    }\n    type Index = Map<number, any> & {\n        dc?: Map<DocumentIndex, number>;\n        df?: number;\n        pa?: Index;\n    };\n    type IndexTerm = {\n        index: Index;\n        term: number[];\n    };\n    interface SerializedIndex {\n        d?: {\n            df: number;\n            dc: [DocumentIndex, number][];\n        };\n        k?: number[];\n        v?: SerializedIndex[];\n    }\n    type Serialization = SpareSerialization | FullSerialization;\n    type SpareSerialization = {\n        _store: false;\n        _optimizeChanges: boolean;\n    };\n    type FullSerialization = {\n        _store: true;\n        _optimizeChanges: boolean;\n        docCount: number;\n        docStore: [DocumentIndex, DocStore][];\n        totalFieldLength: number;\n        root: SerializedIndex;\n    };\n    interface DocStore {\n        fieldLength?: number;\n        indexRef?: Index[];\n    }\n    type DocumentIndex = number | string;\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search/src/query_types.d.ts",
    "content": "/**\n * Base query to enable boost to a query type.\n */\nexport interface BaseQuery<Type> {\n    type: Type;\n    boost?: number;\n}\n/**\n * A query which finds documents where a document field contains a term.\n */\nexport interface TermQuery extends BaseQuery<\"term\"> {\n    field: string;\n    value: string;\n}\n/**\n * A query which finds documents where a document field contains any of the terms.\n */\nexport interface TermsQuery extends BaseQuery<\"terms\"> {\n    field: string;\n    value: string[];\n}\n/**\n * A query which finds documents where the wildcard term can be applied at an existing document field term.\n */\nexport interface WildcardQuery extends BaseQuery<\"wildcard\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which finds documents where the fuzzy term can be transformed into an existing document field term within a\n * given edit distance.\n */\nexport interface FuzzyQuery extends BaseQuery<\"fuzzy\"> {\n    field: string;\n    value: string;\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query which matches documents containing the prefix of a term inside a field.\n */\nexport interface PrefixQuery extends BaseQuery<\"prefix\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which matches all documents with a given field.\n */\nexport interface ExistsQuery extends BaseQuery<\"exists\"> {\n    field: string;\n}\n/**\n * A query which tokenizes the given text into tokens and performs a sub query for each token. The results are combined\n * using a boolean operator.\n */\nexport interface MatchQuery extends BaseQuery<\"match\"> {\n    field: string;\n    value: string;\n    minimum_should_match?: number | string;\n    operator?: \"and\" | \"or\";\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query that matches all documents and giving them a constant score equal to the query boost.\n*/\nexport interface MatchQueryAll extends BaseQuery<\"match_all\"> {\n}\n/**\n * A query that wraps sub queries and returns a constant score equal to the query boost for every document in the filter.\n */\nexport interface ConstantScoreQuery extends BaseQuery<\"constant_score\"> {\n    filter: QueryTypes[];\n}\n/**\n * A query that matches documents matching boolean combinations of sub queries.\n */\nexport interface BoolQuery extends BaseQuery<\"bool\"> {\n    must?: QueryTypes[];\n    filter?: QueryTypes[];\n    should?: QueryTypes[];\n    not?: QueryTypes[];\n    minimum_should_match?: number | string;\n}\n/**\n * Union type of possible query types.\n */\nexport declare type QueryTypes = BoolQuery | ConstantScoreQuery | TermQuery | TermsQuery | WildcardQuery | FuzzyQuery | MatchQuery | MatchQueryAll | PrefixQuery | ExistsQuery;\n/**\n * The main query with the actually full-text search query and the scoring parameters.\n */\nexport interface Query {\n    query: QueryTypes;\n    calculate_scoring?: boolean;\n    explain?: boolean;\n    bm25?: {\n        k1: number;\n        b: number;\n    };\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search/src/scorer.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\n/**\n * @hidden\n */\nexport declare class Scorer {\n    private _invIdxs;\n    private _cache;\n    constructor(invIdxs: Dict<InvertedIndex>);\n    setDirty(): void;\n    score(fieldName: string, boost: number, termIdx: InvertedIndex.Index, doScoring: boolean | null, queryResults: Scorer.QueryResults, term: number[], df?: number): void;\n    scoreConstant(boost: number, docId: InvertedIndex.DocumentIndex, queryResults: Scorer.QueryResults): Scorer.QueryResults;\n    finalScore(query: Query, queryResults: Scorer.QueryResults): Scorer.ScoreResults;\n    private static _calculateFieldLength(fieldLength);\n    private _getCache(fieldName);\n    /**\n     * Returns the idf by either calculate it or use a cached one.\n     * @param {string} fieldName - the name of the field\n     * @param {number} docFreq - the doc frequency of the term\n     * @returns {number} the idf\n     * @private\n     */\n    private _idf(fieldName, docFreq);\n    private _avgFieldLength(fieldName);\n}\nexport declare namespace Scorer {\n    interface IDFCache {\n        idfs: Dict<number>;\n        avgFieldLength: number;\n    }\n    interface QueryResult {\n        tf?: number;\n        idf?: number;\n        boost: number;\n        fieldName?: string;\n        term?: number[];\n    }\n    type QueryResults = Map<InvertedIndex.DocumentIndex, QueryResult[]>;\n    interface BM25Explanation {\n        boost: number;\n        score: number;\n        docID: number;\n        fieldName: string;\n        index: string;\n        idf: number;\n        tfNorm: number;\n        tf: number;\n        fieldLength: number;\n        avgFieldLength: number;\n    }\n    interface ConstantExplanation {\n        boost: number;\n        score: number;\n    }\n    type ScoreExplanation = BM25Explanation | ConstantExplanation;\n    type ScoreResult = {\n        score: number;\n        explanation?: ScoreExplanation[];\n    };\n    type ScoreResults = Dict<ScoreResult>;\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search-language/src/index.d.ts",
    "content": "export { generateStopWordFilter, generateTrimmer, Among, SnowballProgram } from \"./language\";\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search-language/src/language.d.ts",
    "content": "export declare function generateTrimmer(wordCharacters: string): (token: string) => string;\nexport declare function generateStopWordFilter(stopWords: string[]): (token: string) => string;\nexport declare class Among {\n    s_size: number;\n    s: number[];\n    substring_i: number;\n    result: number;\n    method: any;\n    constructor(s: string, substring_i: number, result: number, method?: any);\n}\nexport declare class SnowballProgram {\n    current: string;\n    bra: number;\n    ket: number;\n    limit: number;\n    cursor: number;\n    limit_backward: number;\n    constructor();\n    setCurrent(word: string): void;\n    getCurrent(): string;\n    in_grouping(s: number[], min: number, max: number): boolean;\n    in_grouping_b(s: number[], min: number, max: number): boolean;\n    out_grouping(s: number[], min: number, max: number): boolean;\n    out_grouping_b(s: number[], min: number, max: number): boolean;\n    eq_s(s_size: number, s: string): boolean;\n    eq_s_b(s_size: number, s: string): boolean;\n    find_among(v: Among[], v_size: number): number;\n    find_among_b(v: Among[], v_size: number): number;\n    replace_s(c_bra: number, c_ket: number, s: string): number;\n    slice_check(): void;\n    slice_from(s: string): void;\n    slice_del(): void;\n    insert(c_bra: number, c_ket: number, s: string): void;\n    slice_to(): string;\n    eq_v_b(s: string): boolean;\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search-language-de/src/german_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class GermanAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search-language-de/src/index.d.ts",
    "content": "import { GermanAnalyzer } from \"./german_analyzer\";\nexport { GermanAnalyzer };\nexport default GermanAnalyzer;\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search-language-en/src/english_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class EnglishAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/full-text-search-language-en/src/index.d.ts",
    "content": "import { EnglishAnalyzer } from \"./english_analyzer\";\nexport { EnglishAnalyzer };\nexport default EnglishAnalyzer;\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/indexed-storage/src/index.d.ts",
    "content": "import { IndexedStorage } from \"./indexed_storage\";\nexport { IndexedStorage };\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/indexed-storage/src/indexed_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * Loki persistence adapter class for indexedDb.\n *     This class fulfills abstract adapter interface which can be applied to other storage methods.\n *     Utilizes the included LokiCatalog app/key/value database for actual database persistence.\n *     IndexedDb storage is provided per-domain, so we implement app/key/value database to\n *     allow separate contexts for separate apps within a domain.\n */\nexport declare class IndexedStorage implements StorageAdapter {\n    private _appname;\n    private catalog;\n    /**\n     * Registers the indexed storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the indexed storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {string} [appname=loki] - Application name context can be used to distinguish subdomains, \"loki\" by default\n     */\n    constructor(appname?: string);\n    /**\n     * Retrieves a serialized db string from the catalog.\n     *\n     * @example\n     * // LOAD\n     * var idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * var db = new loki(\"test\", { adapter: idbAdapter });\n     *   db.base(function(result) {\n       *   console.log(\"done\");\n       * });\n     *\n     * @param {string} dbname - the name of the database to retrieve.\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<{}>;\n    /**\n     * Saves a serialized db to the catalog.\n     *\n     * @example\n     * // SAVE : will save App/Key/Val as \"finance\"/\"test\"/{serializedDb}\n     * let idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * let db = new loki(\"test\", { adapter: idbAdapter });\n     * let coll = db.addCollection(\"testColl\");\n     * coll.insert({test: \"val\"});\n     * db.saveDatabase();  // could pass callback if needed for async complete\n     *\n     * @param {string} dbname - the name to give the serialized database within the catalog.\n     * @param {string} dbstring - the serialized db string to save.\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a serialized db from the catalog.\n     *\n     * @example\n     * // DELETE DATABASE\n     * // delete \"finance\"/\"test\" value from catalog\n     * idbAdapter.deleteDatabase(\"test\", function {\n       *   // database deleted\n       * });\n     *\n     * @param {string} dbname - the name of the database to delete from the catalog.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n    /**\n     * Removes all database partitions and pages with the base filename passed in.\n     * This utility method does not (yet) guarantee async deletions will be completed before returning\n     *\n     * @param {string} dbname - the base filename which container, partitions, or pages are derived\n     */\n    deleteDatabasePartitions(dbname: string): void;\n    /**\n     * Retrieves object array of catalog entries for current app.\n     *\n     * @example\n     * idbAdapter.getDatabaseList(function(result) {\n       *   // result is array of string names for that appcontext (\"finance\")\n       *   result.forEach(function(str) {\n       *     console.log(str);\n       *   });\n       * });\n     *\n     * @param {function} callback - should accept array of database names in the catalog for current app.\n     */\n    getDatabaseList(callback: (names: string[]) => void): void;\n    /**\n     * Allows retrieval of list of all keys in catalog along with size\n     * @param {function} callback - (Optional) callback to accept result array.\n     */\n    getCatalogSummary(callback: (entry: Entry[]) => void): void;\n}\nexport interface Entry {\n    app: string;\n    key: string;\n    size: number;\n}\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/local-storage/src/index.d.ts",
    "content": "import { LocalStorage } from \"./local_storage\";\nexport { LocalStorage };\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/local-storage/src/local_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists to web browser's local storage object\n * @constructor LocalStorageAdapter\n */\nexport declare class LocalStorage implements StorageAdapter {\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * loadDatabase() - Load data from localstorage\n     * @param {string} dbname - the name of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * saveDatabase() - save data to localstorage, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was saved\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * deleteDatabase() - delete the database from localstorage, will throw an error if it\n     * can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/loki/src/avl_index.d.ts",
    "content": "import { IRangedIndex, IRangedIndexRequest } from \"./ranged_indexes\";\nimport { ILokiComparer } from \"./comparators\";\n/**\n * Treenode type for binary search tree (BST) implementation.\n *\n * To support duplicates, we may need to either repurpose parent to\n * point to 'elder' sibling or add a siblingId to point to owner of\n * node represented in tree.\n */\nexport declare type TreeNode<T> = {\n    id: number;\n    value: T;\n    parent: number | null;\n    balance: number;\n    height: number;\n    left: number | null;\n    right: number | null;\n    siblings: number[];\n};\nexport interface ITreeNodeHash<T> {\n    [id: number]: TreeNode<T>;\n}\n/**\n * LokiDB AVL Balanced Binary Tree Index implementation.\n * To support duplicates, we use siblings (array) in tree nodes.\n * Basic AVL components guided by William Fiset tutorials at :\n * https://github.com/williamfiset/data-structures/blob/master/com/williamfiset/datastructures/balancedtree/AVLTreeRecursive.java\n * https://www.youtube.com/watch?v=g4y2h70D6Nk&list=PLDV1Zeh2NRsD06x59fxczdWLhDDszUHKt\n */\nexport declare class AvlTreeIndex<T> implements IRangedIndex<T> {\n    name: string;\n    comparator: ILokiComparer<T>;\n    nodes: ITreeNodeHash<T>;\n    apex: number | null;\n    /**\n     * Initializes index with property name and a comparer function.\n     */\n    constructor(name: string, comparator: ILokiComparer<T>);\n    backup(): AvlTreeIndex<T>;\n    restore(tree: AvlTreeIndex<T>): void;\n    /**\n     * Used for inserting a new value into the BinaryTreeIndex\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val Value to be indexed and inserted into binary tree\n     */\n    insert(id: number, val: T): void;\n    /**\n     * Recursively inserts a treenode and re-balances if needed.\n     * @param current\n     * @param node\n     */\n    insertNode(current: TreeNode<T>, node: TreeNode<T>): number;\n    /**\n     * Updates height and balance (calculation) for tree node\n     * @param node\n     */\n    private updateBalance(node);\n    /**\n     * Balance the 'double left-heavy' condition\n     * @param node\n     */\n    private leftLeftCase(node);\n    /**\n     * Balance the '(parent) left heavy, (child) right heavy' condition\n     * @param node\n     */\n    private leftRightCase(node);\n    /**\n     * Balance the 'double right-heavy' condition\n     * @param node\n     */\n    private rightRightCase(node);\n    /**\n     * Balance the '(parent) right heavy, (child) left heavy' condition\n     * @param node\n     */\n    private rightLeftCase(node);\n    /**\n     * Left rotation of node. Swaps right child into current location.\n     * @param node\n     */\n    private rotateLeft(node);\n    /**\n     * Right rotation of node. Swaps left child into current location.\n     * @param node\n     */\n    private rotateRight(node);\n    /**\n     * Diagnostic method for examining tree contents and structure\n     * @param node\n     */\n    getValuesAsTree(node?: TreeNode<T>): any;\n    /**\n     * Updates a value, possibly relocating it, within binary tree\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val New value to be indexed within binary tree\n     */\n    update(id: number, val: T): void;\n    /**\n     * Removes a value from the binary tree index\n     * @param id\n     */\n    remove(id: number): void;\n    /**\n     * Recursive node removal and rebalancer\n     * @param node\n     * @param val\n     */\n    private removeNode(node, id);\n    /**\n     * Utility method for updating a parent's child link when it changes\n     * @param parentId\n     * @param oldChildId\n     * @param newChildId\n     */\n    private updateChildLink(parentId, oldChildId, newChildId);\n    /**\n     * When removing a parent with only child, this does simple remap of child to grandParent.\n     * @param grandParent New parent of 'child'.\n     * @param parent Node being removed.\n     * @param child Node to reparent to grandParent.\n     */\n    private promoteChild(parent, child);\n    /**\n     * Finds a successor to a node and replaces that node with it.\n     * @param node\n     */\n    private promoteSuccessor(node);\n    /**\n     * Utility method for finding In-Order predecessor to the provided node\n     * @param node Parent node to find leaf node of greatest 'value'\n    */\n    private findGreaterLeaf(node);\n    /**\n     * Utility method for finding In-Order successor to the provided node\n     * @param node Parent Node to find leaf node of least 'value'\n     */\n    private findLesserLeaf(node);\n    /**\n     *  Interface method to support ranged queries.  Results sorted by index property.\n     * @param range Options for ranged request.\n     */\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    /**\n     * Implements ranged request operations.\n     * @param node\n     * @param range\n     */\n    private collateRequest(node, range);\n    /**\n     * Used on a branch node to return an array of id within that branch, sorted by their value\n     * @param node\n     */\n    private collateIds(node);\n    /**\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    /**\n     * Inline/Non-recusive 'single value' ($eq) lookup.\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    private locate(node, val);\n    /**\n     * Index integrity check (IRangedIndex interface function)\n     */\n    validateIndex(): boolean;\n    /**\n     * Recursive Node validation routine\n     * @param node\n     */\n    private validateNode(node);\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/loki/src/clone.d.ts",
    "content": "export declare type CloneMethod = \"parse-stringify\" | \"deep\" | \"shallow\" | \"shallow-recurse\";\n/**\n * @hidden\n */\nexport declare function clone<T>(data: T, method?: CloneMethod): T;\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/loki/src/collection.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { UniqueIndex } from \"./unique_index\";\nimport { ResultSet } from \"./result_set\";\nimport { DynamicView } from \"./dynamic_view\";\nimport { IRangedIndex } from \"./ranged_indexes\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc, Dict } from \"../../common/types\";\nimport { FullTextSearch } from \"../../full-text-search/src/full_text_search\";\nimport { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\n/**\n * Collection class that handles documents of same type\n * @extends LokiEventEmitter\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class Collection<TData extends object = object, TNested extends object = object, T extends TData & TNested = TData & TNested> extends LokiEventEmitter {\n    name: string;\n    _data: Doc<T>[];\n    private _idIndex;\n    _rangedIndexes: {\n        [P in keyof T]?: Collection.RangedIndexMeta;\n    };\n    _lokimap: {\n        [$loki: number]: Doc<T>;\n    };\n    _unindexedSortComparator: string;\n    _defaultLokiOperatorPackage: string;\n    /**\n     * Unique constraints contain duplicate object references, so they are not persisted.\n     * We will keep track of properties which have unique constraints applied here, and regenerate on load.\n     */\n    _constraints: {\n        unique: {\n            [P in keyof T]?: UniqueIndex;\n        };\n    };\n    /**\n     * Transforms will be used to store frequently used query chains as a series of steps which itself can be stored along\n     * with the database.\n     */\n    _transforms: Dict<Collection.Transform<T>[]>;\n    /**\n     * In autosave scenarios we will use collection level dirty flags to determine whether save is needed.\n     * currently, if any collection is dirty we will autosave the whole database if autosave is configured.\n     * Defaulting to true since this is called from addCollection and adding a collection should trigger save.\n     */\n    _dirty: boolean;\n    private _cached;\n    /**\n     * Is collection transactional.\n     */\n    private _transactional;\n    /**\n     * Options to clone objects when inserting them.\n     */\n    _cloneObjects: boolean;\n    /**\n     * Default clone method (if enabled) is parse-stringify.\n     */\n    _cloneMethod: CloneMethod;\n    /**\n     * If set to true we will not maintain a meta property for a document.\n     */\n    private _disableMeta;\n    /**\n     * Disable track changes.\n     */\n    private _disableChangesApi;\n    /**\n     * Disable delta update object style on changes.\n     */\n    _disableDeltaChangesApi: boolean;\n    /**\n     * By default, if you insert a document with a Date value for an indexed property, we will convert that value to number.\n     */\n    private _serializableIndexes;\n    /**\n     * Name of path of used nested properties.\n     */\n    private _nestedProperties;\n    /**\n     * Option to activate a cleaner daemon - clears \"aged\" documents at set intervals.\n     */\n    _ttl: Collection.TTL;\n    private _maxId;\n    private _dynamicViews;\n    /**\n     * Changes are tracked by collection and aggregated by the db.\n     */\n    private _changes;\n    /**\n     * stages: a map of uniquely identified 'stages', which hold copies of objects to be\n     * manipulated without affecting the data in the original collection\n     */\n    private _stages;\n    private _commitLog;\n    _fullTextSearch: FullTextSearch;\n    /**\n     * @param {string} name - collection name\n     * @param {(object)} [options={}] - a configuration object\n     * @param {string[]} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {string[]} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {RangedIndexOptions} [options.rangedIndexes] - configuration object for ranged indexes\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are invoked asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes API\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {boolean} [options.serializableIndexes=true] - converts date values on binary indexed property values are serializable\n     * @param {string} [options.cloneMethod=\"deep\"] - the clone method\n     * @param {number} [options.transactional=false] - ?\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale.\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @param {string} [options.unindexedSortComparator=\"js\"] \"js\", \"abstract\", \"abstract-date\", \"loki\" or other registered comparator name\n     * @param {string} [options.defaultLokiOperatorPackage=\"js\"] \"js\", \"loki\", \"comparator\" (or user defined) query ops package\n     * @param {FullTextSearch.FieldOptions} [options.fullTextSearch=] - the full-text search options\n     * @see {@link Loki#addCollection} for normal creation of collections\n     */\n    constructor(name: string, options?: Collection.Options<TData, TNested>);\n    toJSON(): Collection.Serialized;\n    static fromJSONObject(obj: Collection.Serialized, options?: Collection.DeserializeOptions): Collection<any, object, any>;\n    /**\n     * Adds a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {array} transform - an array of transformation 'step' objects to save into the collection\n     */\n    addTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Retrieves a named transform from the collection.\n     * @param {string} name - name of the transform to lookup.\n     */\n    getTransform(name: string): Collection.Transform<T>[];\n    /**\n     * Updates a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {object} transform - a transformation object to save into collection\n     */\n    setTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Removes a named collection transform from the collection\n     * @param {string} name - name of collection transform to remove\n     */\n    removeTransform(name: string): void;\n    private setTTL(age, interval);\n    /**\n     * Create a row filter that covers all documents in the collection.\n     */\n    _prepareFullDocIndex(): number[];\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field\n     * @param indexTypeName\n     * @param comparatorName\n     */\n    ensureIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field Property to create an index on (need to look into contraining on keyof T)\n     * @param indexTypeName Name of IndexType factory within (global?) hashmap to create IRangedIndex from\n     * @param comparatorName Name of Comparator within (global?) hashmap\n     */\n    ensureRangedIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    ensureUniqueIndex(field: keyof T): UniqueIndex;\n    /**\n     * Quickly determine number of documents in collection (or query)\n     * @param {object} query - (optional) query object to count results of\n     * @returns {number} number of documents in the collection\n     */\n    count(query?: ResultSet.Query<Doc<T>>): number;\n    /**\n     * Rebuild idIndex\n     */\n    private _ensureId();\n    /**\n     * Add a dynamic view to the collection\n     * @param {string} name - name of dynamic view to add\n     * @param {object} options - (optional) options to configure dynamic view with\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=SortPriority.PASSIVE] - the sort priority\n     * @param {number} options.minRebuildInterval - minimum rebuild interval (need clarification to docs here)\n     * @returns {DynamicView} reference to the dynamic view added\n     **/\n    addDynamicView(name: string, options?: DynamicView.Options): DynamicView<T>;\n    /**\n     * Remove a dynamic view from the collection\n     * @param {string} name - name of dynamic view to remove\n     **/\n    removeDynamicView(name: string): void;\n    /**\n     * Look up dynamic view reference from within the collection\n     * @param {string} name - name of dynamic view to retrieve reference of\n     * @returns {DynamicView} A reference to the dynamic view with that name\n     **/\n    getDynamicView(name: string): DynamicView<T>;\n    /**\n     * Applies a 'mongo-like' find query object and passes all results to an update function.\n     * @param {object} filterObject - the 'mongo-like' query object\n     * @param {function} updateFunction - the update function\n     */\n    findAndUpdate(filterObject: ResultSet.Query<Doc<T>>, updateFunction: (obj: Doc<T>) => any): void;\n    /**\n     * Applies a 'mongo-like' find query object removes all documents which match that filter.\n     * @param {object} filterObject - 'mongo-like' query object\n     */\n    findAndRemove(filterObject: ResultSet.Query<Doc<T>>): void;\n    /**\n     * Adds object(s) to collection, ensure object(s) have meta properties, clone it if necessary, etc.\n     * @param {(object|array)} doc - the document (or array of documents) to be inserted\n     * @returns {(object|array)} document or documents inserted\n     */\n    insert(doc: TData): Doc<T>;\n    insert(doc: TData[]): Doc<T>[];\n    /**\n     * Adds a single object, ensures it has meta properties, clone it if necessary, etc.\n     * @param {object} doc - the document to be inserted\n     * @param {boolean} bulkInsert - quiet pre-insert and insert event emits\n     * @returns {object} document or 'undefined' if there was a problem inserting it\n     */\n    insertOne(doc: TData, bulkInsert?: boolean): Doc<T>;\n    /**\n     * Refers nested properties of an object to the root of it.\n     * @param {T} data - the object\n     * @returns {T & TNested} the object with nested properties\n     * @hidden\n     */\n    _defineNestedProperties<U extends TData>(data: U): U & TNested;\n    /**\n     * Empties the collection.\n     * @param {boolean} [removeIndices=false] - remove indices\n     */\n    clear({removeIndices: removeIndices}?: {\n        removeIndices?: boolean;\n    }): void;\n    /**\n     * Updates an object and notifies collection that the document has changed.\n     * @param {object} doc - document to update within the collection\n     */\n    update(doc: Doc<T> | Doc<T>[]): void;\n    /**\n     * Add object to collection\n     */\n    private _add(obj);\n    /**\n     * Applies a filter function and passes all results to an update function.\n     * @param {function} filterFunction - the filter function\n     * @param {function} updateFunction - the update function\n     */\n    updateWhere(filterFunction: (obj: Doc<T>) => boolean, updateFunction: (obj: Doc<T>) => Doc<T>): void;\n    /**\n     * Remove all documents matching supplied filter function.\n     * @param {function} filterFunction - the filter function\n     */\n    removeWhere(filterFunction: (obj: Doc<T>) => boolean): void;\n    removeDataOnly(): void;\n    /**\n     * Remove a document from the collection\n     * @param {number|object} doc - document to remove from collection\n     */\n    remove(doc: number | Doc<T> | Doc<T>[]): void;\n    /**\n     * Returns all changes.\n     * @returns {Collection.Change[]}\n     */\n    getChanges(): Collection.Change[];\n    /**\n     * Enables/disables changes api.\n     * @param {boolean} disableChangesApi\n     * @param {boolean} disableDeltaChangesApi\n     */\n    setChangesApi(disableChangesApi: boolean, disableDeltaChangesApi?: boolean): void;\n    /**\n     * Clears all the changes.\n     */\n    flushChanges(): void;\n    private _getObjectDelta(oldObject, newObject);\n    /**\n     * Compare changed object (which is a forced clone) with existing object and return the delta\n     */\n    private _getChangeDelta(obj, old);\n    /**\n     * Creates a clone of the current status of an object and associates operation and collection name,\n     * so the parent db can aggregate and generate a changes object for the entire db\n     */\n    private _createChange(name, op, obj, old?);\n    private _createInsertChange(obj);\n    private _createUpdateChange(obj, old);\n    private _insertMetaWithChange(obj);\n    private _updateMetaWithChange(obj, old);\n    private _insertMeta(obj);\n    private _updateMeta(obj);\n    /**\n     * Get by Id - faster than other methods because of the searching algorithm\n     * @param {int} id - $loki id of document you want to retrieve\n     * @param {boolean} returnPosition - if 'true' we will return [object, position]\n     * @returns {(object|array|null)} Object reference if document was found, null if not,\n     *     or an array if 'returnPosition' was passed.\n     */\n    get(id: number): Doc<T>;\n    get(id: number, returnPosition: boolean): Doc<T> | [Doc<T>, number];\n    /**\n     * Retrieve doc by Unique index\n     * @param {string} field - name of uniquely indexed property to use when doing lookup\n     * @param {any} value - unique value to search for\n     * @returns {object} document matching the value passed\n     */\n    by(field: keyof T, value: any): Doc<T>;\n    /**\n     * Find one object by index property, by property equal to value\n     * @param {object} query - query object used to perform search with\n     * @returns {(object|null)} First matching document, or null if none\n     */\n    findOne(query: ResultSet.Query<Doc<T>>): Doc<T>;\n    /**\n     * Chain method, used for beginning a series of chained find() and/or view() operations\n     * on a collection.\n     *\n     * @param {array} transform - Ordered array of transform step objects similar to chain\n     * @param {object} parameters - Object containing properties representing parameters to substitute\n     * @returns {ResultSet} (this) ResultSet, or data array if any map or join functions where called\n     */\n    chain(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Find method, api is similar to mongodb.\n     * for more complex queries use [chain()]{@link Collection#chain} or [where()]{@link Collection#where}.\n     * @example {@tutorial Query Examples}\n     * @param {object} query - 'mongo-like' query object\n     * @returns {array} Array of matching documents\n     */\n    find(query?: ResultSet.Query<Doc<T>>): Doc<T>[];\n    /**\n     * Find object by unindexed field by property equal to value,\n     * simply iterates and returns the first element matching the query\n     */\n    findOneUnindexed(prop: string, value: any): Doc<T>;\n    /**\n     * Transaction methods\n     */\n    /**\n     * start the transation\n     */\n    startTransaction(): void;\n    /**\n     * Commit the transaction.\n     */\n    commit(): void;\n    /**\n     * Rollback the transaction.\n     */\n    rollback(): void;\n    /**\n     * Query the collection by supplying a javascript filter function.\n     * @example\n     * let results = coll.where(function(obj) {\n       *   return obj.legs === 8;\n       * });\n     * @param {function} fun - filter function to run against all collection docs\n     * @returns {array} all documents which pass your filter function\n     */\n    where(fun: (obj: Doc<T>) => boolean): Doc<T>[];\n    /**\n     * Map Reduce operation\n     * @param {function} mapFunction - function to use as map function\n     * @param {function} reduceFunction - function to use as reduce function\n     * @returns {data} The result of your mapReduce operation\n     */\n    mapReduce<U1, U2>(mapFunction: (value: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Join two collections on specified properties\n     * @param {array} joinData - array of documents to 'join' to this collection\n     * @param {string} leftJoinProp - property name in collection\n     * @param {string} rightJoinProp - property name in joinData\n     * @param {function} mapFun - (Optional) map function to use\n     * @param dataOptions - options to data() before input to your map function\n     * @param [dataOptions.removeMeta] - allows removing meta before calling mapFun\n     * @param [dataOptions.forceClones] - forcing the return of cloned objects to your map object\n     * @param [dataOptions.forceCloneMethod] - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} Result of the mapping operation\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinProp: string | ((obj: any) => string), rightJoinProp: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * (Staging API) create a stage and/or retrieve it\n     */\n    getStage(name: string): any;\n    /**\n     * a collection of objects recording the changes applied through a commmitStage\n     */\n    /**\n     * (Staging API) create a copy of an object and insert it into a stage\n     */\n    stage<F extends TData>(stageName: string, obj: Doc<F>): F;\n    /**\n     * (Staging API) re-attach all objects to the original collection, so indexes and views can be rebuilt\n     * then create a message to be inserted in the commitlog\n     * @param {string} stageName - name of stage\n     * @param {string} message\n     */\n    commitStage(stageName: string, message: string): void;\n    /**\n     * Returns all values of a field.\n     * @param {string} field - the field name\n     * @return {any}: the array of values\n     */\n    extract(field: keyof T): any[];\n    /**\n     * Finds the minimum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the minimum value\n     */\n    min(field: keyof T): number;\n    /**\n     * Finds the maximum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the maximum value\n     */\n    max(field: keyof T): number;\n    /**\n     * Finds the minimum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    minRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Finds the maximum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    maxRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Returns all values of a field as numbers (if possible).\n     * @param {string} field - the field name\n     * @return {number[]} - the number array\n     */\n    extractNumerical(field: keyof T): number[];\n    /**\n     * Calculates the average numerical value of a field\n     * @param {string} field - the field name\n     * @returns {number} average of property in all docs in the collection\n     */\n    avg(field: keyof T): number;\n    /**\n     * Calculate the standard deviation of a field.\n     * @param {string} field - the field name\n     * @return {number} the standard deviation\n     */\n    stdDev(field: keyof T): number;\n    /**\n     * Calculates the mode of a field.\n     * @param {string} field - the field name\n     * @return {number} the mode\n     */\n    mode(field: keyof T): number;\n    /**\n     * Calculates the median of a field.\n     * @param {string} field - the field name\n     * @return {number} the median\n     */\n    median(field: keyof T): number;\n}\nexport declare namespace Collection {\n    interface Options<TData extends object, TNested extends object = {}, T extends object = TData & TNested> {\n        unique?: (keyof T)[];\n        unindexedSortComparator?: string;\n        defaultLokiOperatorPackage?: string;\n        rangedIndexes?: RangedIndexOptions;\n        serializableIndexes?: boolean;\n        asyncListeners?: boolean;\n        disableMeta?: boolean;\n        disableChangesApi?: boolean;\n        disableDeltaChangesApi?: boolean;\n        clone?: boolean;\n        serializableIndices?: boolean;\n        cloneMethod?: CloneMethod;\n        transactional?: boolean;\n        ttl?: number;\n        ttlInterval?: number;\n        nestedProperties?: (keyof TNested | {\n            name: keyof TNested;\n            path: string[];\n        })[];\n        fullTextSearch?: FullTextSearch.FieldOptions[];\n    }\n    interface RangedIndexOptions {\n        [prop: string]: RangedIndexMeta;\n    }\n    interface DeserializeOptions {\n        retainDirtyFlags?: boolean;\n        fullTextSearch?: Dict<Analyzer>;\n        [collName: string]: any | {\n            proto?: any;\n            inflate?: (src: object, dest?: object) => void;\n        };\n    }\n    interface BinaryIndex {\n        dirty: boolean;\n        values: any;\n    }\n    interface RangedIndexMeta {\n        index?: IRangedIndex<any>;\n        indexTypeName?: string;\n        comparatorName?: string;\n    }\n    interface Change {\n        name: string;\n        operation: string;\n        obj: any;\n    }\n    interface Serialized {\n        name: string;\n        unindexedSortComparator: string;\n        defaultLokiOperatorPackage: string;\n        _dynamicViews: DynamicView[];\n        _nestedProperties: {\n            name: string;\n            path: string[];\n        }[];\n        uniqueNames: string[];\n        transforms: Dict<Transform[]>;\n        rangedIndexes: RangedIndexOptions;\n        _data: Doc<any>[];\n        idIndex: number[];\n        maxId: number;\n        _dirty: boolean;\n        transactional: boolean;\n        asyncListeners: boolean;\n        disableMeta: boolean;\n        disableChangesApi: boolean;\n        disableDeltaChangesApi: boolean;\n        cloneObjects: boolean;\n        cloneMethod: CloneMethod;\n        changes: any;\n        _fullTextSearch: FullTextSearch;\n    }\n    interface CheckIndexOptions {\n        randomSampling?: boolean;\n        randomSamplingFactor?: number;\n        repair?: boolean;\n    }\n    type Transform<T extends object = object> = {\n        type: \"find\";\n        value: ResultSet.Query<Doc<T>> | string;\n    } | {\n        type: \"where\";\n        value: ((obj: Doc<T>) => boolean) | string;\n    } | {\n        type: \"simplesort\";\n        property: keyof T;\n        options?: boolean | ResultSet.SimpleSortOptions;\n    } | {\n        type: \"compoundsort\";\n        value: (keyof T | [keyof T, boolean])[];\n    } | {\n        type: \"sort\";\n        value: (a: Doc<T>, b: Doc<T>) => number;\n    } | {\n        type: \"sortByScoring\";\n        desc?: boolean;\n    } | {\n        type: \"limit\";\n        value: number;\n    } | {\n        type: \"offset\";\n        value: number;\n    } | {\n        type: \"map\";\n        value: (obj: Doc<T>, index: number, array: Doc<T>[]) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"eqJoin\";\n        joinData: Collection<any> | ResultSet<any>;\n        leftJoinKey: string | ((obj: any) => string);\n        rightJoinKey: string | ((obj: any) => string);\n        mapFun?: (left: any, right: any) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"mapReduce\";\n        mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => any;\n        reduceFunction: (array: any[]) => any;\n    } | {\n        type: \"update\";\n        value: (obj: Doc<T>) => any;\n    } | {\n        type: \"remove\";\n    };\n    interface TTL {\n        age: number;\n        ttlInterval: number;\n        daemon: any;\n    }\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/loki/src/comparators.d.ts",
    "content": "export interface ILokiComparer<T> {\n    (a: T, b: T): -1 | 0 | 1;\n}\nexport interface IComparatorMap {\n    [name: string]: ILokiComparer<any>;\n}\n/** Map/Register of named ILokiComparer functions returning -1, 0, 1 for lt/eq/gt assertions for two passed parameters */\nexport declare let ComparatorMap: IComparatorMap;\n/** Typescript-friendly factory for strongly typed 'js' comparators */\nexport declare function CreateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'abstract js' comparators */\nexport declare function CreateAbstractJavascriptComparator<T>(): ILokiComparer<T>;\n/**\n * Comparator which attempts to deal with deal with dates at comparator level.\n * Should work for dates in any of the object, string, and number formats\n */\nexport declare function CreateAbstractDateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'loki' comparators */\nexport declare function CreateLokiComparator(): ILokiComparer<any>;\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/loki/src/dynamic_view.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { ResultSet } from \"./result_set\";\nimport { Collection } from \"./collection\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\n/**\n * DynamicView class is a versatile 'live' view class which can have filters and sorts applied.\n *    Collection.addDynamicView(name) instantiates this DynamicView object and notifies it\n *    whenever documents are add/updated/removed so it can remain up-to-date. (chainable)\n *\n * @example\n * let mydv = mycollection.addDynamicView('test');  // default is non-persistent\n * mydv.applyFind({ 'doors' : 4 });\n * mydv.applyWhere(function(obj) { return obj.name === 'Toyota'; });\n * let results = mydv.data();\n *\n * @extends LokiEventEmitter\n\n * @see {@link Collection#addDynamicView} to construct instances of DynamicView\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class DynamicView<T extends object = object> extends LokiEventEmitter {\n    readonly name: string;\n    private _collection;\n    private _persistent;\n    private _sortPriority;\n    private _minRebuildInterval;\n    private _rebuildPending;\n    private _resultSet;\n    private _resultData;\n    private _resultDirty;\n    private _cachedResultSet;\n    private _filterPipeline;\n    private _sortFunction;\n    private _sortCriteria;\n    private _sortCriteriaSimple;\n    private _sortByScoring;\n    private _sortDirty;\n    /**\n     * Constructor.\n     * @param {Collection} collection - a reference to the collection to work agains\n     * @param {string} name - the name of this dynamic view\n     * @param {object} options - the options\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=\"passive\"] - the sort priority\n     * @param {number} [options.minRebuildInterval=1] - minimum rebuild interval (need clarification to docs here)\n     */\n    constructor(collection: Collection<T>, name: string, options?: DynamicView.Options);\n    /**\n     * Internally used immediately after deserialization (loading)\n     *    This will clear out and reapply filterPipeline ops, recreating the view.\n     *    Since where filters do not persist correctly, this method allows\n     *    restoring the view to state where user can re-apply those where filters.\n     *\n     * @param removeWhereFilters\n     * @returns {DynamicView} This dynamic view for further chained ops.\n     * @fires DynamicView.rebuild\n     */\n    private _rematerialize({removeWhereFilters});\n    /**\n     * Makes a copy of the internal ResultSet for branched queries.\n     * Unlike this dynamic view, the branched ResultSet will not be 'live' updated,\n     * so your branched query should be immediately resolved and not held for future evaluation.\n     * @param {(string|array=)} transform - Optional name of collection transform, or an array of transform steps\n     * @param {object} parameters - optional parameters (if optional transform requires them)\n     * @returns {ResultSet} A copy of the internal ResultSet for branched queries.\n     */\n    branchResultSet(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Override of toJSON to avoid circular references.\n     */\n    toJSON(): DynamicView.Serialized;\n    static fromJSONObject(collection: Collection, obj: DynamicView.Serialized): DynamicView;\n    /**\n     * Used to clear pipeline and reset dynamic view to initial state.\n     * Existing options should be retained.\n     * @param {boolean} queueSortPhase - (default: false) if true we will async rebuild view (maybe set default to true in future?)\n     */\n    removeFilters({queueSortPhase}?: {\n        queueSortPhase?: boolean;\n    }): void;\n    /**\n     * Used to apply a sort to the dynamic view\n     * @example\n     * dv.applySort(function(obj1, obj2) {\n       *   if (obj1.name === obj2.name) return 0;\n       *   if (obj1.name > obj2.name) return 1;\n       *   if (obj1.name < obj2.name) return -1;\n       * });\n     * @param {function} comparefun - a javascript compare function used for sorting\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applySort(comparefun: (lhs: Doc<T>, rhs: Doc<T>) => number): this;\n    /**\n     * Used to specify a property used for view translation.\n     * @param {string} field - the field name\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether we should sort descending.\n     * @param {boolean} [options.disableIndexIntersect=false] - whether we should explicity not use array intersection.\n     * @param {boolean} [options.forceIndexIntersect=false] - force array intersection (if binary index exists).\n     * @param {boolean} [options.useJavascriptSorting=false] - whether results are sorted via basic javascript sort.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     * @example\n     * dv.applySimpleSort(\"name\");\n     */\n    applySimpleSort(field: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @param {Array} criteria - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {DynamicView} Reference to this DynamicView, sorted, for future chain operations.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * dv.applySortCriteria(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * dv.applySortCriteria(['age', ['name', true]]);\n     * // to sort by age (descending) and then by name (descending)\n     * dv.applySortCriteria([['age', true], ['name', true]]);\n     */\n    applySortCriteria(criteria: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Used to apply a sort by the latest full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     */\n    applySortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Marks the beginning of a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    startTransaction(): this;\n    /**\n     * Commits a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    commit(): this;\n    /**\n     * Rolls back a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    rollback(): this;\n    /**\n     * Find the index of a filter in the pipeline, by that filter's ID.\n     * @param {(string|number)} uid - The unique ID of the filter.\n     * @returns {number}: index of the referenced filter in the pipeline; -1 if not found.\n     */\n    private _indexOfFilterWithId(uid);\n    /**\n     * Add the filter object to the end of view's filter pipeline and apply the filter to the ResultSet.\n     * @param {object} filter - The filter object. Refer to applyFilter() for extra details.\n     */\n    private _addFilter(filter);\n    /**\n     * Reapply all the filters in the current pipeline.\n     *\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    reapplyFilters(): this;\n    /**\n     * Adds or updates a filter in the DynamicView filter pipeline\n     * @param {object} filter - A filter object to add to the pipeline.\n     *    The object is in the format { 'type': filter_type, 'val', filter_param, 'uid', optional_filter_id }\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFilter(filter: DynamicView.Filter<T>): this;\n    /**\n     * applyFind() - Adds or updates a mongo-style query option in the DynamicView filter pipeline\n     *\n     * @param {object} query - A mongo-style query object to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFind(query: object, uid?: string | number): this;\n    /**\n     * Adds or updates a javascript filter function in the DynamicView filter pipeline\n     * @param {function} fun - A javascript filter function to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyWhere(fun: (obj: Doc<T>) => boolean, uid?: string | number): this;\n    /**\n     * Remove the specified filter from the DynamicView filter pipeline\n     * @param {(string|number)} uid - The unique ID of the filter to be removed.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    removeFilter(uid: string | number): this;\n    /**\n     * Returns the number of documents representing the current DynamicView contents.\n     * @returns {number} The number of documents representing the current DynamicView contents.\n     */\n    count(): number;\n    /**\n     * Resolves and pending filtering and sorting, then returns document array as result.\n     * @param {object} options - optional parameters to pass to ResultSet.data() if non-persistent\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values include 'parse-stringify', 'jquery-extend-deep', 'shallow', 'shallow-assign'\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} An array of documents representing the current DynamicView contents.\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * When the view is not sorted we may still wish to be notified of rebuild events.\n     * This event will throttle and queue a single rebuild event when batches of updates affect the view.\n     */\n    private _queueRebuildEvent();\n    /**\n     * If the view is sorted we will throttle sorting to either :\n     * (1) passive - when the user calls data(), or\n     * (2) active - once they stop updating and yield js thread control\n     */\n    private _queueSortPhase();\n    /**\n     * Invoked synchronously or asynchronously to perform final sort phase (if needed)\n     */\n    private _performSortPhase(options?);\n    /**\n     * (Re)evaluating document inclusion.\n     * Called by : collection.insert() and collection.update().\n     * @param {int} objIndex - index of document to (re)run through filter pipeline.\n     * @param {boolean} isNew - true if the document was just added to the collection.\n     * @hidden\n     */\n    _evaluateDocument(objIndex: number, isNew: boolean): void;\n    /**\n     * Internal function called on collection.delete().\n     * @hidden\n     */\n    _removeDocument(objIndex: number): void;\n    /**\n     * Data transformation via user supplied functions\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: T, index: number, array: T[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n}\nexport declare namespace DynamicView {\n    interface Options {\n        persistent?: boolean;\n        sortPriority?: SortPriority;\n        minRebuildInterval?: number;\n    }\n    type SortPriority = \"passive\" | \"active\";\n    interface Serialized {\n        name: string;\n        _persistent: boolean;\n        _sortPriority: SortPriority;\n        _minRebuildInterval: number;\n        _resultSet: ResultSet<any>;\n        _filterPipeline: Filter<any>[];\n        _sortCriteria: (string | [string, boolean])[];\n        _sortCriteriaSimple: {\n            field: string;\n            options: boolean | ResultSet.SimpleSortOptions;\n        };\n        _sortByScoring: boolean;\n        _sortDirty: boolean;\n    }\n    type Filter<T extends object = object> = {\n        type: \"find\";\n        val: ResultSet.Query<Doc<T>>;\n        uid: number | string;\n    } | {\n        type: \"where\";\n        val: (obj: Doc<T>) => boolean;\n        uid: number | string;\n    };\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/loki/src/event_emitter.d.ts",
    "content": "/**\n * LokiEventEmitter is a minimalist version of EventEmitter. It enables any\n * constructor that inherits EventEmitter to emit events and trigger\n * listeners that have been added to the event through the on(event, callback) method\n *\n * @constructor LokiEventEmitter\n */\nexport declare class LokiEventEmitter {\n    /**\n     * A map, with each property being an array of callbacks.\n     */\n    protected _events: object;\n    /**\n     * Determines whether or not the callbacks associated with each event should happen in an async fashion or not.\n     * Default is false, which means events are synchronous\n     */\n    protected _asyncListeners: boolean;\n    /**\n     * Adds a listener to the queue of callbacks associated to an event\n     * @param {string|string[]} eventName - the name(s) of the event(s) to listen to\n     * @param {function} listener - callback function of listener to attach\n     * @returns {int} the index of the callback in the array of listeners for a particular event\n     */\n    on(eventName: string | string[], listener: Function): Function;\n    /**\n     * Emits a particular event\n     * with the option of passing optional parameters which are going to be processed by the callback\n     * provided signatures match (i.e. if passing emit(event, arg0, arg1) the listener should take two parameters)\n     * @param {string} eventName - the name of the event\n     * @param {object} data - optional object passed with the event\n     */\n    protected emit(eventName: string, ...data: any[]): void;\n    /**\n     * Alias of EventEmitter.on().\n     */\n    addListener(eventName: string | string[], listener: Function): Function;\n    /**\n     * Removes the listener at position 'index' from the event 'eventName'\n     * @param {string|string[]} eventName - the name(s) of the event(s) which the listener is attached to\n     * @param {function} listener - the listener callback function to remove from emitter\n     */\n    removeListener(eventName: string | string[], listener: Function): void;\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/loki/src/index.d.ts",
    "content": "import { Loki } from \"./loki\";\nimport { Collection } from \"./collection\";\nexport { Loki, Collection };\nexport default Loki;\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/loki/src/loki.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { Collection } from \"./collection\";\nimport { Doc, StorageAdapter } from \"../../common/types\";\nimport { IComparatorMap } from \"./comparators\";\nimport { IRangedIndexFactoryMap } from \"./ranged_indexes\";\nimport { ILokiOperatorPackageMap } from \"./operator_packages\";\nexport declare class Loki extends LokiEventEmitter {\n    filename: string;\n    private databaseVersion;\n    private engineVersion;\n    _collections: Collection[];\n    private _env;\n    private _serializationMethod;\n    private _destructureDelimiter;\n    private _persistenceMethod;\n    private _persistenceAdapter;\n    private _throttledSaves;\n    private _throttledSaveRunning;\n    private _throttledSavePending;\n    private _autosave;\n    private _autosaveInterval;\n    private _autosaveRunning;\n    private _autosaveHandler;\n    /**\n     * Constructs the main database class.\n     * @param {string} filename - name of the file to be saved to\n     * @param {object} [options={}] - options\n     * @param {Loki.Environment} [options.env] - the javascript environment\n     * @param {Loki.SerializationMethod} [options.serializationMethod=NORMAL] - the serialization method\n     * @param {string} [options.destructureDelimiter=\"$<\\n\"] - string delimiter used for destructured serialization\n     * @param {IComparatorMap} [options.comparatorMap] allows injecting or overriding registered comparators\n     * @param {IRangedIndexFactoryMap} [options.rangedIndexFactoryMap] allows injecting or overriding registered ranged index factories\n     * @param {ILokiOperatorPackageMap} [options.lokiOperatorPackageMap] allows injecting or overriding registered loki operator packages\n     */\n    constructor(filename?: string, options?: Loki.Options);\n    /**\n     * configures options related to database persistence.\n     *\n     * @param {Loki.PersistenceOptions} [options={}] - options\n     * @param {adapter} [options.adapter=auto] - an instance of a loki persistence adapter\n     * @param {boolean} [options.autosave=false] - enables autosave\n     * @param {int} [options.autosaveInterval=5000] - time interval (in milliseconds) between saves (if dirty)\n     * @param {boolean} [options.autoload=false] - enables autoload on loki instantiation\n     * @param {object} options.inflate - options that are passed to loadDatabase if autoload enabled\n     * @param {boolean} [options.throttledSaves=true] - if true, it batches multiple calls to to saveDatabase reducing number of\n     *   disk I/O operations and guaranteeing proper serialization of the calls. Default value is true.\n     * @param {Loki.PersistenceMethod} options.persistenceMethod - a persistence method which should be used (FS_STORAGE, LOCAL_STORAGE...)\n     * @returns {Promise} a Promise that resolves after initialization and (if enabled) autoloading the database\n     */\n    initializePersistence(options?: Loki.PersistenceOptions): Promise<void>;\n    /**\n     * Copies 'this' database into a new Loki instance. Object references are shared to make lightweight.\n     * @param {object} options - options\n     * @param {boolean} options.removeNonSerializable - nulls properties not safe for serialization.\n     */\n    copy(options?: Loki.CopyOptions): Loki;\n    /**\n     * Adds a collection to the database.\n     * @param {string} name - name of collection to add\n     * @param {object} [options={}] - options to configure collection with.\n     * @param {array} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {array} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {array} [options.indices=[]] - array property names to define binary indexes for\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are called asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes Api\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {string} [options.cloneMethod=CloneMethod.DEEP] - the clone method\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @returns {Collection} a reference to the collection which was just added\n     */\n    addCollection<TData extends object = object, TNested extends object = object>(name: string, options?: Collection.Options<TData, TNested>): Collection<TData, TNested>;\n    loadCollection(collection: Collection): void;\n    /**\n     * Retrieves reference to a collection by name.\n     * @param {string} name - name of collection to look up\n     * @returns {Collection} Reference to collection in database by that name, or null if not found\n     */\n    getCollection<TData extends object = object, TNested extends object = object>(name: string): Collection<TData, TNested>;\n    /**\n     * Renames an existing loki collection\n     * @param {string} oldName - name of collection to rename\n     * @param {string} newName - new name of collection\n     * @returns {Collection} reference to the newly renamed collection\n     */\n    renameCollection<TData extends object = object, TNested extends object = object>(oldName: string, newName: string): Collection<TData, TNested>;\n    listCollections(): {\n        name: string;\n        count: number;\n    }[];\n    /**\n     * Removes a collection from the database.\n     * @param {string} collectionName - name of collection to remove\n     */\n    removeCollection(collectionName: string): void;\n    /**\n     * Serialize database to a string which can be loaded via {@link Loki#loadJSON}\n     *\n     * @returns {string} Stringified representation of the loki database.\n     */\n    serialize(options?: Loki.SerializeOptions): string | string[];\n    toJSON(): Loki.Serialized;\n    /**\n     * Database level destructured JSON serialization routine to allow alternate serialization methods.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {object} options - output format options for use externally to loki\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to only output an individual collection or db (-1)\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {string|Array} A custom, restructured aggregation of independent serializations.\n     */\n    serializeDestructured(options?: Loki.SerializeDestructuredOptions): string | string[];\n    /**\n     * Collection level utility method to serialize a collection in a 'destructured' format\n     *\n     * @param {object} options - used to determine output of method\n     * @param {int} options.delimited - whether to return single delimited string or an array\n     * @param {string} options.delimiter - (optional) if delimited, this is delimiter to use\n     * @param {int} options.collectionIndex -  specify which collection to serialize data for\n     *\n     * @returns {string|array} A custom, restructured aggregation of independent serializations for a single collection.\n     */\n    serializeCollection(options?: {\n        delimited?: boolean;\n        collectionIndex?: number;\n        delimiter?: string;\n    }): string | string[];\n    /**\n     * Database level destructured JSON deserialization routine to minimize memory overhead.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {string|array} destructuredSource - destructured json or array to deserialize from\n     * @param {object} options - source format options\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to deserialize only a single partition\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {object|array} An object representation of the deserialized database, not yet applied to 'this' db or document array\n     */\n    deserializeDestructured(destructuredSource: string | string[], options?: Loki.SerializeDestructuredOptions): any;\n    /**\n     * Collection level utility function to deserializes a destructured collection.\n     *\n     * @param {string|string[]} destructuredSource - destructured representation of collection to inflate\n     * @param {object} options - used to describe format of destructuredSource input\n     * @param {int} [options.delimited=false] - whether source is delimited string or an array\n     * @param {string} options.delimiter - if delimited, this is delimiter to use (if other than default)\n     *\n     * @returns {Array} an array of documents to attach to collection.data.\n     */\n    deserializeCollection<T extends object = object>(destructuredSource: string | string[], options?: Loki.DeserializeCollectionOptions): Doc<T>[];\n    /**\n     * Inflates a loki database from a serialized JSON string\n     *\n     * @param {string} serializedDb - a serialized loki database string\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSON(serializedDb: string | string[], options?: Collection.DeserializeOptions): void;\n    /**\n     * Inflates a loki database from a JS object\n     *\n     * @param {object} dbObject - a serialized loki database object\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSONObject(dbObject: Loki, options?: Collection.DeserializeOptions): void;\n    loadJSONObject(dbObject: Loki.Serialized, options?: Collection.DeserializeOptions): void;\n    /**\n     * Emits the close event. In autosave scenarios, if the database is dirty, this will save and disable timer.\n     * Does not actually destroy the db.\n     *\n     * @returns {Promise} a Promise that resolves after closing the database succeeded\n     */\n    close(): Promise<void>;\n    /**-------------------------+\n     | Changes API               |\n     +--------------------------*/\n    /**\n     * The Changes API enables the tracking the changes occurred in the collections since the beginning of the session,\n     * so it's possible to create a differential dataset for synchronization purposes (possibly to a remote db)\n     */\n    /**\n     * (Changes API) : takes all the changes stored in each\n     * collection and creates a single array for the entire database. If an array of names\n     * of collections is passed then only the included collections will be tracked.\n     *\n     * @param {Array} [arrayOfCollectionNames=] - array of collection names. No arg means all collections are processed.\n     * @returns {Array} array of changes\n     * @see private method _createChange() in Collection\n     */\n    generateChangesNotification(arrayOfCollectionNames?: string[]): Collection.Change[];\n    /**\n     * (Changes API) - stringify changes for network transmission\n     * @returns {string} string representation of the changes\n     */\n    serializeChanges(collectionNamesArray?: string[]): string;\n    /**\n     * (Changes API) : clears all the changes in all collections.\n     */\n    clearChanges(): void;\n    /**\n     * Wait for throttledSaves to complete and invoke your callback when drained or duration is met.\n     *\n     * @param {object} options - configuration options\n     * @param {boolean} [options.recursiveWait=true] - if after queue is drained, another save was kicked off, wait for it\n     * @param {boolean} [options.recursiveWaitLimit=false] - limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDuration=2000] - cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves when save queue is drained, it is passed a sucess parameter value\n     */\n    throttledSaveDrain(options?: Loki.ThrottledDrainOptions): Promise<void>;\n    /**\n     * Internal load logic, decoupled from throttling/contention logic\n     *\n     * @param {object} options - an object containing inflation options for each collection\n     * @param {boolean} ignore_not_found - does not raise an error if database is not found\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    private _loadDatabase(options?, ignore_not_found?);\n    /**\n     * Handles manually loading from an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *    To avoid contention with any throttledSaves, we will drain the save queue first.\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @param {object} [options={}] - if throttling saves and loads, this controls how we drain save queue before loading\n     * @param {boolean} [options.recursiveWait=true] wait recursively until no saves are queued\n     * @param {boolean} [options.recursiveWaitLimit=false] limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDelay=2000] cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    loadDatabase(options?: Loki.LoadDatabaseOptions): Promise<void>;\n    private _saveDatabase();\n    /**\n     * Handles manually saving to an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @returns {Promise} a Promise that resolves after the database is persisted\n     */\n    saveDatabase(): Promise<void>;\n    /**\n     * Handles deleting a database from the underlying storage adapter\n     *\n     * @returns {Promise} a Promise that resolves after the database is deleted\n     */\n    deleteDatabase(): Promise<void>;\n    /****************\n     * Autosave API\n     ****************/\n    /**\n     * Check whether any collections are \"dirty\" meaning we need to save the (entire) database\n     * @returns {boolean} - true if database has changed since last autosave, otherwise false\n     */\n    private _autosaveDirty();\n    /**\n     * Resets dirty flags on all collections.\n     */\n    private _autosaveClearFlags();\n    /**\n     * Starts periodically saves to the underlying storage adapter.\n     */\n    private _autosaveEnable();\n    /**\n     * Stops the autosave interval timer.\n     */\n    private _autosaveDisable();\n}\nexport declare namespace Loki {\n    interface Options {\n        env?: Environment;\n        serializationMethod?: SerializationMethod;\n        destructureDelimiter?: string;\n        comparatorMap?: IComparatorMap;\n        rangedIndexFactoryMap?: IRangedIndexFactoryMap;\n        lokiOperatorPackageMap?: ILokiOperatorPackageMap;\n    }\n    interface PersistenceOptions {\n        adapter?: StorageAdapter;\n        autosave?: boolean;\n        autosaveInterval?: number;\n        autoload?: boolean;\n        throttledSaves?: boolean;\n        persistenceMethod?: Loki.PersistenceMethod;\n        inflate?: any;\n    }\n    interface CopyOptions {\n        removeNonSerializable?: boolean;\n    }\n    interface SerializeOptions {\n        serializationMethod?: SerializationMethod;\n    }\n    interface SerializeDestructuredOptions {\n        partitioned?: boolean;\n        partition?: number;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface DeserializeCollectionOptions {\n        partitioned?: boolean;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface ThrottledDrainOptions {\n        recursiveWait?: boolean;\n        recursiveWaitLimit?: boolean;\n        recursiveWaitLimitDuration?: number;\n        started?: Date;\n    }\n    interface Serialized {\n        _env: Environment;\n        _serializationMethod: SerializationMethod;\n        _autosave: boolean;\n        _autosaveInterval: number;\n        _collections: Collection[];\n        databaseVersion: number;\n        engineVersion: number;\n        filename: string;\n        _persistenceAdapter: StorageAdapter;\n        _persistenceMethod: PersistenceMethod;\n        _throttledSaves: boolean;\n    }\n    type LoadDatabaseOptions = Collection.DeserializeOptions & ThrottledDrainOptions;\n    type SerializationMethod = \"normal\" | \"pretty\" | \"destructured\";\n    type PersistenceMethod = \"fs-storage\" | \"local-storage\" | \"indexed-storage\" | \"memory-storage\" | \"adapter\";\n    type Environment = \"NATIVESCRIPT\" | \"NODEJS\" | \"CORDOVA\" | \"BROWSER\" | \"MEMORY\";\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/loki/src/operator_packages.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\n/** Hash interface for named LokiOperatorPackage registration */\nexport interface ILokiOperatorPackageMap {\n    [name: string]: LokiOperatorPackage;\n}\n/**\n * Helper function for determining 'loki' abstract equality which is a little more abstract than ==\n *     aeqHelper(5, '5') === true\n *     aeqHelper(5.0, '5') === true\n *     aeqHelper(new Date(\"1/1/2011\"), new Date(\"1/1/2011\")) === true\n *     aeqHelper({a:1}, {z:4}) === true (all objects sorted equally)\n *     aeqHelper([1, 2, 3], [1, 3]) === false\n *     aeqHelper([1, 2, 3], [1, 2, 3]) === true\n *     aeqHelper(undefined, null) === true\n * @param {any} prop1\n * @param {any} prop2\n * @returns {boolean}\n * @hidden\n */\nexport declare function aeqHelper(prop1: any, prop2: any): boolean;\n/**\n * Helper function for determining 'less-than' conditions for ops, sorting, and binary indices.\n *     In the future we might want $lt and $gt ops to use their own functionality/helper.\n *     Since binary indices on a property might need to index [12, NaN, new Date(), Infinity], we\n *     need this function (as well as gtHelper) to always ensure one value is LT, GT, or EQ to another.\n * @hidden\n */\nexport declare function ltHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @hidden\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} equal\n * @returns {boolean}\n */\nexport declare function gtHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} descending\n * @returns {number}\n * @hidden\n */\nexport declare function sortHelper(prop1: any, prop2: any, descending: boolean): number;\n/**\n * Default implementation of LokiOperatorPackage, using fastest javascript comparison operators.\n */\nexport declare class LokiOperatorPackage {\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n    $in(a: any, b: any): boolean;\n    $nin(a: any, b: any): boolean;\n    $keyin(a: string, b: object): boolean;\n    $nkeyin(a: string, b: object): boolean;\n    $definedin(a: string, b: object): boolean;\n    $undefinedin(a: string, b: object): boolean;\n    $regex(a: string, b: RegExp): boolean;\n    $containsNone(a: any, b: any): boolean;\n    $containsAny(a: any, b: any): boolean;\n    $contains(a: any, b: any): boolean;\n    $type(a: any, b: any): boolean;\n    $finite(a: number, b: boolean): boolean;\n    $size(a: any, b: any): boolean;\n    $len(a: any, b: any): boolean;\n    $where(a: any, b: any): boolean;\n    $not(a: any, b: any): boolean;\n    $and(a: any, b: any): boolean;\n    $or(a: any, b: any): boolean;\n    private doQueryOp(val, op);\n    private containsCheckFn(a);\n}\n/**\n * LokiOperatorPackage which utilizes abstract 'loki' comparisons for basic relational equality op implementations.\n */\nexport declare class LokiAbstractOperatorPackage extends LokiOperatorPackage {\n    constructor();\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * LokiOperatorPackage which utilizes provided comparator for basic relational equality op implementations.\n */\nexport declare class ComparatorOperatorPackage<T> extends LokiOperatorPackage {\n    comparator: ILokiComparer<T>;\n    constructor(comparator: ILokiComparer<T>);\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * Map/Register of named LokiOperatorPackages which implement all unindexed query ops within 'find' query objects\n */\nexport declare let LokiOperatorPackageMap: ILokiOperatorPackageMap;\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/loki/src/ranged_indexes.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\nexport declare type RangedValueOperator = \"$gt\" | \"$gte\" | \"$lt\" | \"$lte\" | \"$eq\" | \"$neq\" | \"$between\";\nexport interface IRangedIndexRequest<T> {\n    op: RangedValueOperator;\n    val: T;\n    high?: T;\n}\n/** Defines interface which all loki ranged indexes need to implement */\nexport interface IRangedIndex<T> {\n    insert(id: number, val: T): void;\n    update(id: number, val: T): void;\n    remove(id: number): void;\n    restore(tree: any): void;\n    backup(): IRangedIndex<T>;\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    validateIndex(): boolean;\n}\n/** Hash Interface for global ranged index factory map*/\nexport interface IRangedIndexFactoryMap {\n    [name: string]: (name: string, comparator: ILokiComparer<any>) => IRangedIndex<any>;\n}\n/** Map/Register of named factory functions returning IRangedIndex instances */\nexport declare let RangedIndexFactoryMap: IRangedIndexFactoryMap;\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/loki/src/result_set.d.ts",
    "content": "import { Collection } from \"./collection\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\nimport { Query as FullTextSearchQuery } from \"../../full-text-search/src/query_types\";\n/**\n * ResultSet class allowing chainable queries.  Intended to be instanced internally.\n *    Collection.find(), Collection.where(), and Collection.chain() instantiate this.\n *\n * @example\n *    mycollection.chain()\n *      .find({ 'doors' : 4 })\n *      .where(function(obj) { return obj.name === 'Toyota' })\n *      .data();\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class ResultSet<T extends object = object> {\n    _collection: Collection<T>;\n    _filteredRows: number[];\n    _filterInitialized: boolean;\n    private _scoring;\n    /**\n     * Constructor.\n     * @param {Collection} collection - the collection which this ResultSet will query against\n     */\n    constructor(collection: Collection<T>);\n    /**\n     * Reset the ResultSet to its initial state.\n     * @returns {ResultSet} Reference to this ResultSet, for future chain operations.\n     */\n    reset(): this;\n    /**\n     * Override of toJSON to avoid circular references\n     */\n    toJSON(): ResultSet<T>;\n    /**\n     * Allows you to limit the number of documents passed to next chain operation.\n     * A ResultSet copy() is made to avoid altering original ResultSet.\n     * @param {int} qty - The number of documents to return.\n     * @returns {ResultSet} Returns a copy of the ResultSet, limited by qty, for subsequent chain ops.\n     */\n    limit(qty: number): this;\n    /**\n     * Used for skipping 'pos' number of documents in the ResultSet.\n     * @param {int} pos - Number of documents to skip; all preceding documents are filtered out.\n     * @returns {ResultSet} Returns a copy of the ResultSet, containing docs starting at 'pos' for subsequent chain ops.\n     */\n    offset(pos: number): this;\n    /**\n     * To support reuse of ResultSet in branched query situations.\n     * @returns {ResultSet} Returns a copy of the ResultSet (set) but the underlying document references will be the same.\n     */\n    copy(): ResultSet<T>;\n    /**\n     * Executes a named collection transform or raw array of transform steps against the ResultSet.\n     * @param {(string|array)} transform - name of collection transform or raw transform array\n     * @param {object} [parameters=] - object property hash of parameters, if the transform requires them.\n     * @returns {ResultSet} either (this) ResultSet or a clone of of this ResultSet (depending on steps)\n     */\n    transform(transform: string | Collection.Transform<T>[], parameters?: object): this;\n    /**\n     * User supplied compare function is provided two documents to compare. (chainable)\n     * @example\n     *    rslt.sort(function(obj1, obj2) {\n       *      if (obj1.name === obj2.name) return 0;\n       *      if (obj1.name > obj2.name) return 1;\n       *      if (obj1.name < obj2.name) return -1;\n       *    });\n     * @param {function} comparefun - A javascript compare function used for sorting.\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    sort(comparefun: (a: Doc<T>, b: Doc<T>) => number): this;\n    /**\n     * Simpler, loose evaluation for user to sort based on a property name. (chainable).\n     * Sorting based on the same lt/gt helper functions used for binary indices.\n     * @param {string} propname - name of property to sort by.\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether to sort descending\n     * @param {string} [options.sortComparator] override default with name of comparator registered in ComparatorMap\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    simplesort(propname: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * rs.compoundsort(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * rs.compoundsort(['age', ['name', true]);\n     * @param {array} properties - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    compoundsort(properties: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Helper function for compoundsort(), performing individual object comparisons\n     * @param {Array} properties - array of property names, in order, by which to evaluate sort order\n     * @param {object} obj1 - first object to compare\n     * @param {object} obj2 - second object to compare\n     * @returns {number} 0, -1, or 1 to designate if identical (sortwise) or which should be first\n     */\n    private _compoundeval(properties, obj1, obj2);\n    /**\n     * Sorts the ResultSet based on the last full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     * @returns {ResultSet}\n     */\n    sortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Oversee the operation of OR'ed query expressions.\n     * OR'ed expression evaluation runs each expression individually against the full collection,\n     * and finally does a set OR on each expression's results.\n     * Each evaluation can utilize a binary index to prevent multiple linear array scans.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findOr(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $or(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Oversee the operation of AND'ed query expressions.\n     * AND'ed expression evaluation runs each expression progressively against the full collection,\n     * internally utilizing existing chained ResultSet functionality.\n     * Only the first filter can utilize a binary index.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findAnd(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $and(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Used for querying via a mongo-style query object.\n     *\n     * @param {object} query - A mongo-style query object used for filtering current results.\n     * @param {boolean} firstOnly - (Optional) Used by collection.findOne() - flag if this was invoked via findOne()\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    find(query?: ResultSet.Query<Doc<T>>, firstOnly?: boolean): this;\n    /**\n     * Used for filtering via a javascript filter function.\n     * @param {function} fun - A javascript function used for filtering current results by.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    where(fun: (obj: Doc<T>) => boolean): this;\n    /**\n     * Returns the number of documents in the ResultSet.\n     * @returns {number} The number of documents in the ResultSet.\n     */\n    count(): number;\n    /**\n     * Terminates the chain and returns array of filtered documents\n     * @param {object} options\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values 'parse-stringify', 'deep', and 'shallow' and\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} Array of documents in the ResultSet\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * Used to run an update operation on all documents currently in the ResultSet.\n     * @param {function} updateFunction - User supplied updateFunction(obj) will be executed for each document object.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    update(updateFunction: (obj: Doc<T>) => Doc<T>): this;\n    /**\n     * Removes all document objects which are currently in ResultSet from collection (as well as ResultSet)\n     * @returns {ResultSet} this (empty) ResultSet for further chain ops.\n     */\n    remove(): this;\n    /**\n     * data transformation via user supplied functions\n     *\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns {value} The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Left joining two sets of data. Join keys can be defined or calculated properties\n     * eqJoin expects the right join key values to be unique.  Otherwise left data will be joined on the last joinData object with that key\n     * @param {Array|ResultSet|Collection} joinData - Data array to join to.\n     * @param {(string|function)} leftJoinKey - Property name in this result set to join on or a function to produce a value to join on\n     * @param {(string|function)} rightJoinKey - Property name in the joinData to join on or a function to produce a value to join on\n     * @param {function} [mapFun=] - a function that receives each matching pair and maps them into output objects - function(left,right){return joinedObject}\n     * @param {object} [dataOptions=] - optional options to apply to data() calls for left and right sides\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} A ResultSet with data in the format [{left: leftObj, right: rightObj}]\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinKey: string | ((obj: any) => string), rightJoinKey: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * Applies a map function into a new collection for further chaining.\n     * @param {function} mapFun - javascript map function\n     * @param {object} [dataOptions=] - options to data() before input to your map function\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - Allows overriding the default or collection specified cloning method\n     * @return {ResultSet}\n     */\n    map<U extends object>(mapFun: (obj: Doc<T>, index: number, array: Doc<T>[]) => U, dataOptions?: ResultSet.DataOptions): ResultSet<U>;\n}\nexport declare namespace ResultSet {\n    interface DataOptions {\n        forceClones?: boolean;\n        forceCloneMethod?: CloneMethod;\n        removeMeta?: boolean;\n    }\n    interface SimpleSortOptions {\n        desc?: boolean;\n        sortComparator?: string;\n    }\n    type ContainsHelperType<R> = R extends string ? string | string[] : R extends any[] ? R[number] | R[number][] : R extends object ? keyof R | (keyof R)[] : never;\n    type LokiOps<R> = {\n        $eq?: R;\n    } | {\n        $ne?: R;\n    } | {\n        $gt?: R;\n    } | {\n        $gte?: R;\n    } | {\n        $lt?: R;\n    } | {\n        $lte?: R;\n    } | {\n        $between?: [R, R];\n    } | {\n        $in?: R[];\n    } | {\n        $nin?: R[];\n    } | {\n        $keyin?: object;\n    } | {\n        $nkeyin?: object;\n    } | {\n        $definedin?: object;\n    } | {\n        $undefinedin?: object;\n    } | {\n        $regex?: RegExp | string | [string, string];\n    } | {\n        $containsNone?: ContainsHelperType<R>;\n    } | {\n        $containsAny?: ContainsHelperType<R>;\n    } | {\n        $contains?: ContainsHelperType<R>;\n    } | {\n        $type?: string;\n    } | {\n        $finite?: boolean;\n    } | {\n        $size?: number;\n    } | {\n        $len?: number;\n    } | {\n        $where?: (val?: R) => boolean;\n    };\n    type Query<T> = {\n        [P in keyof T]?: LokiOps<T[P]> | T[P];\n    } & {\n        $and?: Query<T>[];\n    } & {\n        $or?: Query<T>[];\n    } & {\n        $fts?: FullTextSearchQuery;\n    };\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/loki/src/unique_index.d.ts",
    "content": "export declare class UniqueIndex {\n    private _field;\n    private _lokiMap;\n    private _valMap;\n    /**\n     * Constructs an unique index object.\n     * @param {string} propertyField - the property field to index\n     */\n    constructor(propertyField: string);\n    /**\n     * Sets a document's unique index.\n     * @param {number} id loki id to associate with value\n     * @param {*} value  value to associate with id\n     */\n    set(id: number, value: any): void;\n    /**\n     * Returns the $loki id of an unique value.\n     * @param {*} value the value to retrieve a loki id match for\n     */\n    get(value: any): number;\n    /**\n     * Updates a document's unique index.\n     * @param {number} id (loki) id of document to update the value to\n     * @param {*} value value to associate with loki id\n     */\n    update(id: number, value: any): void;\n    /**\n     * Removes an unique index.\n     * @param {number} id (loki) id to remove from index\n     */\n    remove(id: number): void;\n    /**\n     * Clears the unique index.\n     */\n    clear(): void;\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/memory-storage/src/index.d.ts",
    "content": "import { MemoryStorage } from \"./memory_storage\";\nexport { MemoryStorage };\nexport default MemoryStorage;\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/memory-storage/src/memory_storage.d.ts",
    "content": "import { Dict, StorageAdapter } from \"../../common/types\";\n/**\n * An in-memory persistence adapter for an in-memory database.\n * This simple 'key/value' adapter is intended for unit testing and diagnostics.\n */\nexport declare class MemoryStorage implements StorageAdapter {\n    hashStore: Dict<{\n        savecount: number;\n        lastsave: Date;\n        value: string;\n    }>;\n    options: MemoryStorage.Options;\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} options - memory storage options\n     * @param {boolean} [options.asyncResponses=false] - whether callbacks are invoked asynchronously (default: false)\n     * @param {int} [options.asyncTimeout=50] - timeout in ms to queue callbacks (default: 50)\n     */\n    constructor(options?: MemoryStorage.Options);\n    /**\n     * Loads a serialized database from its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * Saves a serialized database to its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {string} dbstring - the database content\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a database from its in-memory store.\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport declare namespace MemoryStorage {\n    interface Options {\n        asyncResponses?: boolean;\n        asyncTimeout?: number;\n    }\n}\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/partitioning-adapter/src/index.d.ts",
    "content": "import { PartitioningAdapter } from \"./partitioning_adapter\";\nexport { PartitioningAdapter };\nexport default PartitioningAdapter;\n"
  },
  {
    "path": "dist/packages/indexed-storage/types/partitioning-adapter/src/partitioning_adapter.d.ts",
    "content": "import { Loki } from \"../../loki/src/loki\";\nimport { StorageAdapter } from \"../../common/types\";\n/**\n * An adapter for adapters. Converts a non reference mode adapter into a reference mode adapter\n * which can perform destructuring and partitioning. Each collection will be stored in its own key/save and\n * only dirty collections will be saved. If you  turn on paging with default page size of 25megs and save\n * a 75 meg collection it should use up roughly 3 save slots (key/value pairs sent to inner adapter).\n * A dirty collection that spans three pages will save all three pages again\n * Paging mode was added mainly because Chrome has issues saving 'too large' of a string within a\n * single IndexedDB row. If a single document update causes the collection to be flagged as dirty, all\n * of that collection's pages will be written on next save.\n */\nexport declare class PartitioningAdapter implements StorageAdapter {\n    mode: string;\n    private _adapter;\n    private _dbref;\n    private _dbname;\n    private _pageIterator;\n    private _paging;\n    private _pageSize;\n    private _delimiter;\n    private _dirtyPartitions;\n    /**\n     * Registers the partitioning adapter as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the partitioning storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} adapter - reference to a 'non-reference' mode loki adapter instance.\n     * @param {boolean} paging - (default: false) set to true to enable paging collection data.\n     * @param {number} pageSize - (default : 25MB) you can use this to limit size of strings passed to inner adapter.\n     * @param {string} delimiter - allows you to override the default delimiter\n     */\n    constructor(adapter: StorageAdapter, {paging, pageSize, delimiter}?: {\n        paging?: boolean;\n        pageSize?: number;\n        delimiter?: string;\n    });\n    /**\n     * Loads a database which was partitioned into several key/value saves.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Used to sequentially load each collection partition, one at a time.\n     *\n     * @param {int} partition - ordinal collection position to load next\n     * @returns {Promise} a Promise that resolves after the next partition is loaded\n     */\n    private _loadNextPartition(partition);\n    /**\n     * Used to sequentially load the next page of collection partition, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next page is loaded\n     */\n    private _loadNextPage();\n    /**\n     * Saves a database by partioning into separate key/value saves.\n     * (Loki 'reference mode' persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {object} dbref - reference to database which we will partition and save.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     *\n     */\n    exportDatabase(dbname: string, dbref: Loki): Promise<void>;\n    /**\n     * Helper method used internally to save each dirty collection, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPartition();\n    /**\n     * Helper method used internally to generate and save the next page of the current (dirty) partition.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPage();\n}\n"
  },
  {
    "path": "dist/packages/local-storage/lokidb.local-storage.js",
    "content": "(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"@lokidb/local-storage\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"@lokidb/local-storage\"] = factory();\n\telse\n\t\t{ root[\"@lokidb/local-storage\"] = factory(); root[\"LokiLocalStorage\"] = root[\"@lokidb/local-storage\"].default; }\n})(typeof self !== 'undefined' ? self : this, function() {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// define __esModule on exports\n/******/ \t__webpack_require__.r = function(exports) {\n/******/ \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n/******/ \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n/******/ \t\t}\n/******/ \t\tObject.defineProperty(exports, '__esModule', { value: true });\n/******/ \t};\n/******/\n/******/ \t// create a fake namespace object\n/******/ \t// mode & 1: value is a module id, require it\n/******/ \t// mode & 2: merge all properties of value into the ns\n/******/ \t// mode & 4: return value when already ns object\n/******/ \t// mode & 8|1: behave like require\n/******/ \t__webpack_require__.t = function(value, mode) {\n/******/ \t\tif(mode & 1) value = __webpack_require__(value);\n/******/ \t\tif(mode & 8) return value;\n/******/ \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n/******/ \t\tvar ns = Object.create(null);\n/******/ \t\t__webpack_require__.r(ns);\n/******/ \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n/******/ \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n/******/ \t\treturn ns;\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 1);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return PLUGINS; });\nfunction getGlobal() {\n    let glob;\n    (function (global) {\n        glob = global;\n    })(global !== undefined && global || this);\n    return glob;\n}\nfunction create() {\n    const global = getGlobal();\n    const sym = Symbol.for(\"LOKI\");\n    if (global[sym] === undefined) {\n        global[sym] = {};\n    }\n    return global[sym];\n}\n/**\n * @hidden\n */\nconst PLUGINS = create();\n\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(2)))\n\n/***/ }),\n/* 1 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n\n// EXTERNAL MODULE: ./packages/common/plugin.ts\nvar common_plugin = __webpack_require__(0);\n\n// CONCATENATED MODULE: ./packages/local-storage/src/local_storage.ts\n\n/**\n * A loki persistence adapter which persists to web browser's local storage object\n * @constructor LocalStorageAdapter\n */\nclass local_storage_LocalStorage {\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register() {\n        common_plugin[\"a\" /* PLUGINS */][\"LocalStorage\"] = local_storage_LocalStorage;\n    }\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister() {\n        delete common_plugin[\"a\" /* PLUGINS */][\"LocalStorage\"];\n    }\n    /**\n     * loadDatabase() - Load data from localstorage\n     * @param {string} dbname - the name of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname) {\n        return Promise.resolve(localStorage.getItem(dbname));\n    }\n    /**\n     * saveDatabase() - save data to localstorage, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was saved\n     */\n    saveDatabase(dbname, dbstring) {\n        return Promise.resolve(localStorage.setItem(dbname, dbstring));\n    }\n    /**\n     * deleteDatabase() - delete the database from localstorage, will throw an error if it\n     * can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname) {\n        return Promise.resolve(localStorage.removeItem(dbname));\n    }\n}\n/* harmony default export */ var local_storage = (local_storage_LocalStorage);\n\n// CONCATENATED MODULE: ./packages/local-storage/src/index.ts\n/* concated harmony reexport */__webpack_require__.d(__webpack_exports__, \"LocalStorage\", function() { return local_storage_LocalStorage; });\n\n\n/* harmony default export */ var src = __webpack_exports__[\"default\"] = (local_storage_LocalStorage);\n\n\n/***/ }),\n/* 2 */\n/***/ (function(module, exports) {\n\nvar g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || Function(\"return this\")() || (1, eval)(\"this\");\n} catch (e) {\n\t// This works if the window reference is available\n\tif (typeof window === \"object\") g = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n\n\n/***/ })\n/******/ ]);\n});\n//# sourceMappingURL=lokidb.local-storage.js.map"
  },
  {
    "path": "dist/packages/local-storage/types/common/plugin.d.ts",
    "content": "/**\n * @hidden\n */\nexport declare const PLUGINS: void;\n"
  },
  {
    "path": "dist/packages/local-storage/types/common/types.d.ts",
    "content": "/**\n * @hidden\n */\nimport { Loki } from \"../loki/src/loki\";\nexport interface StorageAdapter {\n    loadDatabase(dbname: string): Promise<any>;\n    saveDatabase?(dbname: string, serialization: string): Promise<void>;\n    deleteDatabase?(dbname: string): Promise<void>;\n    mode?: string;\n    exportDatabase?(dbname: string, dbref: Loki): Promise<void>;\n}\nexport declare type Doc<T extends object = object> = T & {\n    $loki: number;\n    meta?: {\n        created: number;\n        revision: number;\n        version: number;\n        updated?: number;\n    };\n};\nexport interface Dict<T> {\n    [index: string]: T;\n    [index: number]: T;\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/fs-storage/src/fs_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists using node fs module.\n */\nexport declare class FSStorage implements StorageAdapter {\n    /**\n     * Registers the fs storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the fs storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * Load data from file, will throw an error if the file does not exist\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Save data to file, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Delete the database file, will throw an error if the\n     * file can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/fs-storage/src/index.d.ts",
    "content": "import { FSStorage } from \"./fs_storage\";\nexport { FSStorage };\nexport default FSStorage;\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search/src/analyzer/analyzer.d.ts",
    "content": "import { CharacterFilter } from \"./character_filter\";\nimport { Tokenizer, whitespaceTokenizer } from \"./tokenizer\";\nimport { lowercaseTokenFilter, TokenFilter } from \"./token_filter\";\n/**\n * A analyzer converts a string into tokens which are added to the inverted index for searching.\n */\nexport interface Analyzer {\n    /**\n     * The character filters of the analyzer.\n     */\n    char_filter?: CharacterFilter[];\n    /**\n     * The tokenizer of the analyzer.\n     */\n    tokenizer: Tokenizer;\n    /**\n     * The token filters of the analyzer.\n     */\n    token_filter?: TokenFilter[];\n}\n/**\n * Analyzes a given string.\n * @param {Analyzer} analyzer - the analyzer\n * @param {string} str - the string\n * @returns {string[]} - the tokens\n */\nexport declare function analyze(analyzer: Analyzer, str: string): string[];\n/**\n * An analyzer with the whitespace tokenizer and the lowercase token filter.\n */\nexport declare class StandardAnalyzer implements Analyzer {\n    tokenizer: typeof whitespaceTokenizer;\n    token_filter: (typeof lowercaseTokenFilter)[];\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search/src/analyzer/character_filter.d.ts",
    "content": "/**\n * A character filter is used to preprocess a string before it is passed to a tokenizer.\n */\nexport declare type CharacterFilter = (value: string) => string;\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search/src/analyzer/token_filter.d.ts",
    "content": "/**\n * A token filter takes tokens from a tokenizer and modify, delete or add tokens.\n */\nexport declare type TokenFilter = (value: string, index: number, array: string[]) => string;\n/**\n * Converts a token to lowercase.\n * @param {string} token - the token\n * @returns {string} - the lowercased token\n */\nexport declare function lowercaseTokenFilter(token: string): string;\n/**\n * Converts a token to uppercase.\n * @param {string} token - the token\n * @returns {string} - the uppercased token\n */\nexport declare function uppercaseTokenFilter(token: string): string;\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search/src/analyzer/tokenizer.d.ts",
    "content": "/**\n * A tokenizer splits a string into individual tokens.\n */\nexport declare type Tokenizer = (value: string) => string[];\n/**\n * Splits a string at whitespace characters into tokens.\n * @param {string} value - the string\n * @returns {string[]} - the tokens\n */\nexport declare function whitespaceTokenizer(value: string): string[];\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search/src/full_text_search.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\nimport { Scorer } from \"./scorer\";\nimport { Analyzer } from \"./analyzer/analyzer\";\nexport declare class FullTextSearch {\n    private _id;\n    private _docs;\n    private _idxSearcher;\n    private _invIdxs;\n    /**\n     * Registers the full-text search as plugin.\n     */\n    static register(): void;\n    /**\n     * Initialize the full-text search for the given fields.\n     * @param {object[]} fieldOptions - the field options\n     * @param {string} fieldOptions.field - the name of the property field\n     * @param {boolean=true} fieldOptions.store - flag to indicate if the full-text search should be stored on serialization or\n     *  rebuild on deserialization\n     * @param {boolean=true} fieldOptions.optimizeChanges - flag to optimize updating and deleting of documents\n     *    (requires more memory but performs faster)\n     * @param {Analyzer} fieldOptions.analyzer - an analyzer for the field\n     * @param {string} [id] - the property name of the document index\n     */\n    constructor(fieldOptions?: FullTextSearch.FieldOptions[], id?: string);\n    addDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    removeDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    updateDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    clear(): void;\n    search(query: Query): Scorer.ScoreResults;\n    toJSON(): FullTextSearch.Serialization;\n    static fromJSONObject(serialized: FullTextSearch.Serialization, analyzers?: Dict<Analyzer>): FullTextSearch;\n}\nexport declare namespace FullTextSearch {\n    interface FieldOptions extends InvertedIndex.FieldOptions {\n        field: string;\n    }\n    interface Serialization {\n        id: string;\n        ii: Dict<InvertedIndex.Serialization>;\n    }\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search/src/fuzzy/automaton.d.ts",
    "content": "/**\n * Transition with dest, min and max.\n * @hidden\n */\nexport declare type Transition = [number, number, number];\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MIN_CODE_POINT = 0;\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MAX_CODE_POINT = 1114111;\n/**\n * From org/apache/lucene/util/automaton/Automaton.java\n * @hidden\n */\nexport declare class Automaton {\n    private _stateTransitions;\n    private _accept;\n    private _nextState;\n    private _currState;\n    private _transitions;\n    constructor();\n    isAccept(n: number): boolean;\n    createState(): number;\n    setAccept(state: number, accept: boolean): void;\n    finishState(): void;\n    private _finishCurrentState();\n    getStartPoints(): number[];\n    step(state: number, label: number): number;\n    getNumStates(): number;\n    addTransition(source: number, dest: number, min: number, max: number): void;\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search/src/fuzzy/lev1t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev1TParametricDescription.java\n * @hidden\n */\nexport declare class Lev1TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search/src/fuzzy/lev2t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev2TParametricDescription.java\n * @hidden\n */\nexport declare class Lev2TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search/src/fuzzy/levenshtein_automata.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java\n * @hidden\n */\nexport declare class LevenshteinAutomata {\n    private _word;\n    private _numRanges;\n    private _rangeLower;\n    private _rangeUpper;\n    private _description;\n    private _alphabet;\n    private _editDistance;\n    constructor(input: number[], editDistance: number);\n    /**\n     * Transforms the NDFA to a DFA.\n     * @returns {Automaton}\n     */\n    toAutomaton(): Automaton;\n    private _getVector(x, pos, end);\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search/src/fuzzy/long.d.ts",
    "content": "/**\n * Class supports 64Bit integer operations.\n * A cut-down version of dcodeIO/long.js.\n * @hidden\n */\nexport declare class Long {\n    private _low;\n    private _high;\n    constructor(low?: number, high?: number);\n    /**\n     * Returns this long with bits arithmetically shifted to the right by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftRight(numBits: number): Long;\n    /**\n     * Returns this long with bits arithmetically shifted to the left by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftLeft(numBits: number): Long;\n    /**\n     * Returns the bitwise AND of this Long and the specified.\n     * @param {Long} other - the other Long\n     * @returns {Long} the long\n     */\n    and(other: Long): Long;\n    /**\n     * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.\n     * @returns {number}\n     */\n    toInt(): number;\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search/src/fuzzy/parametric_description.d.ts",
    "content": "import { Long } from \"./long\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java#ParametricDescription\n * @hidden\n */\nexport declare class ParametricDescription {\n    protected _w: number;\n    private _n;\n    private _minErrors;\n    constructor(w: number, n: number, minErrors: number[]);\n    /**\n     * Return the number of states needed to compute a Levenshtein DFA\n     */\n    size(): number;\n    /**\n     * Returns true if the <code>state</code> in any Levenshtein DFA is an accept state (final state).\n     */\n    isAccept(absState: number): boolean;\n    /**\n     * Returns the position in the input word for a given <code>state</code>.\n     * This is the minimal boundary for the state.\n     */\n    getPosition(absState: number): number;\n    static unpack(data: Long[], index: number, bitsPerValue: number): number;\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search/src/fuzzy/run_automaton.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/RunAutomaton.java\n * @hidden\n */\nexport declare class RunAutomaton {\n    private _points;\n    private _accept;\n    private _transitions;\n    private _classmap;\n    constructor(automaton: Automaton);\n    getCharClass(c: number): number;\n    step(state: number, c: number): number;\n    isAccept(state: number): boolean;\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search/src/index.d.ts",
    "content": "import { FullTextSearch } from \"./full_text_search\";\nimport { analyze, StandardAnalyzer } from \"./analyzer/analyzer\";\nimport { whitespaceTokenizer } from \"./analyzer/tokenizer\";\nimport { lowercaseTokenFilter, uppercaseTokenFilter } from \"./analyzer/token_filter\";\nexport { FullTextSearch, analyze, StandardAnalyzer, whitespaceTokenizer, lowercaseTokenFilter, uppercaseTokenFilter };\nexport default FullTextSearch;\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search/src/index_searcher.d.ts",
    "content": "import { Scorer } from \"./scorer\";\nimport { InvertedIndex } from \"./inverted_index\";\nimport { Query } from \"./query_types\";\nimport { Dict } from \"../../common/types\";\n/**\n * @hidden\n */\nexport declare class IndexSearcher {\n    private _invIdxs;\n    private _docs;\n    private _scorer;\n    /**\n     * Constructs an index searcher.\n     * @param {Dict<InvertedIndex>} invIdxs - the inverted indexes\n     * @param {Set<number>} docs - the ids of the documents\n     */\n    constructor(invIdxs: Dict<InvertedIndex>, docs: Set<InvertedIndex.DocumentIndex>);\n    search(query: Query): Scorer.ScoreResults;\n    setDirty(): void;\n    private _recursive(query, doScoring);\n    private _getUnique(queries, doScoring, queryResults);\n    private _getAll(queries, doScoring, queryResults?);\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search/src/inverted_index.d.ts",
    "content": "import { Analyzer } from \"./analyzer/analyzer\";\n/**\n * Converts a string into an array of code points.\n * @param str - the string\n * @returns {number[]} to code points\n * @hidden\n */\nexport declare function toCodePoints(str: string): number[];\n/**\n * Inverted index class handles featured text search for specific document fields.\n * @hidden\n */\nexport declare class InvertedIndex {\n    analyzer: Analyzer;\n    docCount: number;\n    docStore: Map<InvertedIndex.DocumentIndex, InvertedIndex.DocStore>;\n    totalFieldLength: number;\n    root: InvertedIndex.Index;\n    private _store;\n    private _optimizeChanges;\n    /**\n     * @param {boolean} [options.store=true] - inverted index will be stored at serialization rather than rebuilt on load\n     * @param {boolean} [options.optimizeChanges=true] - flag to store additional metadata inside the index for better\n     *  performance if an existing field is updated or removed\n     * @param {Analyzer} [options.analyzer=] - the analyzer of this inverted index\n     */\n    constructor(options?: InvertedIndex.FieldOptions);\n    /**\n     * Adds defined fields of a document to the inverted index.\n     * @param {string} field - the field to add\n     * @param {number} docId - the doc id of the field\n     */\n    insert(field: string, docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Removes all relevant terms of a document from the inverted index.\n     * @param {number} docId - the document.\n     */\n    remove(docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Gets the term index of a term.\n     * @param {string} term - the term\n     * @param {object} root - the term index to start from\n     * @param {number} start - the position of the term string to start from\n     * @return {object} - The term index or null if the term is not in the term tree.\n     */\n    static getTermIndex(term: number[], root: InvertedIndex.Index, start?: number): InvertedIndex.Index;\n    /**\n     * Extends a term index to all available term leafs.\n     * @param {object} idx - the term index to start from\n     * @param {number[]} [term=[]] - the current term\n     * @param {Array} termIndices - all extended indices with their term\n     * @returns {Array} - Array with term indices and extension\n     */\n    static extendTermIndex(idx: InvertedIndex.Index, term?: number[], termIndices?: InvertedIndex.IndexTerm[]): InvertedIndex.IndexTerm[];\n    /**\n     * Serialize the inverted index.\n     * @returns {{docStore: *, _fields: *, index: *}}\n     */\n    toJSON(): InvertedIndex.Serialization;\n    /**\n     * Deserialize the inverted index.\n     * @param {{docStore: *, _fields: *, index: *}} serialized - The serialized inverted index.\n     * @param {Analyzer} analyzer[undefined] - an analyzer\n     */\n    static fromJSONObject(serialized: InvertedIndex.Serialization, analyzer?: Analyzer): InvertedIndex;\n    private static _serializeIndex(idx);\n    private static _deserializeIndex(serialized);\n    /**\n     * Set parent of to each index and regenerate the indexRef.\n     * @param {Index} index - the index\n     * @param {Index} parent - the parent\n     */\n    private _regenerate(index, parent);\n    /**\n     * Iterate over the whole inverted index and remove the document.\n     * Delete branch if not needed anymore.\n     * Function is needed if index is used without optimization.\n     * @param {Index} idx - the index\n     * @param {number} docId - the doc id\n     * @returns {boolean} true if index is empty\n     */\n    private _remove(idx, docId);\n}\nexport declare namespace InvertedIndex {\n    interface FieldOptions {\n        store?: boolean;\n        optimizeChanges?: boolean;\n        analyzer?: Analyzer;\n    }\n    type Index = Map<number, any> & {\n        dc?: Map<DocumentIndex, number>;\n        df?: number;\n        pa?: Index;\n    };\n    type IndexTerm = {\n        index: Index;\n        term: number[];\n    };\n    interface SerializedIndex {\n        d?: {\n            df: number;\n            dc: [DocumentIndex, number][];\n        };\n        k?: number[];\n        v?: SerializedIndex[];\n    }\n    type Serialization = SpareSerialization | FullSerialization;\n    type SpareSerialization = {\n        _store: false;\n        _optimizeChanges: boolean;\n    };\n    type FullSerialization = {\n        _store: true;\n        _optimizeChanges: boolean;\n        docCount: number;\n        docStore: [DocumentIndex, DocStore][];\n        totalFieldLength: number;\n        root: SerializedIndex;\n    };\n    interface DocStore {\n        fieldLength?: number;\n        indexRef?: Index[];\n    }\n    type DocumentIndex = number | string;\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search/src/query_types.d.ts",
    "content": "/**\n * Base query to enable boost to a query type.\n */\nexport interface BaseQuery<Type> {\n    type: Type;\n    boost?: number;\n}\n/**\n * A query which finds documents where a document field contains a term.\n */\nexport interface TermQuery extends BaseQuery<\"term\"> {\n    field: string;\n    value: string;\n}\n/**\n * A query which finds documents where a document field contains any of the terms.\n */\nexport interface TermsQuery extends BaseQuery<\"terms\"> {\n    field: string;\n    value: string[];\n}\n/**\n * A query which finds documents where the wildcard term can be applied at an existing document field term.\n */\nexport interface WildcardQuery extends BaseQuery<\"wildcard\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which finds documents where the fuzzy term can be transformed into an existing document field term within a\n * given edit distance.\n */\nexport interface FuzzyQuery extends BaseQuery<\"fuzzy\"> {\n    field: string;\n    value: string;\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query which matches documents containing the prefix of a term inside a field.\n */\nexport interface PrefixQuery extends BaseQuery<\"prefix\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which matches all documents with a given field.\n */\nexport interface ExistsQuery extends BaseQuery<\"exists\"> {\n    field: string;\n}\n/**\n * A query which tokenizes the given text into tokens and performs a sub query for each token. The results are combined\n * using a boolean operator.\n */\nexport interface MatchQuery extends BaseQuery<\"match\"> {\n    field: string;\n    value: string;\n    minimum_should_match?: number | string;\n    operator?: \"and\" | \"or\";\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query that matches all documents and giving them a constant score equal to the query boost.\n*/\nexport interface MatchQueryAll extends BaseQuery<\"match_all\"> {\n}\n/**\n * A query that wraps sub queries and returns a constant score equal to the query boost for every document in the filter.\n */\nexport interface ConstantScoreQuery extends BaseQuery<\"constant_score\"> {\n    filter: QueryTypes[];\n}\n/**\n * A query that matches documents matching boolean combinations of sub queries.\n */\nexport interface BoolQuery extends BaseQuery<\"bool\"> {\n    must?: QueryTypes[];\n    filter?: QueryTypes[];\n    should?: QueryTypes[];\n    not?: QueryTypes[];\n    minimum_should_match?: number | string;\n}\n/**\n * Union type of possible query types.\n */\nexport declare type QueryTypes = BoolQuery | ConstantScoreQuery | TermQuery | TermsQuery | WildcardQuery | FuzzyQuery | MatchQuery | MatchQueryAll | PrefixQuery | ExistsQuery;\n/**\n * The main query with the actually full-text search query and the scoring parameters.\n */\nexport interface Query {\n    query: QueryTypes;\n    calculate_scoring?: boolean;\n    explain?: boolean;\n    bm25?: {\n        k1: number;\n        b: number;\n    };\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search/src/scorer.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\n/**\n * @hidden\n */\nexport declare class Scorer {\n    private _invIdxs;\n    private _cache;\n    constructor(invIdxs: Dict<InvertedIndex>);\n    setDirty(): void;\n    score(fieldName: string, boost: number, termIdx: InvertedIndex.Index, doScoring: boolean | null, queryResults: Scorer.QueryResults, term: number[], df?: number): void;\n    scoreConstant(boost: number, docId: InvertedIndex.DocumentIndex, queryResults: Scorer.QueryResults): Scorer.QueryResults;\n    finalScore(query: Query, queryResults: Scorer.QueryResults): Scorer.ScoreResults;\n    private static _calculateFieldLength(fieldLength);\n    private _getCache(fieldName);\n    /**\n     * Returns the idf by either calculate it or use a cached one.\n     * @param {string} fieldName - the name of the field\n     * @param {number} docFreq - the doc frequency of the term\n     * @returns {number} the idf\n     * @private\n     */\n    private _idf(fieldName, docFreq);\n    private _avgFieldLength(fieldName);\n}\nexport declare namespace Scorer {\n    interface IDFCache {\n        idfs: Dict<number>;\n        avgFieldLength: number;\n    }\n    interface QueryResult {\n        tf?: number;\n        idf?: number;\n        boost: number;\n        fieldName?: string;\n        term?: number[];\n    }\n    type QueryResults = Map<InvertedIndex.DocumentIndex, QueryResult[]>;\n    interface BM25Explanation {\n        boost: number;\n        score: number;\n        docID: number;\n        fieldName: string;\n        index: string;\n        idf: number;\n        tfNorm: number;\n        tf: number;\n        fieldLength: number;\n        avgFieldLength: number;\n    }\n    interface ConstantExplanation {\n        boost: number;\n        score: number;\n    }\n    type ScoreExplanation = BM25Explanation | ConstantExplanation;\n    type ScoreResult = {\n        score: number;\n        explanation?: ScoreExplanation[];\n    };\n    type ScoreResults = Dict<ScoreResult>;\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search-language/src/index.d.ts",
    "content": "export { generateStopWordFilter, generateTrimmer, Among, SnowballProgram } from \"./language\";\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search-language/src/language.d.ts",
    "content": "export declare function generateTrimmer(wordCharacters: string): (token: string) => string;\nexport declare function generateStopWordFilter(stopWords: string[]): (token: string) => string;\nexport declare class Among {\n    s_size: number;\n    s: number[];\n    substring_i: number;\n    result: number;\n    method: any;\n    constructor(s: string, substring_i: number, result: number, method?: any);\n}\nexport declare class SnowballProgram {\n    current: string;\n    bra: number;\n    ket: number;\n    limit: number;\n    cursor: number;\n    limit_backward: number;\n    constructor();\n    setCurrent(word: string): void;\n    getCurrent(): string;\n    in_grouping(s: number[], min: number, max: number): boolean;\n    in_grouping_b(s: number[], min: number, max: number): boolean;\n    out_grouping(s: number[], min: number, max: number): boolean;\n    out_grouping_b(s: number[], min: number, max: number): boolean;\n    eq_s(s_size: number, s: string): boolean;\n    eq_s_b(s_size: number, s: string): boolean;\n    find_among(v: Among[], v_size: number): number;\n    find_among_b(v: Among[], v_size: number): number;\n    replace_s(c_bra: number, c_ket: number, s: string): number;\n    slice_check(): void;\n    slice_from(s: string): void;\n    slice_del(): void;\n    insert(c_bra: number, c_ket: number, s: string): void;\n    slice_to(): string;\n    eq_v_b(s: string): boolean;\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search-language-de/src/german_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class GermanAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search-language-de/src/index.d.ts",
    "content": "import { GermanAnalyzer } from \"./german_analyzer\";\nexport { GermanAnalyzer };\nexport default GermanAnalyzer;\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search-language-en/src/english_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class EnglishAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/full-text-search-language-en/src/index.d.ts",
    "content": "import { EnglishAnalyzer } from \"./english_analyzer\";\nexport { EnglishAnalyzer };\nexport default EnglishAnalyzer;\n"
  },
  {
    "path": "dist/packages/local-storage/types/indexed-storage/src/index.d.ts",
    "content": "import { IndexedStorage } from \"./indexed_storage\";\nexport { IndexedStorage };\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/local-storage/types/indexed-storage/src/indexed_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * Loki persistence adapter class for indexedDb.\n *     This class fulfills abstract adapter interface which can be applied to other storage methods.\n *     Utilizes the included LokiCatalog app/key/value database for actual database persistence.\n *     IndexedDb storage is provided per-domain, so we implement app/key/value database to\n *     allow separate contexts for separate apps within a domain.\n */\nexport declare class IndexedStorage implements StorageAdapter {\n    private _appname;\n    private catalog;\n    /**\n     * Registers the indexed storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the indexed storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {string} [appname=loki] - Application name context can be used to distinguish subdomains, \"loki\" by default\n     */\n    constructor(appname?: string);\n    /**\n     * Retrieves a serialized db string from the catalog.\n     *\n     * @example\n     * // LOAD\n     * var idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * var db = new loki(\"test\", { adapter: idbAdapter });\n     *   db.base(function(result) {\n       *   console.log(\"done\");\n       * });\n     *\n     * @param {string} dbname - the name of the database to retrieve.\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<{}>;\n    /**\n     * Saves a serialized db to the catalog.\n     *\n     * @example\n     * // SAVE : will save App/Key/Val as \"finance\"/\"test\"/{serializedDb}\n     * let idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * let db = new loki(\"test\", { adapter: idbAdapter });\n     * let coll = db.addCollection(\"testColl\");\n     * coll.insert({test: \"val\"});\n     * db.saveDatabase();  // could pass callback if needed for async complete\n     *\n     * @param {string} dbname - the name to give the serialized database within the catalog.\n     * @param {string} dbstring - the serialized db string to save.\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a serialized db from the catalog.\n     *\n     * @example\n     * // DELETE DATABASE\n     * // delete \"finance\"/\"test\" value from catalog\n     * idbAdapter.deleteDatabase(\"test\", function {\n       *   // database deleted\n       * });\n     *\n     * @param {string} dbname - the name of the database to delete from the catalog.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n    /**\n     * Removes all database partitions and pages with the base filename passed in.\n     * This utility method does not (yet) guarantee async deletions will be completed before returning\n     *\n     * @param {string} dbname - the base filename which container, partitions, or pages are derived\n     */\n    deleteDatabasePartitions(dbname: string): void;\n    /**\n     * Retrieves object array of catalog entries for current app.\n     *\n     * @example\n     * idbAdapter.getDatabaseList(function(result) {\n       *   // result is array of string names for that appcontext (\"finance\")\n       *   result.forEach(function(str) {\n       *     console.log(str);\n       *   });\n       * });\n     *\n     * @param {function} callback - should accept array of database names in the catalog for current app.\n     */\n    getDatabaseList(callback: (names: string[]) => void): void;\n    /**\n     * Allows retrieval of list of all keys in catalog along with size\n     * @param {function} callback - (Optional) callback to accept result array.\n     */\n    getCatalogSummary(callback: (entry: Entry[]) => void): void;\n}\nexport interface Entry {\n    app: string;\n    key: string;\n    size: number;\n}\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/local-storage/types/local-storage/src/index.d.ts",
    "content": "import { LocalStorage } from \"./local_storage\";\nexport { LocalStorage };\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/local-storage/types/local-storage/src/local_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists to web browser's local storage object\n * @constructor LocalStorageAdapter\n */\nexport declare class LocalStorage implements StorageAdapter {\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * loadDatabase() - Load data from localstorage\n     * @param {string} dbname - the name of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * saveDatabase() - save data to localstorage, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was saved\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * deleteDatabase() - delete the database from localstorage, will throw an error if it\n     * can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/local-storage/types/loki/src/avl_index.d.ts",
    "content": "import { IRangedIndex, IRangedIndexRequest } from \"./ranged_indexes\";\nimport { ILokiComparer } from \"./comparators\";\n/**\n * Treenode type for binary search tree (BST) implementation.\n *\n * To support duplicates, we may need to either repurpose parent to\n * point to 'elder' sibling or add a siblingId to point to owner of\n * node represented in tree.\n */\nexport declare type TreeNode<T> = {\n    id: number;\n    value: T;\n    parent: number | null;\n    balance: number;\n    height: number;\n    left: number | null;\n    right: number | null;\n    siblings: number[];\n};\nexport interface ITreeNodeHash<T> {\n    [id: number]: TreeNode<T>;\n}\n/**\n * LokiDB AVL Balanced Binary Tree Index implementation.\n * To support duplicates, we use siblings (array) in tree nodes.\n * Basic AVL components guided by William Fiset tutorials at :\n * https://github.com/williamfiset/data-structures/blob/master/com/williamfiset/datastructures/balancedtree/AVLTreeRecursive.java\n * https://www.youtube.com/watch?v=g4y2h70D6Nk&list=PLDV1Zeh2NRsD06x59fxczdWLhDDszUHKt\n */\nexport declare class AvlTreeIndex<T> implements IRangedIndex<T> {\n    name: string;\n    comparator: ILokiComparer<T>;\n    nodes: ITreeNodeHash<T>;\n    apex: number | null;\n    /**\n     * Initializes index with property name and a comparer function.\n     */\n    constructor(name: string, comparator: ILokiComparer<T>);\n    backup(): AvlTreeIndex<T>;\n    restore(tree: AvlTreeIndex<T>): void;\n    /**\n     * Used for inserting a new value into the BinaryTreeIndex\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val Value to be indexed and inserted into binary tree\n     */\n    insert(id: number, val: T): void;\n    /**\n     * Recursively inserts a treenode and re-balances if needed.\n     * @param current\n     * @param node\n     */\n    insertNode(current: TreeNode<T>, node: TreeNode<T>): number;\n    /**\n     * Updates height and balance (calculation) for tree node\n     * @param node\n     */\n    private updateBalance(node);\n    /**\n     * Balance the 'double left-heavy' condition\n     * @param node\n     */\n    private leftLeftCase(node);\n    /**\n     * Balance the '(parent) left heavy, (child) right heavy' condition\n     * @param node\n     */\n    private leftRightCase(node);\n    /**\n     * Balance the 'double right-heavy' condition\n     * @param node\n     */\n    private rightRightCase(node);\n    /**\n     * Balance the '(parent) right heavy, (child) left heavy' condition\n     * @param node\n     */\n    private rightLeftCase(node);\n    /**\n     * Left rotation of node. Swaps right child into current location.\n     * @param node\n     */\n    private rotateLeft(node);\n    /**\n     * Right rotation of node. Swaps left child into current location.\n     * @param node\n     */\n    private rotateRight(node);\n    /**\n     * Diagnostic method for examining tree contents and structure\n     * @param node\n     */\n    getValuesAsTree(node?: TreeNode<T>): any;\n    /**\n     * Updates a value, possibly relocating it, within binary tree\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val New value to be indexed within binary tree\n     */\n    update(id: number, val: T): void;\n    /**\n     * Removes a value from the binary tree index\n     * @param id\n     */\n    remove(id: number): void;\n    /**\n     * Recursive node removal and rebalancer\n     * @param node\n     * @param val\n     */\n    private removeNode(node, id);\n    /**\n     * Utility method for updating a parent's child link when it changes\n     * @param parentId\n     * @param oldChildId\n     * @param newChildId\n     */\n    private updateChildLink(parentId, oldChildId, newChildId);\n    /**\n     * When removing a parent with only child, this does simple remap of child to grandParent.\n     * @param grandParent New parent of 'child'.\n     * @param parent Node being removed.\n     * @param child Node to reparent to grandParent.\n     */\n    private promoteChild(parent, child);\n    /**\n     * Finds a successor to a node and replaces that node with it.\n     * @param node\n     */\n    private promoteSuccessor(node);\n    /**\n     * Utility method for finding In-Order predecessor to the provided node\n     * @param node Parent node to find leaf node of greatest 'value'\n    */\n    private findGreaterLeaf(node);\n    /**\n     * Utility method for finding In-Order successor to the provided node\n     * @param node Parent Node to find leaf node of least 'value'\n     */\n    private findLesserLeaf(node);\n    /**\n     *  Interface method to support ranged queries.  Results sorted by index property.\n     * @param range Options for ranged request.\n     */\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    /**\n     * Implements ranged request operations.\n     * @param node\n     * @param range\n     */\n    private collateRequest(node, range);\n    /**\n     * Used on a branch node to return an array of id within that branch, sorted by their value\n     * @param node\n     */\n    private collateIds(node);\n    /**\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    /**\n     * Inline/Non-recusive 'single value' ($eq) lookup.\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    private locate(node, val);\n    /**\n     * Index integrity check (IRangedIndex interface function)\n     */\n    validateIndex(): boolean;\n    /**\n     * Recursive Node validation routine\n     * @param node\n     */\n    private validateNode(node);\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/loki/src/clone.d.ts",
    "content": "export declare type CloneMethod = \"parse-stringify\" | \"deep\" | \"shallow\" | \"shallow-recurse\";\n/**\n * @hidden\n */\nexport declare function clone<T>(data: T, method?: CloneMethod): T;\n"
  },
  {
    "path": "dist/packages/local-storage/types/loki/src/collection.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { UniqueIndex } from \"./unique_index\";\nimport { ResultSet } from \"./result_set\";\nimport { DynamicView } from \"./dynamic_view\";\nimport { IRangedIndex } from \"./ranged_indexes\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc, Dict } from \"../../common/types\";\nimport { FullTextSearch } from \"../../full-text-search/src/full_text_search\";\nimport { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\n/**\n * Collection class that handles documents of same type\n * @extends LokiEventEmitter\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class Collection<TData extends object = object, TNested extends object = object, T extends TData & TNested = TData & TNested> extends LokiEventEmitter {\n    name: string;\n    _data: Doc<T>[];\n    private _idIndex;\n    _rangedIndexes: {\n        [P in keyof T]?: Collection.RangedIndexMeta;\n    };\n    _lokimap: {\n        [$loki: number]: Doc<T>;\n    };\n    _unindexedSortComparator: string;\n    _defaultLokiOperatorPackage: string;\n    /**\n     * Unique constraints contain duplicate object references, so they are not persisted.\n     * We will keep track of properties which have unique constraints applied here, and regenerate on load.\n     */\n    _constraints: {\n        unique: {\n            [P in keyof T]?: UniqueIndex;\n        };\n    };\n    /**\n     * Transforms will be used to store frequently used query chains as a series of steps which itself can be stored along\n     * with the database.\n     */\n    _transforms: Dict<Collection.Transform<T>[]>;\n    /**\n     * In autosave scenarios we will use collection level dirty flags to determine whether save is needed.\n     * currently, if any collection is dirty we will autosave the whole database if autosave is configured.\n     * Defaulting to true since this is called from addCollection and adding a collection should trigger save.\n     */\n    _dirty: boolean;\n    private _cached;\n    /**\n     * Is collection transactional.\n     */\n    private _transactional;\n    /**\n     * Options to clone objects when inserting them.\n     */\n    _cloneObjects: boolean;\n    /**\n     * Default clone method (if enabled) is parse-stringify.\n     */\n    _cloneMethod: CloneMethod;\n    /**\n     * If set to true we will not maintain a meta property for a document.\n     */\n    private _disableMeta;\n    /**\n     * Disable track changes.\n     */\n    private _disableChangesApi;\n    /**\n     * Disable delta update object style on changes.\n     */\n    _disableDeltaChangesApi: boolean;\n    /**\n     * By default, if you insert a document with a Date value for an indexed property, we will convert that value to number.\n     */\n    private _serializableIndexes;\n    /**\n     * Name of path of used nested properties.\n     */\n    private _nestedProperties;\n    /**\n     * Option to activate a cleaner daemon - clears \"aged\" documents at set intervals.\n     */\n    _ttl: Collection.TTL;\n    private _maxId;\n    private _dynamicViews;\n    /**\n     * Changes are tracked by collection and aggregated by the db.\n     */\n    private _changes;\n    /**\n     * stages: a map of uniquely identified 'stages', which hold copies of objects to be\n     * manipulated without affecting the data in the original collection\n     */\n    private _stages;\n    private _commitLog;\n    _fullTextSearch: FullTextSearch;\n    /**\n     * @param {string} name - collection name\n     * @param {(object)} [options={}] - a configuration object\n     * @param {string[]} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {string[]} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {RangedIndexOptions} [options.rangedIndexes] - configuration object for ranged indexes\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are invoked asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes API\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {boolean} [options.serializableIndexes=true] - converts date values on binary indexed property values are serializable\n     * @param {string} [options.cloneMethod=\"deep\"] - the clone method\n     * @param {number} [options.transactional=false] - ?\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale.\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @param {string} [options.unindexedSortComparator=\"js\"] \"js\", \"abstract\", \"abstract-date\", \"loki\" or other registered comparator name\n     * @param {string} [options.defaultLokiOperatorPackage=\"js\"] \"js\", \"loki\", \"comparator\" (or user defined) query ops package\n     * @param {FullTextSearch.FieldOptions} [options.fullTextSearch=] - the full-text search options\n     * @see {@link Loki#addCollection} for normal creation of collections\n     */\n    constructor(name: string, options?: Collection.Options<TData, TNested>);\n    toJSON(): Collection.Serialized;\n    static fromJSONObject(obj: Collection.Serialized, options?: Collection.DeserializeOptions): Collection<any, object, any>;\n    /**\n     * Adds a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {array} transform - an array of transformation 'step' objects to save into the collection\n     */\n    addTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Retrieves a named transform from the collection.\n     * @param {string} name - name of the transform to lookup.\n     */\n    getTransform(name: string): Collection.Transform<T>[];\n    /**\n     * Updates a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {object} transform - a transformation object to save into collection\n     */\n    setTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Removes a named collection transform from the collection\n     * @param {string} name - name of collection transform to remove\n     */\n    removeTransform(name: string): void;\n    private setTTL(age, interval);\n    /**\n     * Create a row filter that covers all documents in the collection.\n     */\n    _prepareFullDocIndex(): number[];\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field\n     * @param indexTypeName\n     * @param comparatorName\n     */\n    ensureIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field Property to create an index on (need to look into contraining on keyof T)\n     * @param indexTypeName Name of IndexType factory within (global?) hashmap to create IRangedIndex from\n     * @param comparatorName Name of Comparator within (global?) hashmap\n     */\n    ensureRangedIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    ensureUniqueIndex(field: keyof T): UniqueIndex;\n    /**\n     * Quickly determine number of documents in collection (or query)\n     * @param {object} query - (optional) query object to count results of\n     * @returns {number} number of documents in the collection\n     */\n    count(query?: ResultSet.Query<Doc<T>>): number;\n    /**\n     * Rebuild idIndex\n     */\n    private _ensureId();\n    /**\n     * Add a dynamic view to the collection\n     * @param {string} name - name of dynamic view to add\n     * @param {object} options - (optional) options to configure dynamic view with\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=SortPriority.PASSIVE] - the sort priority\n     * @param {number} options.minRebuildInterval - minimum rebuild interval (need clarification to docs here)\n     * @returns {DynamicView} reference to the dynamic view added\n     **/\n    addDynamicView(name: string, options?: DynamicView.Options): DynamicView<T>;\n    /**\n     * Remove a dynamic view from the collection\n     * @param {string} name - name of dynamic view to remove\n     **/\n    removeDynamicView(name: string): void;\n    /**\n     * Look up dynamic view reference from within the collection\n     * @param {string} name - name of dynamic view to retrieve reference of\n     * @returns {DynamicView} A reference to the dynamic view with that name\n     **/\n    getDynamicView(name: string): DynamicView<T>;\n    /**\n     * Applies a 'mongo-like' find query object and passes all results to an update function.\n     * @param {object} filterObject - the 'mongo-like' query object\n     * @param {function} updateFunction - the update function\n     */\n    findAndUpdate(filterObject: ResultSet.Query<Doc<T>>, updateFunction: (obj: Doc<T>) => any): void;\n    /**\n     * Applies a 'mongo-like' find query object removes all documents which match that filter.\n     * @param {object} filterObject - 'mongo-like' query object\n     */\n    findAndRemove(filterObject: ResultSet.Query<Doc<T>>): void;\n    /**\n     * Adds object(s) to collection, ensure object(s) have meta properties, clone it if necessary, etc.\n     * @param {(object|array)} doc - the document (or array of documents) to be inserted\n     * @returns {(object|array)} document or documents inserted\n     */\n    insert(doc: TData): Doc<T>;\n    insert(doc: TData[]): Doc<T>[];\n    /**\n     * Adds a single object, ensures it has meta properties, clone it if necessary, etc.\n     * @param {object} doc - the document to be inserted\n     * @param {boolean} bulkInsert - quiet pre-insert and insert event emits\n     * @returns {object} document or 'undefined' if there was a problem inserting it\n     */\n    insertOne(doc: TData, bulkInsert?: boolean): Doc<T>;\n    /**\n     * Refers nested properties of an object to the root of it.\n     * @param {T} data - the object\n     * @returns {T & TNested} the object with nested properties\n     * @hidden\n     */\n    _defineNestedProperties<U extends TData>(data: U): U & TNested;\n    /**\n     * Empties the collection.\n     * @param {boolean} [removeIndices=false] - remove indices\n     */\n    clear({removeIndices: removeIndices}?: {\n        removeIndices?: boolean;\n    }): void;\n    /**\n     * Updates an object and notifies collection that the document has changed.\n     * @param {object} doc - document to update within the collection\n     */\n    update(doc: Doc<T> | Doc<T>[]): void;\n    /**\n     * Add object to collection\n     */\n    private _add(obj);\n    /**\n     * Applies a filter function and passes all results to an update function.\n     * @param {function} filterFunction - the filter function\n     * @param {function} updateFunction - the update function\n     */\n    updateWhere(filterFunction: (obj: Doc<T>) => boolean, updateFunction: (obj: Doc<T>) => Doc<T>): void;\n    /**\n     * Remove all documents matching supplied filter function.\n     * @param {function} filterFunction - the filter function\n     */\n    removeWhere(filterFunction: (obj: Doc<T>) => boolean): void;\n    removeDataOnly(): void;\n    /**\n     * Remove a document from the collection\n     * @param {number|object} doc - document to remove from collection\n     */\n    remove(doc: number | Doc<T> | Doc<T>[]): void;\n    /**\n     * Returns all changes.\n     * @returns {Collection.Change[]}\n     */\n    getChanges(): Collection.Change[];\n    /**\n     * Enables/disables changes api.\n     * @param {boolean} disableChangesApi\n     * @param {boolean} disableDeltaChangesApi\n     */\n    setChangesApi(disableChangesApi: boolean, disableDeltaChangesApi?: boolean): void;\n    /**\n     * Clears all the changes.\n     */\n    flushChanges(): void;\n    private _getObjectDelta(oldObject, newObject);\n    /**\n     * Compare changed object (which is a forced clone) with existing object and return the delta\n     */\n    private _getChangeDelta(obj, old);\n    /**\n     * Creates a clone of the current status of an object and associates operation and collection name,\n     * so the parent db can aggregate and generate a changes object for the entire db\n     */\n    private _createChange(name, op, obj, old?);\n    private _createInsertChange(obj);\n    private _createUpdateChange(obj, old);\n    private _insertMetaWithChange(obj);\n    private _updateMetaWithChange(obj, old);\n    private _insertMeta(obj);\n    private _updateMeta(obj);\n    /**\n     * Get by Id - faster than other methods because of the searching algorithm\n     * @param {int} id - $loki id of document you want to retrieve\n     * @param {boolean} returnPosition - if 'true' we will return [object, position]\n     * @returns {(object|array|null)} Object reference if document was found, null if not,\n     *     or an array if 'returnPosition' was passed.\n     */\n    get(id: number): Doc<T>;\n    get(id: number, returnPosition: boolean): Doc<T> | [Doc<T>, number];\n    /**\n     * Retrieve doc by Unique index\n     * @param {string} field - name of uniquely indexed property to use when doing lookup\n     * @param {any} value - unique value to search for\n     * @returns {object} document matching the value passed\n     */\n    by(field: keyof T, value: any): Doc<T>;\n    /**\n     * Find one object by index property, by property equal to value\n     * @param {object} query - query object used to perform search with\n     * @returns {(object|null)} First matching document, or null if none\n     */\n    findOne(query: ResultSet.Query<Doc<T>>): Doc<T>;\n    /**\n     * Chain method, used for beginning a series of chained find() and/or view() operations\n     * on a collection.\n     *\n     * @param {array} transform - Ordered array of transform step objects similar to chain\n     * @param {object} parameters - Object containing properties representing parameters to substitute\n     * @returns {ResultSet} (this) ResultSet, or data array if any map or join functions where called\n     */\n    chain(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Find method, api is similar to mongodb.\n     * for more complex queries use [chain()]{@link Collection#chain} or [where()]{@link Collection#where}.\n     * @example {@tutorial Query Examples}\n     * @param {object} query - 'mongo-like' query object\n     * @returns {array} Array of matching documents\n     */\n    find(query?: ResultSet.Query<Doc<T>>): Doc<T>[];\n    /**\n     * Find object by unindexed field by property equal to value,\n     * simply iterates and returns the first element matching the query\n     */\n    findOneUnindexed(prop: string, value: any): Doc<T>;\n    /**\n     * Transaction methods\n     */\n    /**\n     * start the transation\n     */\n    startTransaction(): void;\n    /**\n     * Commit the transaction.\n     */\n    commit(): void;\n    /**\n     * Rollback the transaction.\n     */\n    rollback(): void;\n    /**\n     * Query the collection by supplying a javascript filter function.\n     * @example\n     * let results = coll.where(function(obj) {\n       *   return obj.legs === 8;\n       * });\n     * @param {function} fun - filter function to run against all collection docs\n     * @returns {array} all documents which pass your filter function\n     */\n    where(fun: (obj: Doc<T>) => boolean): Doc<T>[];\n    /**\n     * Map Reduce operation\n     * @param {function} mapFunction - function to use as map function\n     * @param {function} reduceFunction - function to use as reduce function\n     * @returns {data} The result of your mapReduce operation\n     */\n    mapReduce<U1, U2>(mapFunction: (value: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Join two collections on specified properties\n     * @param {array} joinData - array of documents to 'join' to this collection\n     * @param {string} leftJoinProp - property name in collection\n     * @param {string} rightJoinProp - property name in joinData\n     * @param {function} mapFun - (Optional) map function to use\n     * @param dataOptions - options to data() before input to your map function\n     * @param [dataOptions.removeMeta] - allows removing meta before calling mapFun\n     * @param [dataOptions.forceClones] - forcing the return of cloned objects to your map object\n     * @param [dataOptions.forceCloneMethod] - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} Result of the mapping operation\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinProp: string | ((obj: any) => string), rightJoinProp: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * (Staging API) create a stage and/or retrieve it\n     */\n    getStage(name: string): any;\n    /**\n     * a collection of objects recording the changes applied through a commmitStage\n     */\n    /**\n     * (Staging API) create a copy of an object and insert it into a stage\n     */\n    stage<F extends TData>(stageName: string, obj: Doc<F>): F;\n    /**\n     * (Staging API) re-attach all objects to the original collection, so indexes and views can be rebuilt\n     * then create a message to be inserted in the commitlog\n     * @param {string} stageName - name of stage\n     * @param {string} message\n     */\n    commitStage(stageName: string, message: string): void;\n    /**\n     * Returns all values of a field.\n     * @param {string} field - the field name\n     * @return {any}: the array of values\n     */\n    extract(field: keyof T): any[];\n    /**\n     * Finds the minimum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the minimum value\n     */\n    min(field: keyof T): number;\n    /**\n     * Finds the maximum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the maximum value\n     */\n    max(field: keyof T): number;\n    /**\n     * Finds the minimum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    minRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Finds the maximum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    maxRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Returns all values of a field as numbers (if possible).\n     * @param {string} field - the field name\n     * @return {number[]} - the number array\n     */\n    extractNumerical(field: keyof T): number[];\n    /**\n     * Calculates the average numerical value of a field\n     * @param {string} field - the field name\n     * @returns {number} average of property in all docs in the collection\n     */\n    avg(field: keyof T): number;\n    /**\n     * Calculate the standard deviation of a field.\n     * @param {string} field - the field name\n     * @return {number} the standard deviation\n     */\n    stdDev(field: keyof T): number;\n    /**\n     * Calculates the mode of a field.\n     * @param {string} field - the field name\n     * @return {number} the mode\n     */\n    mode(field: keyof T): number;\n    /**\n     * Calculates the median of a field.\n     * @param {string} field - the field name\n     * @return {number} the median\n     */\n    median(field: keyof T): number;\n}\nexport declare namespace Collection {\n    interface Options<TData extends object, TNested extends object = {}, T extends object = TData & TNested> {\n        unique?: (keyof T)[];\n        unindexedSortComparator?: string;\n        defaultLokiOperatorPackage?: string;\n        rangedIndexes?: RangedIndexOptions;\n        serializableIndexes?: boolean;\n        asyncListeners?: boolean;\n        disableMeta?: boolean;\n        disableChangesApi?: boolean;\n        disableDeltaChangesApi?: boolean;\n        clone?: boolean;\n        serializableIndices?: boolean;\n        cloneMethod?: CloneMethod;\n        transactional?: boolean;\n        ttl?: number;\n        ttlInterval?: number;\n        nestedProperties?: (keyof TNested | {\n            name: keyof TNested;\n            path: string[];\n        })[];\n        fullTextSearch?: FullTextSearch.FieldOptions[];\n    }\n    interface RangedIndexOptions {\n        [prop: string]: RangedIndexMeta;\n    }\n    interface DeserializeOptions {\n        retainDirtyFlags?: boolean;\n        fullTextSearch?: Dict<Analyzer>;\n        [collName: string]: any | {\n            proto?: any;\n            inflate?: (src: object, dest?: object) => void;\n        };\n    }\n    interface BinaryIndex {\n        dirty: boolean;\n        values: any;\n    }\n    interface RangedIndexMeta {\n        index?: IRangedIndex<any>;\n        indexTypeName?: string;\n        comparatorName?: string;\n    }\n    interface Change {\n        name: string;\n        operation: string;\n        obj: any;\n    }\n    interface Serialized {\n        name: string;\n        unindexedSortComparator: string;\n        defaultLokiOperatorPackage: string;\n        _dynamicViews: DynamicView[];\n        _nestedProperties: {\n            name: string;\n            path: string[];\n        }[];\n        uniqueNames: string[];\n        transforms: Dict<Transform[]>;\n        rangedIndexes: RangedIndexOptions;\n        _data: Doc<any>[];\n        idIndex: number[];\n        maxId: number;\n        _dirty: boolean;\n        transactional: boolean;\n        asyncListeners: boolean;\n        disableMeta: boolean;\n        disableChangesApi: boolean;\n        disableDeltaChangesApi: boolean;\n        cloneObjects: boolean;\n        cloneMethod: CloneMethod;\n        changes: any;\n        _fullTextSearch: FullTextSearch;\n    }\n    interface CheckIndexOptions {\n        randomSampling?: boolean;\n        randomSamplingFactor?: number;\n        repair?: boolean;\n    }\n    type Transform<T extends object = object> = {\n        type: \"find\";\n        value: ResultSet.Query<Doc<T>> | string;\n    } | {\n        type: \"where\";\n        value: ((obj: Doc<T>) => boolean) | string;\n    } | {\n        type: \"simplesort\";\n        property: keyof T;\n        options?: boolean | ResultSet.SimpleSortOptions;\n    } | {\n        type: \"compoundsort\";\n        value: (keyof T | [keyof T, boolean])[];\n    } | {\n        type: \"sort\";\n        value: (a: Doc<T>, b: Doc<T>) => number;\n    } | {\n        type: \"sortByScoring\";\n        desc?: boolean;\n    } | {\n        type: \"limit\";\n        value: number;\n    } | {\n        type: \"offset\";\n        value: number;\n    } | {\n        type: \"map\";\n        value: (obj: Doc<T>, index: number, array: Doc<T>[]) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"eqJoin\";\n        joinData: Collection<any> | ResultSet<any>;\n        leftJoinKey: string | ((obj: any) => string);\n        rightJoinKey: string | ((obj: any) => string);\n        mapFun?: (left: any, right: any) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"mapReduce\";\n        mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => any;\n        reduceFunction: (array: any[]) => any;\n    } | {\n        type: \"update\";\n        value: (obj: Doc<T>) => any;\n    } | {\n        type: \"remove\";\n    };\n    interface TTL {\n        age: number;\n        ttlInterval: number;\n        daemon: any;\n    }\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/loki/src/comparators.d.ts",
    "content": "export interface ILokiComparer<T> {\n    (a: T, b: T): -1 | 0 | 1;\n}\nexport interface IComparatorMap {\n    [name: string]: ILokiComparer<any>;\n}\n/** Map/Register of named ILokiComparer functions returning -1, 0, 1 for lt/eq/gt assertions for two passed parameters */\nexport declare let ComparatorMap: IComparatorMap;\n/** Typescript-friendly factory for strongly typed 'js' comparators */\nexport declare function CreateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'abstract js' comparators */\nexport declare function CreateAbstractJavascriptComparator<T>(): ILokiComparer<T>;\n/**\n * Comparator which attempts to deal with deal with dates at comparator level.\n * Should work for dates in any of the object, string, and number formats\n */\nexport declare function CreateAbstractDateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'loki' comparators */\nexport declare function CreateLokiComparator(): ILokiComparer<any>;\n"
  },
  {
    "path": "dist/packages/local-storage/types/loki/src/dynamic_view.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { ResultSet } from \"./result_set\";\nimport { Collection } from \"./collection\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\n/**\n * DynamicView class is a versatile 'live' view class which can have filters and sorts applied.\n *    Collection.addDynamicView(name) instantiates this DynamicView object and notifies it\n *    whenever documents are add/updated/removed so it can remain up-to-date. (chainable)\n *\n * @example\n * let mydv = mycollection.addDynamicView('test');  // default is non-persistent\n * mydv.applyFind({ 'doors' : 4 });\n * mydv.applyWhere(function(obj) { return obj.name === 'Toyota'; });\n * let results = mydv.data();\n *\n * @extends LokiEventEmitter\n\n * @see {@link Collection#addDynamicView} to construct instances of DynamicView\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class DynamicView<T extends object = object> extends LokiEventEmitter {\n    readonly name: string;\n    private _collection;\n    private _persistent;\n    private _sortPriority;\n    private _minRebuildInterval;\n    private _rebuildPending;\n    private _resultSet;\n    private _resultData;\n    private _resultDirty;\n    private _cachedResultSet;\n    private _filterPipeline;\n    private _sortFunction;\n    private _sortCriteria;\n    private _sortCriteriaSimple;\n    private _sortByScoring;\n    private _sortDirty;\n    /**\n     * Constructor.\n     * @param {Collection} collection - a reference to the collection to work agains\n     * @param {string} name - the name of this dynamic view\n     * @param {object} options - the options\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=\"passive\"] - the sort priority\n     * @param {number} [options.minRebuildInterval=1] - minimum rebuild interval (need clarification to docs here)\n     */\n    constructor(collection: Collection<T>, name: string, options?: DynamicView.Options);\n    /**\n     * Internally used immediately after deserialization (loading)\n     *    This will clear out and reapply filterPipeline ops, recreating the view.\n     *    Since where filters do not persist correctly, this method allows\n     *    restoring the view to state where user can re-apply those where filters.\n     *\n     * @param removeWhereFilters\n     * @returns {DynamicView} This dynamic view for further chained ops.\n     * @fires DynamicView.rebuild\n     */\n    private _rematerialize({removeWhereFilters});\n    /**\n     * Makes a copy of the internal ResultSet for branched queries.\n     * Unlike this dynamic view, the branched ResultSet will not be 'live' updated,\n     * so your branched query should be immediately resolved and not held for future evaluation.\n     * @param {(string|array=)} transform - Optional name of collection transform, or an array of transform steps\n     * @param {object} parameters - optional parameters (if optional transform requires them)\n     * @returns {ResultSet} A copy of the internal ResultSet for branched queries.\n     */\n    branchResultSet(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Override of toJSON to avoid circular references.\n     */\n    toJSON(): DynamicView.Serialized;\n    static fromJSONObject(collection: Collection, obj: DynamicView.Serialized): DynamicView;\n    /**\n     * Used to clear pipeline and reset dynamic view to initial state.\n     * Existing options should be retained.\n     * @param {boolean} queueSortPhase - (default: false) if true we will async rebuild view (maybe set default to true in future?)\n     */\n    removeFilters({queueSortPhase}?: {\n        queueSortPhase?: boolean;\n    }): void;\n    /**\n     * Used to apply a sort to the dynamic view\n     * @example\n     * dv.applySort(function(obj1, obj2) {\n       *   if (obj1.name === obj2.name) return 0;\n       *   if (obj1.name > obj2.name) return 1;\n       *   if (obj1.name < obj2.name) return -1;\n       * });\n     * @param {function} comparefun - a javascript compare function used for sorting\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applySort(comparefun: (lhs: Doc<T>, rhs: Doc<T>) => number): this;\n    /**\n     * Used to specify a property used for view translation.\n     * @param {string} field - the field name\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether we should sort descending.\n     * @param {boolean} [options.disableIndexIntersect=false] - whether we should explicity not use array intersection.\n     * @param {boolean} [options.forceIndexIntersect=false] - force array intersection (if binary index exists).\n     * @param {boolean} [options.useJavascriptSorting=false] - whether results are sorted via basic javascript sort.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     * @example\n     * dv.applySimpleSort(\"name\");\n     */\n    applySimpleSort(field: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @param {Array} criteria - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {DynamicView} Reference to this DynamicView, sorted, for future chain operations.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * dv.applySortCriteria(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * dv.applySortCriteria(['age', ['name', true]]);\n     * // to sort by age (descending) and then by name (descending)\n     * dv.applySortCriteria([['age', true], ['name', true]]);\n     */\n    applySortCriteria(criteria: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Used to apply a sort by the latest full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     */\n    applySortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Marks the beginning of a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    startTransaction(): this;\n    /**\n     * Commits a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    commit(): this;\n    /**\n     * Rolls back a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    rollback(): this;\n    /**\n     * Find the index of a filter in the pipeline, by that filter's ID.\n     * @param {(string|number)} uid - The unique ID of the filter.\n     * @returns {number}: index of the referenced filter in the pipeline; -1 if not found.\n     */\n    private _indexOfFilterWithId(uid);\n    /**\n     * Add the filter object to the end of view's filter pipeline and apply the filter to the ResultSet.\n     * @param {object} filter - The filter object. Refer to applyFilter() for extra details.\n     */\n    private _addFilter(filter);\n    /**\n     * Reapply all the filters in the current pipeline.\n     *\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    reapplyFilters(): this;\n    /**\n     * Adds or updates a filter in the DynamicView filter pipeline\n     * @param {object} filter - A filter object to add to the pipeline.\n     *    The object is in the format { 'type': filter_type, 'val', filter_param, 'uid', optional_filter_id }\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFilter(filter: DynamicView.Filter<T>): this;\n    /**\n     * applyFind() - Adds or updates a mongo-style query option in the DynamicView filter pipeline\n     *\n     * @param {object} query - A mongo-style query object to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFind(query: object, uid?: string | number): this;\n    /**\n     * Adds or updates a javascript filter function in the DynamicView filter pipeline\n     * @param {function} fun - A javascript filter function to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyWhere(fun: (obj: Doc<T>) => boolean, uid?: string | number): this;\n    /**\n     * Remove the specified filter from the DynamicView filter pipeline\n     * @param {(string|number)} uid - The unique ID of the filter to be removed.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    removeFilter(uid: string | number): this;\n    /**\n     * Returns the number of documents representing the current DynamicView contents.\n     * @returns {number} The number of documents representing the current DynamicView contents.\n     */\n    count(): number;\n    /**\n     * Resolves and pending filtering and sorting, then returns document array as result.\n     * @param {object} options - optional parameters to pass to ResultSet.data() if non-persistent\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values include 'parse-stringify', 'jquery-extend-deep', 'shallow', 'shallow-assign'\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} An array of documents representing the current DynamicView contents.\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * When the view is not sorted we may still wish to be notified of rebuild events.\n     * This event will throttle and queue a single rebuild event when batches of updates affect the view.\n     */\n    private _queueRebuildEvent();\n    /**\n     * If the view is sorted we will throttle sorting to either :\n     * (1) passive - when the user calls data(), or\n     * (2) active - once they stop updating and yield js thread control\n     */\n    private _queueSortPhase();\n    /**\n     * Invoked synchronously or asynchronously to perform final sort phase (if needed)\n     */\n    private _performSortPhase(options?);\n    /**\n     * (Re)evaluating document inclusion.\n     * Called by : collection.insert() and collection.update().\n     * @param {int} objIndex - index of document to (re)run through filter pipeline.\n     * @param {boolean} isNew - true if the document was just added to the collection.\n     * @hidden\n     */\n    _evaluateDocument(objIndex: number, isNew: boolean): void;\n    /**\n     * Internal function called on collection.delete().\n     * @hidden\n     */\n    _removeDocument(objIndex: number): void;\n    /**\n     * Data transformation via user supplied functions\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: T, index: number, array: T[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n}\nexport declare namespace DynamicView {\n    interface Options {\n        persistent?: boolean;\n        sortPriority?: SortPriority;\n        minRebuildInterval?: number;\n    }\n    type SortPriority = \"passive\" | \"active\";\n    interface Serialized {\n        name: string;\n        _persistent: boolean;\n        _sortPriority: SortPriority;\n        _minRebuildInterval: number;\n        _resultSet: ResultSet<any>;\n        _filterPipeline: Filter<any>[];\n        _sortCriteria: (string | [string, boolean])[];\n        _sortCriteriaSimple: {\n            field: string;\n            options: boolean | ResultSet.SimpleSortOptions;\n        };\n        _sortByScoring: boolean;\n        _sortDirty: boolean;\n    }\n    type Filter<T extends object = object> = {\n        type: \"find\";\n        val: ResultSet.Query<Doc<T>>;\n        uid: number | string;\n    } | {\n        type: \"where\";\n        val: (obj: Doc<T>) => boolean;\n        uid: number | string;\n    };\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/loki/src/event_emitter.d.ts",
    "content": "/**\n * LokiEventEmitter is a minimalist version of EventEmitter. It enables any\n * constructor that inherits EventEmitter to emit events and trigger\n * listeners that have been added to the event through the on(event, callback) method\n *\n * @constructor LokiEventEmitter\n */\nexport declare class LokiEventEmitter {\n    /**\n     * A map, with each property being an array of callbacks.\n     */\n    protected _events: object;\n    /**\n     * Determines whether or not the callbacks associated with each event should happen in an async fashion or not.\n     * Default is false, which means events are synchronous\n     */\n    protected _asyncListeners: boolean;\n    /**\n     * Adds a listener to the queue of callbacks associated to an event\n     * @param {string|string[]} eventName - the name(s) of the event(s) to listen to\n     * @param {function} listener - callback function of listener to attach\n     * @returns {int} the index of the callback in the array of listeners for a particular event\n     */\n    on(eventName: string | string[], listener: Function): Function;\n    /**\n     * Emits a particular event\n     * with the option of passing optional parameters which are going to be processed by the callback\n     * provided signatures match (i.e. if passing emit(event, arg0, arg1) the listener should take two parameters)\n     * @param {string} eventName - the name of the event\n     * @param {object} data - optional object passed with the event\n     */\n    protected emit(eventName: string, ...data: any[]): void;\n    /**\n     * Alias of EventEmitter.on().\n     */\n    addListener(eventName: string | string[], listener: Function): Function;\n    /**\n     * Removes the listener at position 'index' from the event 'eventName'\n     * @param {string|string[]} eventName - the name(s) of the event(s) which the listener is attached to\n     * @param {function} listener - the listener callback function to remove from emitter\n     */\n    removeListener(eventName: string | string[], listener: Function): void;\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/loki/src/index.d.ts",
    "content": "import { Loki } from \"./loki\";\nimport { Collection } from \"./collection\";\nexport { Loki, Collection };\nexport default Loki;\n"
  },
  {
    "path": "dist/packages/local-storage/types/loki/src/loki.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { Collection } from \"./collection\";\nimport { Doc, StorageAdapter } from \"../../common/types\";\nimport { IComparatorMap } from \"./comparators\";\nimport { IRangedIndexFactoryMap } from \"./ranged_indexes\";\nimport { ILokiOperatorPackageMap } from \"./operator_packages\";\nexport declare class Loki extends LokiEventEmitter {\n    filename: string;\n    private databaseVersion;\n    private engineVersion;\n    _collections: Collection[];\n    private _env;\n    private _serializationMethod;\n    private _destructureDelimiter;\n    private _persistenceMethod;\n    private _persistenceAdapter;\n    private _throttledSaves;\n    private _throttledSaveRunning;\n    private _throttledSavePending;\n    private _autosave;\n    private _autosaveInterval;\n    private _autosaveRunning;\n    private _autosaveHandler;\n    /**\n     * Constructs the main database class.\n     * @param {string} filename - name of the file to be saved to\n     * @param {object} [options={}] - options\n     * @param {Loki.Environment} [options.env] - the javascript environment\n     * @param {Loki.SerializationMethod} [options.serializationMethod=NORMAL] - the serialization method\n     * @param {string} [options.destructureDelimiter=\"$<\\n\"] - string delimiter used for destructured serialization\n     * @param {IComparatorMap} [options.comparatorMap] allows injecting or overriding registered comparators\n     * @param {IRangedIndexFactoryMap} [options.rangedIndexFactoryMap] allows injecting or overriding registered ranged index factories\n     * @param {ILokiOperatorPackageMap} [options.lokiOperatorPackageMap] allows injecting or overriding registered loki operator packages\n     */\n    constructor(filename?: string, options?: Loki.Options);\n    /**\n     * configures options related to database persistence.\n     *\n     * @param {Loki.PersistenceOptions} [options={}] - options\n     * @param {adapter} [options.adapter=auto] - an instance of a loki persistence adapter\n     * @param {boolean} [options.autosave=false] - enables autosave\n     * @param {int} [options.autosaveInterval=5000] - time interval (in milliseconds) between saves (if dirty)\n     * @param {boolean} [options.autoload=false] - enables autoload on loki instantiation\n     * @param {object} options.inflate - options that are passed to loadDatabase if autoload enabled\n     * @param {boolean} [options.throttledSaves=true] - if true, it batches multiple calls to to saveDatabase reducing number of\n     *   disk I/O operations and guaranteeing proper serialization of the calls. Default value is true.\n     * @param {Loki.PersistenceMethod} options.persistenceMethod - a persistence method which should be used (FS_STORAGE, LOCAL_STORAGE...)\n     * @returns {Promise} a Promise that resolves after initialization and (if enabled) autoloading the database\n     */\n    initializePersistence(options?: Loki.PersistenceOptions): Promise<void>;\n    /**\n     * Copies 'this' database into a new Loki instance. Object references are shared to make lightweight.\n     * @param {object} options - options\n     * @param {boolean} options.removeNonSerializable - nulls properties not safe for serialization.\n     */\n    copy(options?: Loki.CopyOptions): Loki;\n    /**\n     * Adds a collection to the database.\n     * @param {string} name - name of collection to add\n     * @param {object} [options={}] - options to configure collection with.\n     * @param {array} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {array} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {array} [options.indices=[]] - array property names to define binary indexes for\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are called asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes Api\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {string} [options.cloneMethod=CloneMethod.DEEP] - the clone method\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @returns {Collection} a reference to the collection which was just added\n     */\n    addCollection<TData extends object = object, TNested extends object = object>(name: string, options?: Collection.Options<TData, TNested>): Collection<TData, TNested>;\n    loadCollection(collection: Collection): void;\n    /**\n     * Retrieves reference to a collection by name.\n     * @param {string} name - name of collection to look up\n     * @returns {Collection} Reference to collection in database by that name, or null if not found\n     */\n    getCollection<TData extends object = object, TNested extends object = object>(name: string): Collection<TData, TNested>;\n    /**\n     * Renames an existing loki collection\n     * @param {string} oldName - name of collection to rename\n     * @param {string} newName - new name of collection\n     * @returns {Collection} reference to the newly renamed collection\n     */\n    renameCollection<TData extends object = object, TNested extends object = object>(oldName: string, newName: string): Collection<TData, TNested>;\n    listCollections(): {\n        name: string;\n        count: number;\n    }[];\n    /**\n     * Removes a collection from the database.\n     * @param {string} collectionName - name of collection to remove\n     */\n    removeCollection(collectionName: string): void;\n    /**\n     * Serialize database to a string which can be loaded via {@link Loki#loadJSON}\n     *\n     * @returns {string} Stringified representation of the loki database.\n     */\n    serialize(options?: Loki.SerializeOptions): string | string[];\n    toJSON(): Loki.Serialized;\n    /**\n     * Database level destructured JSON serialization routine to allow alternate serialization methods.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {object} options - output format options for use externally to loki\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to only output an individual collection or db (-1)\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {string|Array} A custom, restructured aggregation of independent serializations.\n     */\n    serializeDestructured(options?: Loki.SerializeDestructuredOptions): string | string[];\n    /**\n     * Collection level utility method to serialize a collection in a 'destructured' format\n     *\n     * @param {object} options - used to determine output of method\n     * @param {int} options.delimited - whether to return single delimited string or an array\n     * @param {string} options.delimiter - (optional) if delimited, this is delimiter to use\n     * @param {int} options.collectionIndex -  specify which collection to serialize data for\n     *\n     * @returns {string|array} A custom, restructured aggregation of independent serializations for a single collection.\n     */\n    serializeCollection(options?: {\n        delimited?: boolean;\n        collectionIndex?: number;\n        delimiter?: string;\n    }): string | string[];\n    /**\n     * Database level destructured JSON deserialization routine to minimize memory overhead.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {string|array} destructuredSource - destructured json or array to deserialize from\n     * @param {object} options - source format options\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to deserialize only a single partition\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {object|array} An object representation of the deserialized database, not yet applied to 'this' db or document array\n     */\n    deserializeDestructured(destructuredSource: string | string[], options?: Loki.SerializeDestructuredOptions): any;\n    /**\n     * Collection level utility function to deserializes a destructured collection.\n     *\n     * @param {string|string[]} destructuredSource - destructured representation of collection to inflate\n     * @param {object} options - used to describe format of destructuredSource input\n     * @param {int} [options.delimited=false] - whether source is delimited string or an array\n     * @param {string} options.delimiter - if delimited, this is delimiter to use (if other than default)\n     *\n     * @returns {Array} an array of documents to attach to collection.data.\n     */\n    deserializeCollection<T extends object = object>(destructuredSource: string | string[], options?: Loki.DeserializeCollectionOptions): Doc<T>[];\n    /**\n     * Inflates a loki database from a serialized JSON string\n     *\n     * @param {string} serializedDb - a serialized loki database string\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSON(serializedDb: string | string[], options?: Collection.DeserializeOptions): void;\n    /**\n     * Inflates a loki database from a JS object\n     *\n     * @param {object} dbObject - a serialized loki database object\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSONObject(dbObject: Loki, options?: Collection.DeserializeOptions): void;\n    loadJSONObject(dbObject: Loki.Serialized, options?: Collection.DeserializeOptions): void;\n    /**\n     * Emits the close event. In autosave scenarios, if the database is dirty, this will save and disable timer.\n     * Does not actually destroy the db.\n     *\n     * @returns {Promise} a Promise that resolves after closing the database succeeded\n     */\n    close(): Promise<void>;\n    /**-------------------------+\n     | Changes API               |\n     +--------------------------*/\n    /**\n     * The Changes API enables the tracking the changes occurred in the collections since the beginning of the session,\n     * so it's possible to create a differential dataset for synchronization purposes (possibly to a remote db)\n     */\n    /**\n     * (Changes API) : takes all the changes stored in each\n     * collection and creates a single array for the entire database. If an array of names\n     * of collections is passed then only the included collections will be tracked.\n     *\n     * @param {Array} [arrayOfCollectionNames=] - array of collection names. No arg means all collections are processed.\n     * @returns {Array} array of changes\n     * @see private method _createChange() in Collection\n     */\n    generateChangesNotification(arrayOfCollectionNames?: string[]): Collection.Change[];\n    /**\n     * (Changes API) - stringify changes for network transmission\n     * @returns {string} string representation of the changes\n     */\n    serializeChanges(collectionNamesArray?: string[]): string;\n    /**\n     * (Changes API) : clears all the changes in all collections.\n     */\n    clearChanges(): void;\n    /**\n     * Wait for throttledSaves to complete and invoke your callback when drained or duration is met.\n     *\n     * @param {object} options - configuration options\n     * @param {boolean} [options.recursiveWait=true] - if after queue is drained, another save was kicked off, wait for it\n     * @param {boolean} [options.recursiveWaitLimit=false] - limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDuration=2000] - cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves when save queue is drained, it is passed a sucess parameter value\n     */\n    throttledSaveDrain(options?: Loki.ThrottledDrainOptions): Promise<void>;\n    /**\n     * Internal load logic, decoupled from throttling/contention logic\n     *\n     * @param {object} options - an object containing inflation options for each collection\n     * @param {boolean} ignore_not_found - does not raise an error if database is not found\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    private _loadDatabase(options?, ignore_not_found?);\n    /**\n     * Handles manually loading from an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *    To avoid contention with any throttledSaves, we will drain the save queue first.\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @param {object} [options={}] - if throttling saves and loads, this controls how we drain save queue before loading\n     * @param {boolean} [options.recursiveWait=true] wait recursively until no saves are queued\n     * @param {boolean} [options.recursiveWaitLimit=false] limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDelay=2000] cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    loadDatabase(options?: Loki.LoadDatabaseOptions): Promise<void>;\n    private _saveDatabase();\n    /**\n     * Handles manually saving to an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @returns {Promise} a Promise that resolves after the database is persisted\n     */\n    saveDatabase(): Promise<void>;\n    /**\n     * Handles deleting a database from the underlying storage adapter\n     *\n     * @returns {Promise} a Promise that resolves after the database is deleted\n     */\n    deleteDatabase(): Promise<void>;\n    /****************\n     * Autosave API\n     ****************/\n    /**\n     * Check whether any collections are \"dirty\" meaning we need to save the (entire) database\n     * @returns {boolean} - true if database has changed since last autosave, otherwise false\n     */\n    private _autosaveDirty();\n    /**\n     * Resets dirty flags on all collections.\n     */\n    private _autosaveClearFlags();\n    /**\n     * Starts periodically saves to the underlying storage adapter.\n     */\n    private _autosaveEnable();\n    /**\n     * Stops the autosave interval timer.\n     */\n    private _autosaveDisable();\n}\nexport declare namespace Loki {\n    interface Options {\n        env?: Environment;\n        serializationMethod?: SerializationMethod;\n        destructureDelimiter?: string;\n        comparatorMap?: IComparatorMap;\n        rangedIndexFactoryMap?: IRangedIndexFactoryMap;\n        lokiOperatorPackageMap?: ILokiOperatorPackageMap;\n    }\n    interface PersistenceOptions {\n        adapter?: StorageAdapter;\n        autosave?: boolean;\n        autosaveInterval?: number;\n        autoload?: boolean;\n        throttledSaves?: boolean;\n        persistenceMethod?: Loki.PersistenceMethod;\n        inflate?: any;\n    }\n    interface CopyOptions {\n        removeNonSerializable?: boolean;\n    }\n    interface SerializeOptions {\n        serializationMethod?: SerializationMethod;\n    }\n    interface SerializeDestructuredOptions {\n        partitioned?: boolean;\n        partition?: number;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface DeserializeCollectionOptions {\n        partitioned?: boolean;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface ThrottledDrainOptions {\n        recursiveWait?: boolean;\n        recursiveWaitLimit?: boolean;\n        recursiveWaitLimitDuration?: number;\n        started?: Date;\n    }\n    interface Serialized {\n        _env: Environment;\n        _serializationMethod: SerializationMethod;\n        _autosave: boolean;\n        _autosaveInterval: number;\n        _collections: Collection[];\n        databaseVersion: number;\n        engineVersion: number;\n        filename: string;\n        _persistenceAdapter: StorageAdapter;\n        _persistenceMethod: PersistenceMethod;\n        _throttledSaves: boolean;\n    }\n    type LoadDatabaseOptions = Collection.DeserializeOptions & ThrottledDrainOptions;\n    type SerializationMethod = \"normal\" | \"pretty\" | \"destructured\";\n    type PersistenceMethod = \"fs-storage\" | \"local-storage\" | \"indexed-storage\" | \"memory-storage\" | \"adapter\";\n    type Environment = \"NATIVESCRIPT\" | \"NODEJS\" | \"CORDOVA\" | \"BROWSER\" | \"MEMORY\";\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/loki/src/operator_packages.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\n/** Hash interface for named LokiOperatorPackage registration */\nexport interface ILokiOperatorPackageMap {\n    [name: string]: LokiOperatorPackage;\n}\n/**\n * Helper function for determining 'loki' abstract equality which is a little more abstract than ==\n *     aeqHelper(5, '5') === true\n *     aeqHelper(5.0, '5') === true\n *     aeqHelper(new Date(\"1/1/2011\"), new Date(\"1/1/2011\")) === true\n *     aeqHelper({a:1}, {z:4}) === true (all objects sorted equally)\n *     aeqHelper([1, 2, 3], [1, 3]) === false\n *     aeqHelper([1, 2, 3], [1, 2, 3]) === true\n *     aeqHelper(undefined, null) === true\n * @param {any} prop1\n * @param {any} prop2\n * @returns {boolean}\n * @hidden\n */\nexport declare function aeqHelper(prop1: any, prop2: any): boolean;\n/**\n * Helper function for determining 'less-than' conditions for ops, sorting, and binary indices.\n *     In the future we might want $lt and $gt ops to use their own functionality/helper.\n *     Since binary indices on a property might need to index [12, NaN, new Date(), Infinity], we\n *     need this function (as well as gtHelper) to always ensure one value is LT, GT, or EQ to another.\n * @hidden\n */\nexport declare function ltHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @hidden\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} equal\n * @returns {boolean}\n */\nexport declare function gtHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} descending\n * @returns {number}\n * @hidden\n */\nexport declare function sortHelper(prop1: any, prop2: any, descending: boolean): number;\n/**\n * Default implementation of LokiOperatorPackage, using fastest javascript comparison operators.\n */\nexport declare class LokiOperatorPackage {\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n    $in(a: any, b: any): boolean;\n    $nin(a: any, b: any): boolean;\n    $keyin(a: string, b: object): boolean;\n    $nkeyin(a: string, b: object): boolean;\n    $definedin(a: string, b: object): boolean;\n    $undefinedin(a: string, b: object): boolean;\n    $regex(a: string, b: RegExp): boolean;\n    $containsNone(a: any, b: any): boolean;\n    $containsAny(a: any, b: any): boolean;\n    $contains(a: any, b: any): boolean;\n    $type(a: any, b: any): boolean;\n    $finite(a: number, b: boolean): boolean;\n    $size(a: any, b: any): boolean;\n    $len(a: any, b: any): boolean;\n    $where(a: any, b: any): boolean;\n    $not(a: any, b: any): boolean;\n    $and(a: any, b: any): boolean;\n    $or(a: any, b: any): boolean;\n    private doQueryOp(val, op);\n    private containsCheckFn(a);\n}\n/**\n * LokiOperatorPackage which utilizes abstract 'loki' comparisons for basic relational equality op implementations.\n */\nexport declare class LokiAbstractOperatorPackage extends LokiOperatorPackage {\n    constructor();\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * LokiOperatorPackage which utilizes provided comparator for basic relational equality op implementations.\n */\nexport declare class ComparatorOperatorPackage<T> extends LokiOperatorPackage {\n    comparator: ILokiComparer<T>;\n    constructor(comparator: ILokiComparer<T>);\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * Map/Register of named LokiOperatorPackages which implement all unindexed query ops within 'find' query objects\n */\nexport declare let LokiOperatorPackageMap: ILokiOperatorPackageMap;\n"
  },
  {
    "path": "dist/packages/local-storage/types/loki/src/ranged_indexes.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\nexport declare type RangedValueOperator = \"$gt\" | \"$gte\" | \"$lt\" | \"$lte\" | \"$eq\" | \"$neq\" | \"$between\";\nexport interface IRangedIndexRequest<T> {\n    op: RangedValueOperator;\n    val: T;\n    high?: T;\n}\n/** Defines interface which all loki ranged indexes need to implement */\nexport interface IRangedIndex<T> {\n    insert(id: number, val: T): void;\n    update(id: number, val: T): void;\n    remove(id: number): void;\n    restore(tree: any): void;\n    backup(): IRangedIndex<T>;\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    validateIndex(): boolean;\n}\n/** Hash Interface for global ranged index factory map*/\nexport interface IRangedIndexFactoryMap {\n    [name: string]: (name: string, comparator: ILokiComparer<any>) => IRangedIndex<any>;\n}\n/** Map/Register of named factory functions returning IRangedIndex instances */\nexport declare let RangedIndexFactoryMap: IRangedIndexFactoryMap;\n"
  },
  {
    "path": "dist/packages/local-storage/types/loki/src/result_set.d.ts",
    "content": "import { Collection } from \"./collection\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\nimport { Query as FullTextSearchQuery } from \"../../full-text-search/src/query_types\";\n/**\n * ResultSet class allowing chainable queries.  Intended to be instanced internally.\n *    Collection.find(), Collection.where(), and Collection.chain() instantiate this.\n *\n * @example\n *    mycollection.chain()\n *      .find({ 'doors' : 4 })\n *      .where(function(obj) { return obj.name === 'Toyota' })\n *      .data();\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class ResultSet<T extends object = object> {\n    _collection: Collection<T>;\n    _filteredRows: number[];\n    _filterInitialized: boolean;\n    private _scoring;\n    /**\n     * Constructor.\n     * @param {Collection} collection - the collection which this ResultSet will query against\n     */\n    constructor(collection: Collection<T>);\n    /**\n     * Reset the ResultSet to its initial state.\n     * @returns {ResultSet} Reference to this ResultSet, for future chain operations.\n     */\n    reset(): this;\n    /**\n     * Override of toJSON to avoid circular references\n     */\n    toJSON(): ResultSet<T>;\n    /**\n     * Allows you to limit the number of documents passed to next chain operation.\n     * A ResultSet copy() is made to avoid altering original ResultSet.\n     * @param {int} qty - The number of documents to return.\n     * @returns {ResultSet} Returns a copy of the ResultSet, limited by qty, for subsequent chain ops.\n     */\n    limit(qty: number): this;\n    /**\n     * Used for skipping 'pos' number of documents in the ResultSet.\n     * @param {int} pos - Number of documents to skip; all preceding documents are filtered out.\n     * @returns {ResultSet} Returns a copy of the ResultSet, containing docs starting at 'pos' for subsequent chain ops.\n     */\n    offset(pos: number): this;\n    /**\n     * To support reuse of ResultSet in branched query situations.\n     * @returns {ResultSet} Returns a copy of the ResultSet (set) but the underlying document references will be the same.\n     */\n    copy(): ResultSet<T>;\n    /**\n     * Executes a named collection transform or raw array of transform steps against the ResultSet.\n     * @param {(string|array)} transform - name of collection transform or raw transform array\n     * @param {object} [parameters=] - object property hash of parameters, if the transform requires them.\n     * @returns {ResultSet} either (this) ResultSet or a clone of of this ResultSet (depending on steps)\n     */\n    transform(transform: string | Collection.Transform<T>[], parameters?: object): this;\n    /**\n     * User supplied compare function is provided two documents to compare. (chainable)\n     * @example\n     *    rslt.sort(function(obj1, obj2) {\n       *      if (obj1.name === obj2.name) return 0;\n       *      if (obj1.name > obj2.name) return 1;\n       *      if (obj1.name < obj2.name) return -1;\n       *    });\n     * @param {function} comparefun - A javascript compare function used for sorting.\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    sort(comparefun: (a: Doc<T>, b: Doc<T>) => number): this;\n    /**\n     * Simpler, loose evaluation for user to sort based on a property name. (chainable).\n     * Sorting based on the same lt/gt helper functions used for binary indices.\n     * @param {string} propname - name of property to sort by.\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether to sort descending\n     * @param {string} [options.sortComparator] override default with name of comparator registered in ComparatorMap\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    simplesort(propname: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * rs.compoundsort(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * rs.compoundsort(['age', ['name', true]);\n     * @param {array} properties - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    compoundsort(properties: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Helper function for compoundsort(), performing individual object comparisons\n     * @param {Array} properties - array of property names, in order, by which to evaluate sort order\n     * @param {object} obj1 - first object to compare\n     * @param {object} obj2 - second object to compare\n     * @returns {number} 0, -1, or 1 to designate if identical (sortwise) or which should be first\n     */\n    private _compoundeval(properties, obj1, obj2);\n    /**\n     * Sorts the ResultSet based on the last full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     * @returns {ResultSet}\n     */\n    sortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Oversee the operation of OR'ed query expressions.\n     * OR'ed expression evaluation runs each expression individually against the full collection,\n     * and finally does a set OR on each expression's results.\n     * Each evaluation can utilize a binary index to prevent multiple linear array scans.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findOr(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $or(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Oversee the operation of AND'ed query expressions.\n     * AND'ed expression evaluation runs each expression progressively against the full collection,\n     * internally utilizing existing chained ResultSet functionality.\n     * Only the first filter can utilize a binary index.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findAnd(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $and(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Used for querying via a mongo-style query object.\n     *\n     * @param {object} query - A mongo-style query object used for filtering current results.\n     * @param {boolean} firstOnly - (Optional) Used by collection.findOne() - flag if this was invoked via findOne()\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    find(query?: ResultSet.Query<Doc<T>>, firstOnly?: boolean): this;\n    /**\n     * Used for filtering via a javascript filter function.\n     * @param {function} fun - A javascript function used for filtering current results by.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    where(fun: (obj: Doc<T>) => boolean): this;\n    /**\n     * Returns the number of documents in the ResultSet.\n     * @returns {number} The number of documents in the ResultSet.\n     */\n    count(): number;\n    /**\n     * Terminates the chain and returns array of filtered documents\n     * @param {object} options\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values 'parse-stringify', 'deep', and 'shallow' and\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} Array of documents in the ResultSet\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * Used to run an update operation on all documents currently in the ResultSet.\n     * @param {function} updateFunction - User supplied updateFunction(obj) will be executed for each document object.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    update(updateFunction: (obj: Doc<T>) => Doc<T>): this;\n    /**\n     * Removes all document objects which are currently in ResultSet from collection (as well as ResultSet)\n     * @returns {ResultSet} this (empty) ResultSet for further chain ops.\n     */\n    remove(): this;\n    /**\n     * data transformation via user supplied functions\n     *\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns {value} The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Left joining two sets of data. Join keys can be defined or calculated properties\n     * eqJoin expects the right join key values to be unique.  Otherwise left data will be joined on the last joinData object with that key\n     * @param {Array|ResultSet|Collection} joinData - Data array to join to.\n     * @param {(string|function)} leftJoinKey - Property name in this result set to join on or a function to produce a value to join on\n     * @param {(string|function)} rightJoinKey - Property name in the joinData to join on or a function to produce a value to join on\n     * @param {function} [mapFun=] - a function that receives each matching pair and maps them into output objects - function(left,right){return joinedObject}\n     * @param {object} [dataOptions=] - optional options to apply to data() calls for left and right sides\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} A ResultSet with data in the format [{left: leftObj, right: rightObj}]\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinKey: string | ((obj: any) => string), rightJoinKey: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * Applies a map function into a new collection for further chaining.\n     * @param {function} mapFun - javascript map function\n     * @param {object} [dataOptions=] - options to data() before input to your map function\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - Allows overriding the default or collection specified cloning method\n     * @return {ResultSet}\n     */\n    map<U extends object>(mapFun: (obj: Doc<T>, index: number, array: Doc<T>[]) => U, dataOptions?: ResultSet.DataOptions): ResultSet<U>;\n}\nexport declare namespace ResultSet {\n    interface DataOptions {\n        forceClones?: boolean;\n        forceCloneMethod?: CloneMethod;\n        removeMeta?: boolean;\n    }\n    interface SimpleSortOptions {\n        desc?: boolean;\n        sortComparator?: string;\n    }\n    type ContainsHelperType<R> = R extends string ? string | string[] : R extends any[] ? R[number] | R[number][] : R extends object ? keyof R | (keyof R)[] : never;\n    type LokiOps<R> = {\n        $eq?: R;\n    } | {\n        $ne?: R;\n    } | {\n        $gt?: R;\n    } | {\n        $gte?: R;\n    } | {\n        $lt?: R;\n    } | {\n        $lte?: R;\n    } | {\n        $between?: [R, R];\n    } | {\n        $in?: R[];\n    } | {\n        $nin?: R[];\n    } | {\n        $keyin?: object;\n    } | {\n        $nkeyin?: object;\n    } | {\n        $definedin?: object;\n    } | {\n        $undefinedin?: object;\n    } | {\n        $regex?: RegExp | string | [string, string];\n    } | {\n        $containsNone?: ContainsHelperType<R>;\n    } | {\n        $containsAny?: ContainsHelperType<R>;\n    } | {\n        $contains?: ContainsHelperType<R>;\n    } | {\n        $type?: string;\n    } | {\n        $finite?: boolean;\n    } | {\n        $size?: number;\n    } | {\n        $len?: number;\n    } | {\n        $where?: (val?: R) => boolean;\n    };\n    type Query<T> = {\n        [P in keyof T]?: LokiOps<T[P]> | T[P];\n    } & {\n        $and?: Query<T>[];\n    } & {\n        $or?: Query<T>[];\n    } & {\n        $fts?: FullTextSearchQuery;\n    };\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/loki/src/unique_index.d.ts",
    "content": "export declare class UniqueIndex {\n    private _field;\n    private _lokiMap;\n    private _valMap;\n    /**\n     * Constructs an unique index object.\n     * @param {string} propertyField - the property field to index\n     */\n    constructor(propertyField: string);\n    /**\n     * Sets a document's unique index.\n     * @param {number} id loki id to associate with value\n     * @param {*} value  value to associate with id\n     */\n    set(id: number, value: any): void;\n    /**\n     * Returns the $loki id of an unique value.\n     * @param {*} value the value to retrieve a loki id match for\n     */\n    get(value: any): number;\n    /**\n     * Updates a document's unique index.\n     * @param {number} id (loki) id of document to update the value to\n     * @param {*} value value to associate with loki id\n     */\n    update(id: number, value: any): void;\n    /**\n     * Removes an unique index.\n     * @param {number} id (loki) id to remove from index\n     */\n    remove(id: number): void;\n    /**\n     * Clears the unique index.\n     */\n    clear(): void;\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/memory-storage/src/index.d.ts",
    "content": "import { MemoryStorage } from \"./memory_storage\";\nexport { MemoryStorage };\nexport default MemoryStorage;\n"
  },
  {
    "path": "dist/packages/local-storage/types/memory-storage/src/memory_storage.d.ts",
    "content": "import { Dict, StorageAdapter } from \"../../common/types\";\n/**\n * An in-memory persistence adapter for an in-memory database.\n * This simple 'key/value' adapter is intended for unit testing and diagnostics.\n */\nexport declare class MemoryStorage implements StorageAdapter {\n    hashStore: Dict<{\n        savecount: number;\n        lastsave: Date;\n        value: string;\n    }>;\n    options: MemoryStorage.Options;\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} options - memory storage options\n     * @param {boolean} [options.asyncResponses=false] - whether callbacks are invoked asynchronously (default: false)\n     * @param {int} [options.asyncTimeout=50] - timeout in ms to queue callbacks (default: 50)\n     */\n    constructor(options?: MemoryStorage.Options);\n    /**\n     * Loads a serialized database from its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * Saves a serialized database to its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {string} dbstring - the database content\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a database from its in-memory store.\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport declare namespace MemoryStorage {\n    interface Options {\n        asyncResponses?: boolean;\n        asyncTimeout?: number;\n    }\n}\n"
  },
  {
    "path": "dist/packages/local-storage/types/partitioning-adapter/src/index.d.ts",
    "content": "import { PartitioningAdapter } from \"./partitioning_adapter\";\nexport { PartitioningAdapter };\nexport default PartitioningAdapter;\n"
  },
  {
    "path": "dist/packages/local-storage/types/partitioning-adapter/src/partitioning_adapter.d.ts",
    "content": "import { Loki } from \"../../loki/src/loki\";\nimport { StorageAdapter } from \"../../common/types\";\n/**\n * An adapter for adapters. Converts a non reference mode adapter into a reference mode adapter\n * which can perform destructuring and partitioning. Each collection will be stored in its own key/save and\n * only dirty collections will be saved. If you  turn on paging with default page size of 25megs and save\n * a 75 meg collection it should use up roughly 3 save slots (key/value pairs sent to inner adapter).\n * A dirty collection that spans three pages will save all three pages again\n * Paging mode was added mainly because Chrome has issues saving 'too large' of a string within a\n * single IndexedDB row. If a single document update causes the collection to be flagged as dirty, all\n * of that collection's pages will be written on next save.\n */\nexport declare class PartitioningAdapter implements StorageAdapter {\n    mode: string;\n    private _adapter;\n    private _dbref;\n    private _dbname;\n    private _pageIterator;\n    private _paging;\n    private _pageSize;\n    private _delimiter;\n    private _dirtyPartitions;\n    /**\n     * Registers the partitioning adapter as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the partitioning storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} adapter - reference to a 'non-reference' mode loki adapter instance.\n     * @param {boolean} paging - (default: false) set to true to enable paging collection data.\n     * @param {number} pageSize - (default : 25MB) you can use this to limit size of strings passed to inner adapter.\n     * @param {string} delimiter - allows you to override the default delimiter\n     */\n    constructor(adapter: StorageAdapter, {paging, pageSize, delimiter}?: {\n        paging?: boolean;\n        pageSize?: number;\n        delimiter?: string;\n    });\n    /**\n     * Loads a database which was partitioned into several key/value saves.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Used to sequentially load each collection partition, one at a time.\n     *\n     * @param {int} partition - ordinal collection position to load next\n     * @returns {Promise} a Promise that resolves after the next partition is loaded\n     */\n    private _loadNextPartition(partition);\n    /**\n     * Used to sequentially load the next page of collection partition, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next page is loaded\n     */\n    private _loadNextPage();\n    /**\n     * Saves a database by partioning into separate key/value saves.\n     * (Loki 'reference mode' persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {object} dbref - reference to database which we will partition and save.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     *\n     */\n    exportDatabase(dbname: string, dbref: Loki): Promise<void>;\n    /**\n     * Helper method used internally to save each dirty collection, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPartition();\n    /**\n     * Helper method used internally to generate and save the next page of the current (dirty) partition.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPage();\n}\n"
  },
  {
    "path": "dist/packages/loki/lokidb.loki.js",
    "content": "(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"@lokidb/loki\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"@lokidb/loki\"] = factory();\n\telse\n\t\t{ root[\"@lokidb/loki\"] = factory(); root[\"Loki\"] = root[\"@lokidb/loki\"].default; }\n})(typeof self !== 'undefined' ? self : this, function() {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// define __esModule on exports\n/******/ \t__webpack_require__.r = function(exports) {\n/******/ \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n/******/ \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n/******/ \t\t}\n/******/ \t\tObject.defineProperty(exports, '__esModule', { value: true });\n/******/ \t};\n/******/\n/******/ \t// create a fake namespace object\n/******/ \t// mode & 1: value is a module id, require it\n/******/ \t// mode & 2: merge all properties of value into the ns\n/******/ \t// mode & 4: return value when already ns object\n/******/ \t// mode & 8|1: behave like require\n/******/ \t__webpack_require__.t = function(value, mode) {\n/******/ \t\tif(mode & 1) value = __webpack_require__(value);\n/******/ \t\tif(mode & 8) return value;\n/******/ \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n/******/ \t\tvar ns = Object.create(null);\n/******/ \t\t__webpack_require__.r(ns);\n/******/ \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n/******/ \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n/******/ \t\treturn ns;\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 8);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return ComparatorMap; });\n/* unused harmony export CreateJavascriptComparator */\n/* unused harmony export CreateAbstractJavascriptComparator */\n/* unused harmony export CreateAbstractDateJavascriptComparator */\n/* unused harmony export CreateLokiComparator */\n/* harmony import */ var _operator_packages__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);\n/**\n * This file contains LokiOperatorPackages, RangedIndex and Comparator interfaces, as well as\n * global map object instances for registered LokiOperatorPackages, RangedIndex implementations, and Comparator functions\n */\n\n/** Map/Register of named ILokiComparer functions returning -1, 0, 1 for lt/eq/gt assertions for two passed parameters */\nlet ComparatorMap = {\n    \"js\": CreateJavascriptComparator(),\n    \"abstract-js\": CreateAbstractJavascriptComparator(),\n    \"abstract-date\": CreateAbstractDateJavascriptComparator(),\n    \"loki\": CreateLokiComparator()\n};\n/** Typescript-friendly factory for strongly typed 'js' comparators */\nfunction CreateJavascriptComparator() {\n    return (val, val2) => {\n        if (val === val2)\n            return 0;\n        if (val < val2)\n            return -1;\n        return 1;\n    };\n}\n/** Typescript-friendly factory for strongly typed 'abstract js' comparators */\nfunction CreateAbstractJavascriptComparator() {\n    return (val, val2) => {\n        if (val == val2)\n            return 0;\n        if (val < val2)\n            return -1;\n        return 1;\n    };\n}\n/**\n * Comparator which attempts to deal with deal with dates at comparator level.\n * Should work for dates in any of the object, string, and number formats\n */\nfunction CreateAbstractDateJavascriptComparator() {\n    return (val, val2) => {\n        let v1 = (new Date(val).toISOString());\n        let v2 = (new Date(val2).toISOString());\n        if (v1 == v2)\n            return 0;\n        if (v1 < v2)\n            return -1;\n        return 1;\n    };\n}\n/** Typescript-friendly factory for strongly typed 'loki' comparators */\nfunction CreateLokiComparator() {\n    return (val, val2) => {\n        if (Object(_operator_packages__WEBPACK_IMPORTED_MODULE_0__[/* aeqHelper */ \"b\"])(val, val2))\n            return 0;\n        if (Object(_operator_packages__WEBPACK_IMPORTED_MODULE_0__[/* ltHelper */ \"c\"])(val, val2, false))\n            return -1;\n        return 1;\n    };\n}\n\n\n/***/ }),\n/* 1 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return PLUGINS; });\nfunction getGlobal() {\n    let glob;\n    (function (global) {\n        glob = global;\n    })(global !== undefined && global || this);\n    return glob;\n}\nfunction create() {\n    const global = getGlobal();\n    const sym = Symbol.for(\"LOKI\");\n    if (global[sym] === undefined) {\n        global[sym] = {};\n    }\n    return global[sym];\n}\n/**\n * @hidden\n */\nconst PLUGINS = create();\n\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(7)))\n\n/***/ }),\n/* 2 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"b\", function() { return aeqHelper; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"c\", function() { return ltHelper; });\n/* unused harmony export gtHelper */\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"d\", function() { return sortHelper; });\n/* unused harmony export LokiOperatorPackage */\n/* unused harmony export LokiAbstractOperatorPackage */\n/* unused harmony export ComparatorOperatorPackage */\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return LokiOperatorPackageMap; });\n/**\n * Helper function for determining 'loki' abstract equality which is a little more abstract than ==\n *     aeqHelper(5, '5') === true\n *     aeqHelper(5.0, '5') === true\n *     aeqHelper(new Date(\"1/1/2011\"), new Date(\"1/1/2011\")) === true\n *     aeqHelper({a:1}, {z:4}) === true (all objects sorted equally)\n *     aeqHelper([1, 2, 3], [1, 3]) === false\n *     aeqHelper([1, 2, 3], [1, 2, 3]) === true\n *     aeqHelper(undefined, null) === true\n * @param {any} prop1\n * @param {any} prop2\n * @returns {boolean}\n * @hidden\n */\nfunction aeqHelper(prop1, prop2) {\n    if (prop1 === prop2)\n        return true;\n    // 'falsy' and Boolean handling\n    if (!prop1 || !prop2 || prop1 === true || prop2 === true || prop1 !== prop1 || prop2 !== prop2) {\n        let t1;\n        let t2;\n        // dates and NaN conditions (typed dates before serialization)\n        switch (prop1) {\n            case undefined:\n                t1 = 1;\n                break;\n            case null:\n                t1 = 1;\n                break;\n            case false:\n                t1 = 3;\n                break;\n            case true:\n                t1 = 4;\n                break;\n            case \"\":\n                t1 = 5;\n                break;\n            default:\n                t1 = (prop1 === prop1) ? 9 : 0;\n                break;\n        }\n        switch (prop2) {\n            case undefined:\n                t2 = 1;\n                break;\n            case null:\n                t2 = 1;\n                break;\n            case false:\n                t2 = 3;\n                break;\n            case true:\n                t2 = 4;\n                break;\n            case \"\":\n                t2 = 5;\n                break;\n            default:\n                t2 = (prop2 === prop2) ? 9 : 0;\n                break;\n        }\n        // one or both is edge case\n        if (t1 !== 9 || t2 !== 9) {\n            return (t1 === t2);\n        }\n    }\n    // Handle 'Number-like' comparisons\n    let cv1 = Number(prop1);\n    let cv2 = Number(prop2);\n    // if one or both are 'number-like'...\n    if (cv1 === cv1 || cv2 === cv2) {\n        return (cv1 === cv2);\n    }\n    // not strict equal nor less than nor gt so must be mixed types, convert to string and use that to compare\n    cv1 = prop1.toString();\n    cv2 = prop2.toString();\n    return (cv1 == cv2);\n}\n/**\n * Helper function for determining 'less-than' conditions for ops, sorting, and binary indices.\n *     In the future we might want $lt and $gt ops to use their own functionality/helper.\n *     Since binary indices on a property might need to index [12, NaN, new Date(), Infinity], we\n *     need this function (as well as gtHelper) to always ensure one value is LT, GT, or EQ to another.\n * @hidden\n */\nfunction ltHelper(prop1, prop2, equal) {\n    // if one of the params is falsy or strictly true or not equal to itself\n    // 0, 0.0, \"\", NaN, null, undefined, not defined, false, true\n    if (!prop1 || !prop2 || prop1 === true || prop2 === true || prop1 !== prop1 || prop2 !== prop2) {\n        let t1;\n        let t2;\n        switch (prop1) {\n            case undefined:\n                t1 = 1;\n                break;\n            case null:\n                t1 = 1;\n                break;\n            case false:\n                t1 = 3;\n                break;\n            case true:\n                t1 = 4;\n                break;\n            case \"\":\n                t1 = 5;\n                break;\n            // if strict equal probably 0 so sort higher, otherwise probably NaN so sort lower than even null\n            default:\n                t1 = (prop1 === prop1) ? 9 : 0;\n                break;\n        }\n        switch (prop2) {\n            case undefined:\n                t2 = 1;\n                break;\n            case null:\n                t2 = 1;\n                break;\n            case false:\n                t2 = 3;\n                break;\n            case true:\n                t2 = 4;\n                break;\n            case \"\":\n                t2 = 5;\n                break;\n            default:\n                t2 = (prop2 === prop2) ? 9 : 0;\n                break;\n        }\n        // one or both is edge case\n        if (t1 !== 9 || t2 !== 9) {\n            return (t1 === t2) ? equal : (t1 < t2);\n        }\n    }\n    // if both are numbers (string encoded or not), compare as numbers\n    let cv1 = Number(prop1);\n    let cv2 = Number(prop2);\n    if (cv1 === cv1 && cv2 === cv2) {\n        if (cv1 < cv2)\n            return true;\n        if (cv1 > cv2)\n            return false;\n        return equal;\n    }\n    if (cv1 === cv1 && cv2 !== cv2) {\n        return true;\n    }\n    if (cv2 === cv2 && cv1 !== cv1) {\n        return false;\n    }\n    if (prop1 < prop2)\n        return true;\n    if (prop1 > prop2)\n        return false;\n    if (prop1 == prop2)\n        return equal;\n    // not strict equal nor less than nor gt so must be mixed types, convert to string and use that to compare\n    cv1 = prop1.toString();\n    cv2 = prop2.toString();\n    if (cv1 < cv2) {\n        return true;\n    }\n    if (cv1 == cv2) {\n        return equal;\n    }\n    return false;\n}\n/**\n * @hidden\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} equal\n * @returns {boolean}\n */\nfunction gtHelper(prop1, prop2, equal) {\n    // 'falsy' and Boolean handling\n    if (!prop1 || !prop2 || prop1 === true || prop2 === true || prop1 !== prop1 || prop2 !== prop2) {\n        let t1;\n        let t2;\n        switch (prop1) {\n            case undefined:\n                t1 = 1;\n                break;\n            case null:\n                t1 = 1;\n                break;\n            case false:\n                t1 = 3;\n                break;\n            case true:\n                t1 = 4;\n                break;\n            case \"\":\n                t1 = 5;\n                break;\n            // NaN 0\n            default:\n                t1 = (prop1 === prop1) ? 9 : 0;\n                break;\n        }\n        switch (prop2) {\n            case undefined:\n                t2 = 1;\n                break;\n            case null:\n                t2 = 1;\n                break;\n            case false:\n                t2 = 3;\n                break;\n            case true:\n                t2 = 4;\n                break;\n            case \"\":\n                t2 = 5;\n                break;\n            default:\n                t2 = (prop2 === prop2) ? 9 : 0;\n                break;\n        }\n        // one or both is edge case\n        if (t1 !== 9 || t2 !== 9) {\n            return (t1 === t2) ? equal : (t1 > t2);\n        }\n    }\n    // if both are numbers (string encoded or not), compare as numbers\n    let cv1 = Number(prop1);\n    let cv2 = Number(prop2);\n    if (cv1 === cv1 && cv2 === cv2) {\n        if (cv1 > cv2)\n            return true;\n        if (cv1 < cv2)\n            return false;\n        return equal;\n    }\n    if (cv1 === cv1 && cv2 !== cv2) {\n        return false;\n    }\n    if (cv2 === cv2 && cv1 !== cv1) {\n        return true;\n    }\n    if (prop1 > prop2)\n        return true;\n    if (prop1 < prop2)\n        return false;\n    if (prop1 == prop2)\n        return equal;\n    // not strict equal nor less than nor gt so must be dates or mixed types\n    // convert to string and use that to compare\n    cv1 = prop1.toString();\n    cv2 = prop2.toString();\n    if (cv1 > cv2) {\n        return true;\n    }\n    if (cv1 == cv2) {\n        return equal;\n    }\n    return false;\n}\n/**\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} descending\n * @returns {number}\n * @hidden\n */\nfunction sortHelper(prop1, prop2, descending) {\n    if (aeqHelper(prop1, prop2)) {\n        return 0;\n    }\n    if (ltHelper(prop1, prop2, false)) {\n        return descending ? 1 : -1;\n    }\n    if (gtHelper(prop1, prop2, false)) {\n        return descending ? -1 : 1;\n    }\n    // not lt, not gt so implied equality-- date compatible\n    return 0;\n}\n/**\n * Default implementation of LokiOperatorPackage, using fastest javascript comparison operators.\n */\nclass LokiOperatorPackage {\n    // comparison operators\n    // a is the value in the collection\n    // b is the query value\n    $eq(a, b) {\n        return a === b;\n    }\n    $ne(a, b) {\n        return a !== b;\n    }\n    $gt(a, b) {\n        return a > b;\n    }\n    $gte(a, b) {\n        return a >= b;\n    }\n    $lt(a, b) {\n        return a < b;\n    }\n    $lte(a, b) {\n        return a <= b;\n    }\n    $between(a, range) {\n        if (a === undefined || a === null)\n            return false;\n        return a >= range[0] && a <= range[1];\n    }\n    $in(a, b) {\n        return b.indexOf(a) !== -1;\n    }\n    $nin(a, b) {\n        return b.indexOf(a) === -1;\n    }\n    $keyin(a, b) {\n        return a in b;\n    }\n    $nkeyin(a, b) {\n        return !(a in b);\n    }\n    $definedin(a, b) {\n        return b[a] !== undefined;\n    }\n    $undefinedin(a, b) {\n        return b[a] === undefined;\n    }\n    $regex(a, b) {\n        return b.test(a);\n    }\n    $containsNone(a, b) {\n        return !this.$containsAny(a, b);\n    }\n    $containsAny(a, b) {\n        const checkFn = this.containsCheckFn(a);\n        if (checkFn !== null) {\n            return (Array.isArray(b)) ? (b.some(checkFn)) : (checkFn(b));\n        }\n        return false;\n    }\n    $contains(a, b) {\n        const checkFn = this.containsCheckFn(a);\n        if (checkFn !== null) {\n            return (Array.isArray(b)) ? (b.every(checkFn)) : (checkFn(b));\n        }\n        return false;\n    }\n    $type(a, b) {\n        let type = typeof a;\n        if (type === \"object\") {\n            if (Array.isArray(a)) {\n                type = \"array\";\n            }\n            else if (a instanceof Date) {\n                type = \"date\";\n            }\n        }\n        return (typeof b !== \"object\") ? (type === b) : this.doQueryOp(type, b);\n    }\n    $finite(a, b) {\n        return (b === isFinite(a));\n    }\n    $size(a, b) {\n        if (Array.isArray(a)) {\n            return (typeof b !== \"object\") ? (a.length === b) : this.doQueryOp(a.length, b);\n        }\n        return false;\n    }\n    $len(a, b) {\n        if (typeof a === \"string\") {\n            return (typeof b !== \"object\") ? (a.length === b) : this.doQueryOp(a.length, b);\n        }\n        return false;\n    }\n    $where(a, b) {\n        return b(a) === true;\n    }\n    // field-level logical operators\n    // a is the value in the collection\n    // b is the nested query operation (for '$not')\n    //   or an array of nested query operations (for '$and' and '$or')\n    $not(a, b) {\n        return !this.doQueryOp(a, b);\n    }\n    $and(a, b) {\n        for (let idx = 0, len = b.length; idx < len; idx++) {\n            if (!this.doQueryOp(a, b[idx])) {\n                return false;\n            }\n        }\n        return true;\n    }\n    $or(a, b) {\n        for (let idx = 0, len = b.length; idx < len; idx++) {\n            if (this.doQueryOp(a, b[idx])) {\n                return true;\n            }\n        }\n        return false;\n    }\n    doQueryOp(val, op) {\n        for (let p in op) {\n            if (Object.hasOwnProperty.call(op, p)) {\n                return this[p](val, op[p]);\n            }\n        }\n        return false;\n    }\n    containsCheckFn(a) {\n        if (typeof a === \"string\" || Array.isArray(a)) {\n            return (b) => a.indexOf(b) !== -1;\n        }\n        else if (typeof a === \"object\" && a !== null) {\n            return (b) => Object.hasOwnProperty.call(a, b);\n        }\n        return null;\n    }\n}\n/**\n * LokiOperatorPackage which utilizes abstract 'loki' comparisons for basic relational equality op implementations.\n */\nclass LokiAbstractOperatorPackage extends LokiOperatorPackage {\n    constructor() {\n        super();\n    }\n    $eq(a, b) {\n        return aeqHelper(a, b);\n    }\n    $ne(a, b) {\n        return !aeqHelper(a, b);\n    }\n    $gt(a, b) {\n        return gtHelper(a, b, false);\n    }\n    $gte(a, b) {\n        return gtHelper(a, b, true);\n    }\n    $lt(a, b) {\n        return ltHelper(a, b, false);\n    }\n    $lte(a, b) {\n        return ltHelper(a, b, true);\n    }\n    $between(a, range) {\n        if (a === undefined || a === null)\n            return false;\n        return gtHelper(a, range[0], true) && ltHelper(a, range[1], true);\n    }\n}\n/**\n * LokiOperatorPackage which utilizes provided comparator for basic relational equality op implementations.\n */\nclass ComparatorOperatorPackage extends LokiOperatorPackage {\n    constructor(comparator) {\n        super();\n        this.comparator = comparator;\n    }\n    $eq(a, b) {\n        return this.comparator(a, b) === 0;\n    }\n    $ne(a, b) {\n        return this.comparator(a, b) !== 0;\n    }\n    $gt(a, b) {\n        return this.comparator(a, b) === 1;\n    }\n    $gte(a, b) {\n        return this.comparator(a, b) > -1;\n    }\n    $lt(a, b) {\n        return this.comparator(a, b) === -1;\n    }\n    $lte(a, b) {\n        return this.comparator(a, b) < 1;\n    }\n    $between(a, range) {\n        if (a === undefined || a === null)\n            return false;\n        return this.comparator(a, range[0]) > -1 && this.comparator(a, range[1]) < 1;\n    }\n}\n/**\n * Map/Register of named LokiOperatorPackages which implement all unindexed query ops within 'find' query objects\n */\nlet LokiOperatorPackageMap = {\n    \"js\": new LokiOperatorPackage(),\n    \"loki\": new LokiAbstractOperatorPackage()\n};\n\n\n/***/ }),\n/* 3 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// EXTERNAL MODULE: ./packages/loki/src/event_emitter.ts\nvar event_emitter = __webpack_require__(5);\n\n// CONCATENATED MODULE: ./packages/loki/src/unique_index.ts\nclass UniqueIndex {\n    /**\n     * Constructs an unique index object.\n     * @param {string} propertyField - the property field to index\n     */\n    constructor(propertyField) {\n        this._field = propertyField;\n        this._lokiMap = {};\n        this._valMap = {};\n    }\n    /**\n     * Sets a document's unique index.\n     * @param {number} id loki id to associate with value\n     * @param {*} value  value to associate with id\n     */\n    set(id, value) {\n        // unique index should not include null/undefined values\n        if (value !== null && value !== undefined) {\n            if (value in this._lokiMap) {\n                throw new Error(\"Duplicate key for property \" + this._field + \": \" + value);\n            }\n            if (id in this._valMap) {\n                throw new Error(\"Duplicate key for property $loki : \" + id);\n            }\n            this._lokiMap[value] = id;\n            this._valMap[id] = value;\n        }\n    }\n    /**\n     * Returns the $loki id of an unique value.\n     * @param {*} value the value to retrieve a loki id match for\n     */\n    get(value) {\n        return this._lokiMap[value];\n    }\n    /**\n     * Updates a document's unique index.\n     * @param {number} id (loki) id of document to update the value to\n     * @param {*} value value to associate with loki id\n     */\n    update(id, value) {\n        // if the value has not changed, do nothing\n        if (value === this._valMap[id]) {\n            return;\n        }\n        // the value must have changed, so check if new value already exists\n        if (value in this._lokiMap) {\n            throw new Error(\"Duplicate key for property \" + this._field + \": \" + value);\n        }\n        this.remove(id);\n        this.set(id, value);\n    }\n    /**\n     * Removes an unique index.\n     * @param {number} id (loki) id to remove from index\n     */\n    remove(id) {\n        if (!(id in this._valMap)) {\n            throw new Error(\"Key is not in unique index: \" + this._field);\n        }\n        let oldValue = this._valMap[id];\n        delete this._lokiMap[oldValue];\n        delete this._valMap[id];\n    }\n    /**\n     * Clears the unique index.\n     */\n    clear() {\n        this._lokiMap = {};\n        this._valMap = {};\n    }\n}\n\n// CONCATENATED MODULE: ./packages/loki/src/clone.ts\nfunction add(copy, key, value) {\n    if (copy instanceof Array) {\n        copy.push(value);\n        return copy[copy.length - 1];\n    }\n    else if (copy instanceof Object) {\n        copy[key] = value;\n        return copy[key];\n    }\n}\nfunction walk(target, copy) {\n    for (let key in target) {\n        let obj = target[key];\n        if (obj instanceof Date) {\n            let value = new Date(obj.getTime());\n            add(copy, key, value);\n        }\n        else if (obj instanceof Function) {\n            let value = obj;\n            add(copy, key, value);\n        }\n        else if (obj instanceof Array) {\n            let value = [];\n            let last = add(copy, key, value);\n            walk(obj, last);\n        }\n        else if (obj instanceof Object) {\n            let value = {};\n            let last = add(copy, key, value);\n            walk(obj, last);\n        }\n        else {\n            let value = obj;\n            add(copy, key, value);\n        }\n    }\n}\n// Deep copy from Simeon Velichkov.\n/**\n * @param target\n * @returns {any}\n */\nfunction deepCopy(target) {\n    if (/number|string|boolean/.test(typeof target)) {\n        return target;\n    }\n    else if (target instanceof Date) {\n        return new Date(target.getTime());\n    }\n    const copy = (target instanceof Array) ? [] : {};\n    walk(target, copy);\n    return copy;\n}\n/**\n * @hidden\n */\nfunction clone(data, method = \"parse-stringify\") {\n    if (data === null || data === undefined) {\n        return null;\n    }\n    let cloned;\n    switch (method) {\n        case \"parse-stringify\":\n            cloned = JSON.parse(JSON.stringify(data));\n            break;\n        case \"deep\":\n            cloned = deepCopy(data);\n            break;\n        case \"shallow\":\n            cloned = Object.create(data.constructor.prototype);\n            Object.assign(cloned, data);\n            break;\n        case \"shallow-recurse\":\n            // shallow clone top level properties\n            cloned = clone(data, \"shallow\");\n            const keys = Object.keys(data);\n            // for each of the top level properties which are object literals, recursively shallow copy\n            for (let i = 0; i < keys.length; i++) {\n                const key = keys[i];\n                if (typeof data[key] === \"object\" && data[key].constructor.name === \"Object\") {\n                    cloned[key] = clone(data[key], \"shallow-recurse\");\n                }\n            }\n            break;\n        default:\n            break;\n    }\n    return cloned;\n}\n\n// EXTERNAL MODULE: ./packages/loki/src/operator_packages.ts\nvar operator_packages = __webpack_require__(2);\n\n// EXTERNAL MODULE: ./packages/loki/src/comparators.ts\nvar comparators = __webpack_require__(0);\n\n// CONCATENATED MODULE: ./packages/loki/src/result_set.ts\n\n\n\n\n// used to recursively scan hierarchical transform step object for param substitution\nfunction resolveTransformObject(subObj, params, depth = 0) {\n    if (++depth >= 10) {\n        return subObj;\n    }\n    for (const prop in subObj) {\n        if (typeof subObj[prop] === \"string\" && subObj[prop].indexOf(\"[%lktxp]\") === 0) {\n            const pname = subObj[prop].substring(8);\n            if (params[pname] !== undefined) {\n                subObj[prop] = params[pname];\n            }\n        }\n        else if (typeof subObj[prop] === \"object\") {\n            subObj[prop] = resolveTransformObject(subObj[prop], params, depth);\n        }\n    }\n    return subObj;\n}\n// top level utility to resolve an entire (single) transform (array of steps) for parameter substitution\nfunction resolveTransformParams(transform, params) {\n    if (params === undefined) {\n        return transform;\n    }\n    // iterate all steps in the transform array\n    const resolvedTransform = [];\n    for (let idx = 0; idx < transform.length; idx++) {\n        // clone transform so our scan/replace can operate directly on cloned transform\n        const clonedStep = clone(transform[idx], \"shallow-recurse\");\n        resolvedTransform.push(resolveTransformObject(clonedStep, params));\n    }\n    return resolvedTransform;\n}\n/**\n * @hidden\n */\n// if an op is registered in this object, our 'calculateRange' can use it with our binary indices.\n// if the op is registered to a function, we will run that function/op as a 2nd pass filter on results.\n// those 2nd pass filter functions should be similar to LokiOps functions, accepting 2 vals to compare.\nconst indexedOps = {\n    $eq: true,\n    $dteq: true,\n    $gt: true,\n    $gte: true,\n    $lt: true,\n    $lte: true,\n    $in: true,\n    $between: true\n};\n/**\n * ResultSet class allowing chainable queries.  Intended to be instanced internally.\n *    Collection.find(), Collection.where(), and Collection.chain() instantiate this.\n *\n * @example\n *    mycollection.chain()\n *      .find({ 'doors' : 4 })\n *      .where(function(obj) { return obj.name === 'Toyota' })\n *      .data();\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nclass result_set_ResultSet {\n    /**\n     * Constructor.\n     * @param {Collection} collection - the collection which this ResultSet will query against\n     */\n    constructor(collection) {\n        this._filteredRows = [];\n        this._filterInitialized = false;\n        // Holds the scoring result of the last full-text search.\n        this._scoring = null;\n        // retain reference to collection we are querying against\n        this._collection = collection;\n    }\n    /**\n     * Reset the ResultSet to its initial state.\n     * @returns {ResultSet} Reference to this ResultSet, for future chain operations.\n     */\n    reset() {\n        if (this._filteredRows.length > 0) {\n            this._filteredRows = [];\n        }\n        this._filterInitialized = false;\n        return this;\n    }\n    /**\n     * Override of toJSON to avoid circular references\n     */\n    toJSON() {\n        const copy = this.copy();\n        copy._collection = null;\n        return copy;\n    }\n    /**\n     * Allows you to limit the number of documents passed to next chain operation.\n     * A ResultSet copy() is made to avoid altering original ResultSet.\n     * @param {int} qty - The number of documents to return.\n     * @returns {ResultSet} Returns a copy of the ResultSet, limited by qty, for subsequent chain ops.\n     */\n    limit(qty) {\n        // if this has no filters applied, we need to populate filteredRows first\n        if (!this._filterInitialized && this._filteredRows.length === 0) {\n            this._filteredRows = this._collection._prepareFullDocIndex();\n        }\n        this._filteredRows = this._filteredRows.slice(0, qty);\n        this._filterInitialized = true;\n        return this;\n    }\n    /**\n     * Used for skipping 'pos' number of documents in the ResultSet.\n     * @param {int} pos - Number of documents to skip; all preceding documents are filtered out.\n     * @returns {ResultSet} Returns a copy of the ResultSet, containing docs starting at 'pos' for subsequent chain ops.\n     */\n    offset(pos) {\n        // if this has no filters applied, we need to populate filteredRows first\n        if (!this._filterInitialized && this._filteredRows.length === 0) {\n            this._filteredRows = this._collection._prepareFullDocIndex();\n        }\n        this._filteredRows = this._filteredRows.slice(pos);\n        this._filterInitialized = true;\n        return this;\n    }\n    /**\n     * To support reuse of ResultSet in branched query situations.\n     * @returns {ResultSet} Returns a copy of the ResultSet (set) but the underlying document references will be the same.\n     */\n    copy() {\n        const result = new result_set_ResultSet(this._collection);\n        result._filteredRows = this._filteredRows.slice();\n        result._filterInitialized = this._filterInitialized;\n        return result;\n    }\n    /**\n     * Executes a named collection transform or raw array of transform steps against the ResultSet.\n     * @param {(string|array)} transform - name of collection transform or raw transform array\n     * @param {object} [parameters=] - object property hash of parameters, if the transform requires them.\n     * @returns {ResultSet} either (this) ResultSet or a clone of of this ResultSet (depending on steps)\n     */\n    transform(transform, parameters) {\n        // if transform is name, then do lookup first\n        if (typeof transform === \"string\") {\n            transform = this._collection._transforms[transform];\n        }\n        if (parameters !== undefined) {\n            transform = resolveTransformParams(transform, parameters);\n        }\n        let rs = this;\n        for (let idx = 0; idx < transform.length; idx++) {\n            const step = transform[idx];\n            switch (step.type) {\n                case \"find\":\n                    rs.find(step.value);\n                    break;\n                case \"where\":\n                    rs.where(step.value);\n                    break;\n                case \"simplesort\":\n                    rs.simplesort(step.property, step.options);\n                    break;\n                case \"compoundsort\":\n                    rs.compoundsort(step.value);\n                    break;\n                case \"sort\":\n                    rs.sort(step.value);\n                    break;\n                case \"sortByScoring\":\n                    rs.sortByScoring(step.desc);\n                    break;\n                case \"limit\":\n                    rs = rs.limit(step.value);\n                    break; // limit makes copy so update reference\n                case \"offset\":\n                    rs = rs.offset(step.value);\n                    break; // offset makes copy so update reference\n                case \"map\":\n                    rs = rs.map(step.value, step.dataOptions);\n                    break;\n                case \"eqJoin\":\n                    rs = rs.eqJoin(step.joinData, step.leftJoinKey, step.rightJoinKey, step.mapFun, step.dataOptions);\n                    break;\n                // following cases break chain by returning array data so make any of these last in transform steps\n                case \"mapReduce\":\n                    rs = rs.mapReduce(step.mapFunction, step.reduceFunction);\n                    break;\n                // following cases update documents in current filtered ResultSet (use carefully)\n                case \"update\":\n                    rs.update(step.value);\n                    break;\n                case \"remove\":\n                    rs.remove();\n                    break;\n                default:\n                    break;\n            }\n        }\n        return rs;\n    }\n    /**\n     * User supplied compare function is provided two documents to compare. (chainable)\n     * @example\n     *    rslt.sort(function(obj1, obj2) {\n       *      if (obj1.name === obj2.name) return 0;\n       *      if (obj1.name > obj2.name) return 1;\n       *      if (obj1.name < obj2.name) return -1;\n       *    });\n     * @param {function} comparefun - A javascript compare function used for sorting.\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    sort(comparefun) {\n        // if this has no filters applied, just we need to populate filteredRows first\n        if (!this._filterInitialized && this._filteredRows.length === 0) {\n            this._filteredRows = this._collection._prepareFullDocIndex();\n        }\n        const data = this._collection._data;\n        const wrappedComparer = (a, b) => comparefun(data[a], data[b]);\n        this._filteredRows.sort(wrappedComparer);\n        return this;\n    }\n    /**\n     * Simpler, loose evaluation for user to sort based on a property name. (chainable).\n     * Sorting based on the same lt/gt helper functions used for binary indices.\n     * @param {string} propname - name of property to sort by.\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether to sort descending\n     * @param {string} [options.sortComparator] override default with name of comparator registered in ComparatorMap\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    simplesort(propname, options = { desc: false }) {\n        if (typeof options === \"boolean\") {\n            options = {\n                desc: options\n            };\n        }\n        if (!this._filterInitialized && this._collection._rangedIndexes.hasOwnProperty(propname)) {\n            let sortedIds = this._collection._rangedIndexes[propname].index.rangeRequest();\n            let dataPositions = [];\n            // until we refactor resultset to store $loki ids in filteredrows,\n            // we need to convert $loki ids to data array positions\n            for (let id of sortedIds) {\n                dataPositions.push(this._collection.get(id, true)[1]);\n            }\n            this._filteredRows = options.desc ? dataPositions.reverse() : dataPositions;\n            this._filterInitialized = true;\n            return this;\n        }\n        // if this has no filters applied, just we need to populate filteredRows first\n        if (!this._filterInitialized && this._filteredRows.length === 0) {\n            this._filteredRows = this._collection._prepareFullDocIndex();\n        }\n        const data = this._collection._data;\n        let comparator = (options.sortComparator) ?\n            comparators[\"a\" /* ComparatorMap */][options.sortComparator] :\n            comparators[\"a\" /* ComparatorMap */][this._collection._unindexedSortComparator];\n        const wrappedComparer = (a, b) => {\n            return comparator(data[a][propname], data[b][propname]);\n        };\n        this._filteredRows.sort(wrappedComparer);\n        if (options.desc) {\n            this._filteredRows.reverse();\n        }\n        return this;\n    }\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * rs.compoundsort(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * rs.compoundsort(['age', ['name', true]);\n     * @param {array} properties - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    compoundsort(properties) {\n        if (properties.length === 0) {\n            throw new Error(\"Invalid call to compoundsort, need at least one property\");\n        }\n        if (properties.length === 1) {\n            const prop = properties[0];\n            if (typeof prop === \"string\") {\n                return this.simplesort(prop, false);\n            }\n            else {\n                return this.simplesort(prop[0], prop[1]);\n            }\n        }\n        // unify the structure of 'properties' to avoid checking it repeatedly while sorting\n        for (let i = 0, len = properties.length; i < len; i++) {\n            const prop = properties[i];\n            if (typeof prop === \"string\") {\n                properties[i] = [prop, false];\n            }\n        }\n        // if this has no filters applied, just we need to populate filteredRows first\n        if (!this._filterInitialized && this._filteredRows.length === 0) {\n            this._filteredRows = this._collection._prepareFullDocIndex();\n        }\n        const data = this._collection._data;\n        const wrappedComparer = (a, b) => this._compoundeval(properties, data[a], data[b]);\n        this._filteredRows.sort(wrappedComparer);\n        return this;\n    }\n    /**\n     * Helper function for compoundsort(), performing individual object comparisons\n     * @param {Array} properties - array of property names, in order, by which to evaluate sort order\n     * @param {object} obj1 - first object to compare\n     * @param {object} obj2 - second object to compare\n     * @returns {number} 0, -1, or 1 to designate if identical (sortwise) or which should be first\n     */\n    _compoundeval(properties, obj1, obj2) {\n        for (let i = 0, len = properties.length; i < len; i++) {\n            const prop = properties[i];\n            const field = prop[0];\n            const res = Object(operator_packages[\"d\" /* sortHelper */])(obj1[field], obj2[field], prop[1]);\n            if (res !== 0) {\n                return res;\n            }\n        }\n        return 0;\n    }\n    /**\n     * Sorts the ResultSet based on the last full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     * @returns {ResultSet}\n     */\n    sortByScoring(ascending = false) {\n        if (this._scoring === null) {\n            throw new Error(\"No scoring available\");\n        }\n        if (ascending) {\n            this._filteredRows.sort((a, b) => this._scoring[a].score - this._scoring[b].score);\n        }\n        else {\n            this._filteredRows.sort((a, b) => this._scoring[b].score - this._scoring[a].score);\n        }\n        return this;\n    }\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring() {\n        if (this._scoring === null) {\n            throw new Error(\"No scoring available\");\n        }\n        const scoring = [];\n        for (let i = 0; i < this._filteredRows.length; i++) {\n            scoring.push(this._scoring[this._filteredRows[i]]);\n        }\n        return scoring;\n    }\n    /**\n     * Oversee the operation of OR'ed query expressions.\n     * OR'ed expression evaluation runs each expression individually against the full collection,\n     * and finally does a set OR on each expression's results.\n     * Each evaluation can utilize a binary index to prevent multiple linear array scans.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findOr(expressionArray) {\n        const docset = [];\n        const idxset = [];\n        const origCount = this.count();\n        // If filter is already initialized, then we query against only those items already in filter.\n        // This means no index utilization for fields, so hopefully its filtered to a smallish filteredRows.\n        for (let ei = 0, elen = expressionArray.length; ei < elen; ei++) {\n            // we need to branch existing query to run each filter separately and combine results\n            const fr = this.copy().find(expressionArray[ei])._filteredRows;\n            const frlen = fr.length;\n            // if the find operation did not reduce the initial set, then the initial set is the actual result\n            if (frlen === origCount) {\n                return this;\n            }\n            // add any document 'hits'\n            for (let fri = 0; fri < frlen; fri++) {\n                const idx = fr[fri];\n                if (idxset[idx] === undefined) {\n                    idxset[idx] = true;\n                    docset.push(idx);\n                }\n            }\n        }\n        this._filteredRows = docset;\n        this._filterInitialized = true;\n        return this;\n    }\n    $or(expressionArray) {\n        return this.findOr(expressionArray);\n    }\n    /**\n     * Oversee the operation of AND'ed query expressions.\n     * AND'ed expression evaluation runs each expression progressively against the full collection,\n     * internally utilizing existing chained ResultSet functionality.\n     * Only the first filter can utilize a binary index.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findAnd(expressionArray) {\n        // we have already implementing method chaining in this (our ResultSet class)\n        // so lets just progressively apply user supplied and filters\n        for (let i = 0, len = expressionArray.length; i < len; i++) {\n            if (this.count() === 0) {\n                return this;\n            }\n            this.find(expressionArray[i]);\n        }\n        return this;\n    }\n    $and(expressionArray) {\n        return this.findAnd(expressionArray);\n    }\n    /**\n     * Used for querying via a mongo-style query object.\n     *\n     * @param {object} query - A mongo-style query object used for filtering current results.\n     * @param {boolean} firstOnly - (Optional) Used by collection.findOne() - flag if this was invoked via findOne()\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    find(query, firstOnly = false) {\n        if (this._collection._data.length === 0) {\n            this._filteredRows = [];\n            this._filterInitialized = true;\n            return this;\n        }\n        const queryObject = query || \"getAll\";\n        let property;\n        let queryObjectOp;\n        let value;\n        if (typeof queryObject === \"object\") {\n            let filters = [];\n            for (let p in queryObject) {\n                let obj = {};\n                obj[p] = queryObject[p];\n                filters.push(obj);\n                if (queryObject[p] !== undefined) {\n                    property = p;\n                    queryObjectOp = queryObject[p];\n                }\n            }\n            // if more than one expression in single query object,\n            // convert implicit $and to explicit $and\n            if (filters.length > 1) {\n                return this.find({ \"$and\": filters }, firstOnly);\n            }\n        }\n        // apply no filters if they want all\n        if (!property || queryObject === \"getAll\") {\n            if (firstOnly) {\n                this._filteredRows = (this._collection._data.length > 0) ? [0] : [];\n                this._filterInitialized = true;\n            }\n            return this;\n        }\n        // injecting $and and $or expression tree evaluation here.\n        if (property === \"$and\" || property === \"$or\") {\n            this[property](queryObjectOp);\n            // for chained find with firstOnly,\n            if (firstOnly && this._filteredRows.length > 1) {\n                this._filteredRows = this._filteredRows.slice(0, 1);\n            }\n            return this;\n        }\n        // see if query object is in shorthand mode (assuming eq operator)\n        let operator = \"\";\n        if (queryObjectOp === null || (typeof queryObjectOp !== \"object\" || queryObjectOp instanceof Date)) {\n            operator = \"$eq\";\n            value = queryObjectOp;\n        }\n        else if (typeof queryObjectOp === \"object\") {\n            for (let key in queryObjectOp) {\n                if (queryObjectOp[key] !== undefined) {\n                    operator = key;\n                    value = queryObjectOp[key];\n                    break;\n                }\n            }\n        }\n        else {\n            throw new Error(\"Do not know what you want to do.\");\n        }\n        // for regex ops, precompile\n        if (operator === \"$regex\") {\n            if (Array.isArray(value)) {\n                value = new RegExp(value[0], value[1]);\n            }\n            else if (!(value instanceof RegExp)) {\n                value = new RegExp(value);\n            }\n        }\n        // if an index exists for the property being queried against, use it\n        // for now only enabling where it is the first filter applied and prop is indexed\n        const doIndexCheck = !this._filterInitialized;\n        let searchByIndex = false;\n        if (doIndexCheck && this._collection._rangedIndexes[property] && indexedOps[operator]) {\n            searchByIndex = true;\n        }\n        // the comparison function\n        const operatorPackage = operator_packages[\"a\" /* LokiOperatorPackageMap */][this._collection._defaultLokiOperatorPackage];\n        // \"shortcut\" for collection data\n        const data = this._collection._data;\n        // Query executed differently depending on :\n        //    - whether the property being queried has an index defined\n        //    - if chained, we handle first pass differently for initial filteredRows[] population\n        //\n        // For performance reasons, each case has its own if block to minimize in-loop calculations\n        let result = [];\n        // If the filteredRows[] is already initialized, use it\n        if (this._filterInitialized) {\n            let filter = this._filteredRows;\n            if (property === \"$fts\") {\n                this._scoring = this._collection._fullTextSearch.search(queryObject.$fts);\n                let keys = Object.keys(this._scoring);\n                for (let i = 0; i < keys.length; i++) {\n                    if (filter.indexOf(+keys[i]) !== -1) {\n                        result.push(+keys[i]);\n                    }\n                }\n            }\n            else if (this._collection._constraints.unique[property] !== undefined && operator === \"$eq\") {\n                // convert back to position for filtered rows (until we refactor filteredrows to store $loki instead of data pos)\n                const id = this._collection._constraints.unique[property].get(value);\n                if (id !== undefined) {\n                    const row = this._collection.get(id, true)[1];\n                    if (filter.indexOf(row) !== -1) {\n                        result.push(row);\n                    }\n                }\n            }\n            else {\n                for (let i = 0; i < filter.length; i++) {\n                    let rowIdx = filter[i];\n                    // calling operator as method property of operator package preserves 'this'\n                    if (operatorPackage[operator](data[rowIdx][property], value)) {\n                        result.push(rowIdx);\n                    }\n                }\n            }\n            this._filteredRows = result;\n            this._filterInitialized = true; // next time work against filteredRows[]\n            return this;\n        }\n        this._filteredRows = result;\n        this._filterInitialized = true; // next time work against filteredRows[]\n        if (property === \"$fts\") {\n            this._scoring = this._collection._fullTextSearch.search(queryObject.$fts);\n            let keys = Object.keys(this._scoring);\n            for (let i = 0; i < keys.length; i++) {\n                result.push(+keys[i]);\n            }\n            return this;\n        }\n        // Use unique constraint for search.\n        if (this._collection._constraints.unique[property] !== undefined && operator === \"$eq\") {\n            // convert back to position for filtered rows (until we refactor filteredrows to store $loki instead of data pos)\n            const id = this._collection._constraints.unique[property].get(value);\n            if (id !== undefined) {\n                result.push(this._collection.get(id, true)[1]);\n            }\n            return this;\n        }\n        // if not searching by index\n        if (!searchByIndex) {\n            // determine comparator to use for ops\n            for (let i = 0; i < data.length; i++) {\n                // calling operator as method property of operator package preserves 'this'\n                if (operatorPackage[operator](data[i][property], value)) {\n                    result.push(i);\n                    if (firstOnly) {\n                        return this;\n                    }\n                }\n            }\n            return this;\n        }\n        // If we have a rangedIndex defined, use that and bail\n        if (this._collection._rangedIndexes[property]) {\n            if (operator === \"$in\") {\n                let ri = this._collection._rangedIndexes[property];\n                // iterate each $in array value\n                for (let val of value) {\n                    // request matches where val eq current iterated val\n                    let idResult = ri.index.rangeRequest({ op: \"$eq\", val: val });\n                    // for each result in match\n                    for (let id of idResult) {\n                        // convert $loki id to data position and add to result (filteredrows)\n                        result.push(this._collection.get(id, true)[1]);\n                    }\n                }\n                return this;\n            }\n            if (operator === \"$between\") {\n                let idResult = this._collection._rangedIndexes[property].index.rangeRequest({\n                    op: operator,\n                    val: value[0],\n                    high: value[1]\n                });\n                // for now we will have to 'shim' the binary tree index's $loki ids back\n                // into data array indices, ideally i would like to repurpose filteredrows to use loki ids\n                for (let id of idResult) {\n                    result.push(this._collection.get(id, true)[1]);\n                }\n                return this;\n            }\n            let idResult = this._collection._rangedIndexes[property].index.rangeRequest({\n                op: operator,\n                val: value\n            });\n            // if our op requires 'second pass'\n            if (indexedOps[operator] !== true) {\n                for (let id of idResult) {\n                    let pos = this._collection.get(id, true)[1];\n                    if (indexedOps[operator](data[pos][property], value)) {\n                        result.push(pos);\n                    }\n                }\n            }\n            else {\n                // for now we will have to 'shim' the binary tree index's $loki ids back\n                // into data array indices, ideally i would like to repurpose filteredrows to use loki ids\n                for (let id of idResult) {\n                    result.push(this._collection.get(id, true)[1]);\n                }\n            }\n        }\n        return this;\n    }\n    /**\n     * Used for filtering via a javascript filter function.\n     * @param {function} fun - A javascript function used for filtering current results by.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    where(fun) {\n        let viewFunction;\n        let result = [];\n        if (\"function\" === typeof fun) {\n            viewFunction = fun;\n        }\n        else {\n            throw new TypeError(\"Argument is not a stored view or a function\");\n        }\n        // If the filteredRows[] is already initialized, use it\n        if (this._filterInitialized) {\n            let j = this._filteredRows.length;\n            while (j--) {\n                if (viewFunction(this._collection._data[this._filteredRows[j]]) === true) {\n                    result.push(this._filteredRows[j]);\n                }\n            }\n            this._filteredRows = result;\n            return this;\n        }\n        // otherwise this is initial chained op, work against data, push into filteredRows[]\n        else {\n            let k = this._collection._data.length;\n            while (k--) {\n                if (viewFunction(this._collection._data[k]) === true) {\n                    result.push(k);\n                }\n            }\n            this._filteredRows = result;\n            this._filterInitialized = true;\n            return this;\n        }\n    }\n    /**\n     * Returns the number of documents in the ResultSet.\n     * @returns {number} The number of documents in the ResultSet.\n     */\n    count() {\n        if (this._filterInitialized) {\n            return this._filteredRows.length;\n        }\n        return this._collection.count();\n    }\n    /**\n     * Terminates the chain and returns array of filtered documents\n     * @param {object} options\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values 'parse-stringify', 'deep', and 'shallow' and\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} Array of documents in the ResultSet\n     */\n    data(options = {}) {\n        let forceClones;\n        let forceCloneMethod;\n        let removeMeta;\n        ({\n            forceClones = false,\n            forceCloneMethod = this._collection._cloneMethod,\n            removeMeta = false\n        } = options);\n        let result = [];\n        let data = this._collection._data;\n        let obj;\n        let method;\n        // if user opts to strip meta, then force clones and use 'shallow' if 'force' options are not present\n        if (removeMeta && !forceClones) {\n            forceClones = true;\n            forceCloneMethod = \"shallow\";\n        }\n        // if collection has delta changes active, then force clones and use CloneMethod.DEEP for effective change tracking of nested objects\n        if (!this._collection._disableDeltaChangesApi) {\n            forceClones = true;\n            forceCloneMethod = \"deep\";\n        }\n        // if this has no filters applied, just return collection.data\n        if (!this._filterInitialized) {\n            if (this._filteredRows.length === 0) {\n                // determine whether we need to clone objects or not\n                if (this._collection._cloneObjects || forceClones) {\n                    method = forceCloneMethod;\n                    for (let i = 0; i < data.length; i++) {\n                        obj = this._collection._defineNestedProperties(clone(data[i], method));\n                        if (removeMeta) {\n                            delete obj.$loki;\n                            delete obj.meta;\n                        }\n                        result.push(obj);\n                    }\n                    return result;\n                }\n                // otherwise we are not cloning so return sliced array with same object references\n                else {\n                    return data.slice();\n                }\n            }\n            else {\n                // filteredRows must have been set manually, so use it\n                this._filterInitialized = true;\n            }\n        }\n        const fr = this._filteredRows;\n        if (this._collection._cloneObjects || forceClones) {\n            method = forceCloneMethod;\n            for (let i = 0; i < fr.length; i++) {\n                obj = this._collection._defineNestedProperties(clone(data[fr[i]], method));\n                if (removeMeta) {\n                    delete obj.$loki;\n                    delete obj.meta;\n                }\n                result.push(obj);\n            }\n        }\n        else {\n            for (let i = 0; i < fr.length; i++) {\n                result.push(data[fr[i]]);\n            }\n        }\n        return result;\n    }\n    /**\n     * Used to run an update operation on all documents currently in the ResultSet.\n     * @param {function} updateFunction - User supplied updateFunction(obj) will be executed for each document object.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    update(updateFunction) {\n        // if this has no filters applied, we need to populate filteredRows first\n        if (!this._filterInitialized && this._filteredRows.length === 0) {\n            this._filteredRows = this._collection._prepareFullDocIndex();\n        }\n        const len = this._filteredRows.length;\n        const rcd = this._collection._data;\n        // pass in each document object currently in ResultSet to user supplied updateFunction\n        for (let idx = 0; idx < len; idx++) {\n            // if we have cloning option specified or are doing differential delta changes, clone object first\n            if (this._collection._cloneObjects || !this._collection._disableDeltaChangesApi) {\n                const obj = clone(rcd[this._filteredRows[idx]], this._collection._cloneMethod);\n                updateFunction(obj);\n                this._collection.update(obj);\n            }\n            else {\n                // no need to clone, so just perform update on collection data object instance\n                updateFunction(rcd[this._filteredRows[idx]]);\n                this._collection.update(rcd[this._filteredRows[idx]]);\n            }\n        }\n        return this;\n    }\n    /**\n     * Removes all document objects which are currently in ResultSet from collection (as well as ResultSet)\n     * @returns {ResultSet} this (empty) ResultSet for further chain ops.\n     */\n    remove() {\n        // if this has no filters applied, we need to populate filteredRows first\n        if (!this._filterInitialized && this._filteredRows.length === 0) {\n            this._filteredRows = this._collection._prepareFullDocIndex();\n        }\n        this._collection.remove(this.data());\n        this._filteredRows = [];\n        return this;\n    }\n    /**\n     * data transformation via user supplied functions\n     *\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns {value} The output of your reduceFunction\n     */\n    mapReduce(mapFunction, reduceFunction) {\n        try {\n            return reduceFunction(this.data().map(mapFunction));\n        }\n        catch (err) {\n            throw err;\n        }\n    }\n    /**\n     * Left joining two sets of data. Join keys can be defined or calculated properties\n     * eqJoin expects the right join key values to be unique.  Otherwise left data will be joined on the last joinData object with that key\n     * @param {Array|ResultSet|Collection} joinData - Data array to join to.\n     * @param {(string|function)} leftJoinKey - Property name in this result set to join on or a function to produce a value to join on\n     * @param {(string|function)} rightJoinKey - Property name in the joinData to join on or a function to produce a value to join on\n     * @param {function} [mapFun=] - a function that receives each matching pair and maps them into output objects - function(left,right){return joinedObject}\n     * @param {object} [dataOptions=] - optional options to apply to data() calls for left and right sides\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} A ResultSet with data in the format [{left: leftObj, right: rightObj}]\n     */\n    eqJoin(joinData, leftJoinKey, rightJoinKey, mapFun, dataOptions) {\n        let rightData = [];\n        let rightDataLength;\n        let key;\n        let result = [];\n        let leftKeyisFunction = typeof leftJoinKey === \"function\";\n        let rightKeyisFunction = typeof rightJoinKey === \"function\";\n        let joinMap = {};\n        //get the left data\n        let leftData = this.data(dataOptions);\n        let leftDataLength = leftData.length;\n        //get the right data\n        if (joinData instanceof collection_Collection) {\n            rightData = joinData.chain().data(dataOptions);\n        }\n        else if (joinData instanceof result_set_ResultSet) {\n            rightData = joinData.data(dataOptions);\n        }\n        else if (Array.isArray(joinData)) {\n            rightData = joinData;\n        }\n        else {\n            throw new TypeError(\"joinData needs to be an array or result set\");\n        }\n        rightDataLength = rightData.length;\n        //construct a lookup table\n        for (let i = 0; i < rightDataLength; i++) {\n            key = rightKeyisFunction\n                ? rightJoinKey(rightData[i])\n                : rightData[i][rightJoinKey];\n            joinMap[key] = rightData[i];\n        }\n        if (!mapFun) {\n            mapFun = (left, right) => ({\n                left,\n                right\n            });\n        }\n        //Run map function over each object in the ResultSet\n        for (let j = 0; j < leftDataLength; j++) {\n            key = leftKeyisFunction\n                ? leftJoinKey(leftData[j])\n                : leftData[j][leftJoinKey];\n            result.push(mapFun(leftData[j], joinMap[key] || {}));\n        }\n        //return a new ResultSet with no filters\n        this._collection = new collection_Collection(\"joinData\");\n        this._collection.insert(result);\n        this._filteredRows = [];\n        this._filterInitialized = false;\n        return this;\n    }\n    /**\n     * Applies a map function into a new collection for further chaining.\n     * @param {function} mapFun - javascript map function\n     * @param {object} [dataOptions=] - options to data() before input to your map function\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - Allows overriding the default or collection specified cloning method\n     * @return {ResultSet}\n     */\n    map(mapFun, dataOptions) {\n        const data = this.data(dataOptions).map(mapFun);\n        //return return a new ResultSet with no filters\n        this._collection = new collection_Collection(\"mappedData\");\n        this._collection.insert(data);\n        this._filteredRows = [];\n        this._filterInitialized = false;\n        return this;\n    }\n}\n\n// CONCATENATED MODULE: ./packages/loki/src/dynamic_view.ts\n\n\n/**\n * DynamicView class is a versatile 'live' view class which can have filters and sorts applied.\n *    Collection.addDynamicView(name) instantiates this DynamicView object and notifies it\n *    whenever documents are add/updated/removed so it can remain up-to-date. (chainable)\n *\n * @example\n * let mydv = mycollection.addDynamicView('test');  // default is non-persistent\n * mydv.applyFind({ 'doors' : 4 });\n * mydv.applyWhere(function(obj) { return obj.name === 'Toyota'; });\n * let results = mydv.data();\n *\n * @extends LokiEventEmitter\n\n * @see {@link Collection#addDynamicView} to construct instances of DynamicView\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nclass dynamic_view_DynamicView extends event_emitter[\"a\" /* LokiEventEmitter */] {\n    /**\n     * Constructor.\n     * @param {Collection} collection - a reference to the collection to work agains\n     * @param {string} name - the name of this dynamic view\n     * @param {object} options - the options\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=\"passive\"] - the sort priority\n     * @param {number} [options.minRebuildInterval=1] - minimum rebuild interval (need clarification to docs here)\n     */\n    constructor(collection, name, options = {}) {\n        super();\n        this._rebuildPending = false;\n        this._resultData = [];\n        this._resultDirty = false;\n        this._cachedResultSet = null;\n        // keep ordered filter pipeline\n        this._filterPipeline = [];\n        // sorting member variables\n        // we only support one active search, applied using applySort() or applySimpleSort()\n        this._sortFunction = null;\n        this._sortCriteria = null;\n        this._sortCriteriaSimple = null;\n        this._sortByScoring = null;\n        this._sortDirty = false;\n        ({\n            persistent: this._persistent = false,\n            // 'passive' will defer the sort phase until they call data(). (most efficient overall)\n            // 'active' will sort async whenever next idle. (prioritizes read speeds)\n            sortPriority: this._sortPriority = \"passive\",\n            minRebuildInterval: this._minRebuildInterval = 1\n        } = options);\n        this._collection = collection;\n        this.name = name;\n        this._resultSet = new result_set_ResultSet(collection);\n        // for now just have 1 event for when we finally rebuilt lazy view\n        // once we refactor transactions, i will tie in certain transactional events\n        this._events = {\n            \"rebuild\": []\n        };\n    }\n    /**\n     * Internally used immediately after deserialization (loading)\n     *    This will clear out and reapply filterPipeline ops, recreating the view.\n     *    Since where filters do not persist correctly, this method allows\n     *    restoring the view to state where user can re-apply those where filters.\n     *\n     * @param removeWhereFilters\n     * @returns {DynamicView} This dynamic view for further chained ops.\n     * @fires DynamicView.rebuild\n     */\n    _rematerialize({ removeWhereFilters = false }) {\n        this._resultData = [];\n        this._resultDirty = true;\n        this._resultSet = new result_set_ResultSet(this._collection);\n        if (this._sortFunction || this._sortCriteria || this._sortCriteriaSimple || this._sortByScoring !== null) {\n            this._sortDirty = true;\n        }\n        if (removeWhereFilters) {\n            // for each view see if it had any where filters applied... since they don't\n            // serialize those functions lets remove those invalid filters\n            let fpi = this._filterPipeline.length;\n            while (fpi--) {\n                if (this._filterPipeline[fpi].type === \"where\") {\n                    if (fpi !== this._filterPipeline.length - 1) {\n                        this._filterPipeline[fpi] = this._filterPipeline[this._filterPipeline.length - 1];\n                    }\n                    this._filterPipeline.length--;\n                }\n            }\n        }\n        // back up old filter pipeline, clear filter pipeline, and reapply pipeline ops\n        const ofp = this._filterPipeline;\n        this._filterPipeline = [];\n        // now re-apply 'find' filterPipeline ops\n        for (let idx = 0; idx < ofp.length; idx++) {\n            this.applyFind(ofp[idx].val);\n        }\n        // during creation of unit tests, i will remove this forced refresh and leave lazy\n        this.data();\n        // emit rebuild event in case user wants to be notified\n        this.emit(\"rebuild\", this);\n        return this;\n    }\n    /**\n     * Makes a copy of the internal ResultSet for branched queries.\n     * Unlike this dynamic view, the branched ResultSet will not be 'live' updated,\n     * so your branched query should be immediately resolved and not held for future evaluation.\n     * @param {(string|array=)} transform - Optional name of collection transform, or an array of transform steps\n     * @param {object} parameters - optional parameters (if optional transform requires them)\n     * @returns {ResultSet} A copy of the internal ResultSet for branched queries.\n     */\n    branchResultSet(transform, parameters) {\n        const rs = this._resultSet.copy();\n        if (transform === undefined) {\n            return rs;\n        }\n        return rs.transform(transform, parameters);\n    }\n    /**\n     * Override of toJSON to avoid circular references.\n     */\n    toJSON() {\n        return {\n            name: this.name,\n            _persistent: this._persistent,\n            _sortPriority: this._sortPriority,\n            _minRebuildInterval: this._minRebuildInterval,\n            _resultSet: this._resultSet,\n            _filterPipeline: this._filterPipeline,\n            _sortCriteria: this._sortCriteria,\n            _sortCriteriaSimple: this._sortCriteriaSimple,\n            _sortByScoring: this._sortByScoring,\n            _sortDirty: this._sortDirty,\n        };\n    }\n    static fromJSONObject(collection, obj) {\n        let dv = new dynamic_view_DynamicView(collection, obj.name);\n        dv._resultDirty = true;\n        dv._filterPipeline = obj._filterPipeline;\n        dv._resultData = [];\n        dv._sortCriteria = obj._sortCriteria;\n        dv._sortCriteriaSimple = obj._sortCriteriaSimple;\n        dv._sortByScoring = obj._sortByScoring;\n        dv._sortDirty = obj._sortDirty;\n        dv._resultSet._filteredRows = obj._resultSet._filteredRows;\n        dv._resultSet._filterInitialized = obj._resultSet._filterInitialized;\n        dv._rematerialize({\n            removeWhereFilters: true\n        });\n        return dv;\n    }\n    /**\n     * Used to clear pipeline and reset dynamic view to initial state.\n     * Existing options should be retained.\n     * @param {boolean} queueSortPhase - (default: false) if true we will async rebuild view (maybe set default to true in future?)\n     */\n    removeFilters({ queueSortPhase = false } = {}) {\n        this._rebuildPending = false;\n        this._resultSet.reset();\n        this._resultData = [];\n        this._resultDirty = true;\n        this._cachedResultSet = null;\n        // keep ordered filter pipeline\n        this._filterPipeline = [];\n        // sorting member variables\n        // we only support one active search, applied using applySort() or applySimpleSort()\n        this._sortFunction = null;\n        this._sortCriteria = null;\n        this._sortCriteriaSimple = null;\n        this._sortByScoring = null;\n        this._sortDirty = false;\n        if (queueSortPhase === true) {\n            this._queueSortPhase();\n        }\n    }\n    /**\n     * Used to apply a sort to the dynamic view\n     * @example\n     * dv.applySort(function(obj1, obj2) {\n       *   if (obj1.name === obj2.name) return 0;\n       *   if (obj1.name > obj2.name) return 1;\n       *   if (obj1.name < obj2.name) return -1;\n       * });\n     * @param {function} comparefun - a javascript compare function used for sorting\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applySort(comparefun) {\n        this._sortFunction = comparefun;\n        this._sortCriteria = null;\n        this._sortCriteriaSimple = null;\n        this._sortByScoring = null;\n        this._queueSortPhase();\n        return this;\n    }\n    /**\n     * Used to specify a property used for view translation.\n     * @param {string} field - the field name\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether we should sort descending.\n     * @param {boolean} [options.disableIndexIntersect=false] - whether we should explicity not use array intersection.\n     * @param {boolean} [options.forceIndexIntersect=false] - force array intersection (if binary index exists).\n     * @param {boolean} [options.useJavascriptSorting=false] - whether results are sorted via basic javascript sort.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     * @example\n     * dv.applySimpleSort(\"name\");\n     */\n    applySimpleSort(field, options = false) {\n        this._sortCriteriaSimple = { field, options };\n        this._sortFunction = null;\n        this._sortCriteria = null;\n        this._sortByScoring = null;\n        this._queueSortPhase();\n        return this;\n    }\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @param {Array} criteria - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {DynamicView} Reference to this DynamicView, sorted, for future chain operations.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * dv.applySortCriteria(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * dv.applySortCriteria(['age', ['name', true]]);\n     * // to sort by age (descending) and then by name (descending)\n     * dv.applySortCriteria([['age', true], ['name', true]]);\n     */\n    applySortCriteria(criteria) {\n        this._sortCriteria = criteria;\n        this._sortCriteriaSimple = null;\n        this._sortFunction = null;\n        this._sortByScoring = null;\n        this._queueSortPhase();\n        return this;\n    }\n    /**\n     * Used to apply a sort by the latest full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     */\n    applySortByScoring(ascending = false) {\n        this._sortFunction = null;\n        this._sortCriteria = null;\n        this._sortCriteriaSimple = null;\n        this._sortByScoring = ascending;\n        this._queueSortPhase();\n        return this;\n    }\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring() {\n        return this._resultSet.getScoring();\n    }\n    /**\n     * Marks the beginning of a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    startTransaction() {\n        this._cachedResultSet = this._resultSet.copy();\n        return this;\n    }\n    /**\n     * Commits a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    commit() {\n        this._cachedResultSet = null;\n        return this;\n    }\n    /**\n     * Rolls back a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    rollback() {\n        this._resultSet = this._cachedResultSet;\n        if (this._persistent) {\n            // for now just rebuild the persistent dynamic view data in this worst case scenario\n            // (a persistent view utilizing transactions which get rolled back), we already know the filter so not too bad.\n            this._resultData = this._resultSet.data();\n            this.emit(\"rebuild\", this);\n        }\n        return this;\n    }\n    /**\n     * Find the index of a filter in the pipeline, by that filter's ID.\n     * @param {(string|number)} uid - The unique ID of the filter.\n     * @returns {number}: index of the referenced filter in the pipeline; -1 if not found.\n     */\n    _indexOfFilterWithId(uid) {\n        if (typeof uid === \"string\" || typeof uid === \"number\") {\n            for (let idx = 0, len = this._filterPipeline.length; idx < len; idx++) {\n                if (uid === this._filterPipeline[idx].uid) {\n                    return idx;\n                }\n            }\n        }\n        return -1;\n    }\n    /**\n     * Add the filter object to the end of view's filter pipeline and apply the filter to the ResultSet.\n     * @param {object} filter - The filter object. Refer to applyFilter() for extra details.\n     */\n    _addFilter(filter) {\n        this._filterPipeline.push(filter);\n        this._resultSet[filter.type](filter.val);\n    }\n    /**\n     * Reapply all the filters in the current pipeline.\n     *\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    reapplyFilters() {\n        this._resultSet.reset();\n        this._cachedResultSet = null;\n        if (this._persistent) {\n            this._resultData = [];\n            this._resultDirty = true;\n        }\n        const filters = this._filterPipeline;\n        this._filterPipeline = [];\n        for (let idx = 0, len = filters.length; idx < len; idx++) {\n            this._addFilter(filters[idx]);\n        }\n        if (this._sortFunction || this._sortCriteria || this._sortCriteriaSimple || this._sortByScoring !== null) {\n            this._queueSortPhase();\n        }\n        else {\n            this._queueRebuildEvent();\n        }\n        return this;\n    }\n    /**\n     * Adds or updates a filter in the DynamicView filter pipeline\n     * @param {object} filter - A filter object to add to the pipeline.\n     *    The object is in the format { 'type': filter_type, 'val', filter_param, 'uid', optional_filter_id }\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFilter(filter) {\n        const idx = this._indexOfFilterWithId(filter.uid);\n        if (idx >= 0) {\n            this._filterPipeline[idx] = filter;\n            return this.reapplyFilters();\n        }\n        this._cachedResultSet = null;\n        if (this._persistent) {\n            this._resultData = [];\n            this._resultDirty = true;\n        }\n        this._addFilter(filter);\n        if (this._sortFunction || this._sortCriteria || this._sortCriteriaSimple || this._sortByScoring !== null) {\n            this._queueSortPhase();\n        }\n        else {\n            this._queueRebuildEvent();\n        }\n        return this;\n    }\n    /**\n     * applyFind() - Adds or updates a mongo-style query option in the DynamicView filter pipeline\n     *\n     * @param {object} query - A mongo-style query object to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFind(query, uid = \"\") {\n        this.applyFilter({\n            type: \"find\",\n            val: query,\n            uid\n        });\n        return this;\n    }\n    /**\n     * Adds or updates a javascript filter function in the DynamicView filter pipeline\n     * @param {function} fun - A javascript filter function to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyWhere(fun, uid) {\n        this.applyFilter({\n            type: \"where\",\n            val: fun,\n            uid\n        });\n        return this;\n    }\n    /**\n     * Remove the specified filter from the DynamicView filter pipeline\n     * @param {(string|number)} uid - The unique ID of the filter to be removed.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    removeFilter(uid) {\n        const idx = this._indexOfFilterWithId(uid);\n        if (idx < 0) {\n            throw new Error(\"Dynamic view does not contain a filter with ID: \" + uid);\n        }\n        this._filterPipeline.splice(idx, 1);\n        this.reapplyFilters();\n        return this;\n    }\n    /**\n     * Returns the number of documents representing the current DynamicView contents.\n     * @returns {number} The number of documents representing the current DynamicView contents.\n     */\n    count() {\n        // in order to be accurate we will pay the minimum cost (and not alter dv state management)\n        // recurring ResultSet data resolutions should know internally its already up to date.\n        // for persistent data this will not update resultdata nor fire rebuild event.\n        if (this._resultDirty) {\n            this._resultData = this._resultSet.data();\n        }\n        return this._resultSet.count();\n    }\n    /**\n     * Resolves and pending filtering and sorting, then returns document array as result.\n     * @param {object} options - optional parameters to pass to ResultSet.data() if non-persistent\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values include 'parse-stringify', 'jquery-extend-deep', 'shallow', 'shallow-assign'\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} An array of documents representing the current DynamicView contents.\n     */\n    data(options = {}) {\n        // using final sort phase as 'catch all' for a few use cases which require full rebuild\n        if (this._sortDirty || this._resultDirty) {\n            this._performSortPhase({\n                suppressRebuildEvent: true\n            });\n        }\n        return (this._persistent) ? (this._resultData) : (this._resultSet.data(options));\n    }\n    /**\n     * When the view is not sorted we may still wish to be notified of rebuild events.\n     * This event will throttle and queue a single rebuild event when batches of updates affect the view.\n     */\n    _queueRebuildEvent() {\n        if (this._rebuildPending) {\n            return;\n        }\n        this._rebuildPending = true;\n        setTimeout(() => {\n            if (this._rebuildPending) {\n                this._rebuildPending = false;\n                this.emit(\"rebuild\", this);\n            }\n        }, this._minRebuildInterval);\n    }\n    /**\n     * If the view is sorted we will throttle sorting to either :\n     * (1) passive - when the user calls data(), or\n     * (2) active - once they stop updating and yield js thread control\n     */\n    _queueSortPhase() {\n        // already queued? exit without queuing again\n        if (this._sortDirty) {\n            return;\n        }\n        this._sortDirty = true;\n        if (this._sortPriority === \"active\") {\n            // active sorting... once they are done and yield js thread, run async performSortPhase()\n            setTimeout(() => {\n                this._performSortPhase();\n            }, this._minRebuildInterval);\n        }\n        else {\n            // must be passive sorting... since not calling performSortPhase (until data call), lets use queueRebuildEvent to\n            // potentially notify user that data has changed.\n            this._queueRebuildEvent();\n        }\n    }\n    /**\n     * Invoked synchronously or asynchronously to perform final sort phase (if needed)\n     */\n    _performSortPhase(options = {}) {\n        // async call to this may have been pre-empted by synchronous call to data before async could fire\n        if (!this._sortDirty && !this._resultDirty) {\n            return;\n        }\n        if (this._sortDirty) {\n            if (this._sortFunction) {\n                this._resultSet.sort(this._sortFunction);\n            }\n            else if (this._sortCriteria) {\n                this._resultSet.compoundsort(this._sortCriteria);\n            }\n            else if (this._sortCriteriaSimple) {\n                this._resultSet.simplesort(this._sortCriteriaSimple.field, this._sortCriteriaSimple.options);\n            }\n            else if (this._sortByScoring !== null) {\n                this._resultSet.sortByScoring(this._sortByScoring);\n            }\n            this._sortDirty = false;\n        }\n        if (this._persistent) {\n            // persistent view, rebuild local resultdata array\n            this._resultData = this._resultSet.data();\n            this._resultDirty = false;\n        }\n        if (!options.suppressRebuildEvent) {\n            this.emit(\"rebuild\", this);\n        }\n    }\n    /**\n     * (Re)evaluating document inclusion.\n     * Called by : collection.insert() and collection.update().\n     * @param {int} objIndex - index of document to (re)run through filter pipeline.\n     * @param {boolean} isNew - true if the document was just added to the collection.\n     * @hidden\n     */\n    _evaluateDocument(objIndex, isNew) {\n        // if no filter applied yet, the result 'set' should remain 'everything'\n        if (!this._resultSet._filterInitialized) {\n            if (this._persistent) {\n                this._resultData = this._resultSet.data();\n            }\n            // need to re-sort to sort new document\n            if (this._sortFunction || this._sortCriteria || this._sortCriteriaSimple) {\n                this._queueSortPhase();\n            }\n            else {\n                this._queueRebuildEvent();\n            }\n            return;\n        }\n        const ofr = this._resultSet._filteredRows;\n        const oldPos = (isNew) ? (-1) : (ofr.indexOf(+objIndex));\n        const oldlen = ofr.length;\n        // creating a 1-element ResultSet to run filter chain ops on to see if that doc passes filters;\n        // mostly efficient algorithm, slight stack overhead price (this function is called on inserts and updates)\n        const evalResultSet = new result_set_ResultSet(this._collection);\n        evalResultSet._filteredRows = [objIndex];\n        evalResultSet._filterInitialized = true;\n        let filter;\n        for (let idx = 0, len = this._filterPipeline.length; idx < len; idx++) {\n            filter = this._filterPipeline[idx];\n            evalResultSet[filter.type](filter.val);\n        }\n        // not a true position, but -1 if not pass our filter(s), 0 if passed filter(s)\n        const newPos = (evalResultSet._filteredRows.length === 0) ? -1 : 0;\n        // wasn't in old, shouldn't be now... do nothing\n        if (oldPos === -1 && newPos === -1)\n            return;\n        // wasn't in ResultSet, should be now... add\n        if (oldPos === -1 && newPos !== -1) {\n            ofr.push(objIndex);\n            if (this._persistent) {\n                this._resultData.push(this._collection._data[objIndex]);\n            }\n            // need to re-sort to sort new document\n            if (this._sortFunction || this._sortCriteria || this._sortCriteriaSimple) {\n                this._queueSortPhase();\n            }\n            else {\n                this._queueRebuildEvent();\n            }\n            return;\n        }\n        // was in ResultSet, shouldn't be now... delete\n        if (oldPos !== -1 && newPos === -1) {\n            if (oldPos < oldlen - 1) {\n                ofr.splice(oldPos, 1);\n                if (this._persistent) {\n                    this._resultData.splice(oldPos, 1);\n                }\n            }\n            else {\n                ofr.length = oldlen - 1;\n                if (this._persistent) {\n                    this._resultData.length = oldlen - 1;\n                }\n            }\n            // in case changes to data altered a sort column\n            if (this._sortFunction || this._sortCriteria || this._sortCriteriaSimple) {\n                this._queueSortPhase();\n            }\n            else {\n                this._queueRebuildEvent();\n            }\n            return;\n        }\n        // was in ResultSet, should still be now... (update persistent only?)\n        if (oldPos !== -1 && newPos !== -1) {\n            if (this._persistent) {\n                // in case document changed, replace persistent view data with the latest collection._data document\n                this._resultData[oldPos] = this._collection._data[objIndex];\n            }\n            // in case changes to data altered a sort column\n            if (this._sortFunction || this._sortCriteria || this._sortCriteriaSimple) {\n                this._queueSortPhase();\n            }\n            else {\n                this._queueRebuildEvent();\n            }\n        }\n    }\n    /**\n     * Internal function called on collection.delete().\n     * @hidden\n     */\n    _removeDocument(objIndex) {\n        // if no filter applied yet, the result 'set' should remain 'everything'\n        if (!this._resultSet._filterInitialized) {\n            if (this._persistent) {\n                this._resultData = this._resultSet.data();\n            }\n            // in case changes to data altered a sort column\n            if (this._sortFunction || this._sortCriteria || this._sortCriteriaSimple) {\n                this._queueSortPhase();\n            }\n            else {\n                this._queueRebuildEvent();\n            }\n            return;\n        }\n        const ofr = this._resultSet._filteredRows;\n        const oldPos = ofr.indexOf(+objIndex);\n        let oldlen = ofr.length;\n        if (oldPos !== -1) {\n            // if not last row in resultdata, swap last to hole and truncate last row\n            if (oldPos < oldlen - 1) {\n                ofr[oldPos] = ofr[oldlen - 1];\n                ofr.length = oldlen - 1;\n                if (this._persistent) {\n                    this._resultData[oldPos] = this._resultData[oldlen - 1];\n                    this._resultData.length = oldlen - 1;\n                }\n            }\n            // last row, so just truncate last row\n            else {\n                ofr.length = oldlen - 1;\n                if (this._persistent) {\n                    this._resultData.length = oldlen - 1;\n                }\n            }\n            // in case changes to data altered a sort column\n            if (this._sortFunction || this._sortCriteria || this._sortCriteriaSimple) {\n                this._queueSortPhase();\n            }\n            else {\n                this._queueRebuildEvent();\n            }\n        }\n        // since we are using filteredRows to store data array positions\n        // if they remove a document (whether in our view or not),\n        // we need to adjust array positions -1 for all document array references after that position\n        oldlen = ofr.length;\n        for (let idx = 0; idx < oldlen; idx++) {\n            if (ofr[idx] > objIndex) {\n                ofr[idx]--;\n            }\n        }\n    }\n    /**\n     * Data transformation via user supplied functions\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns The output of your reduceFunction\n     */\n    mapReduce(mapFunction, reduceFunction) {\n        try {\n            return reduceFunction(this.data().map(mapFunction));\n        }\n        catch (err) {\n            throw err;\n        }\n    }\n}\n\n// EXTERNAL MODULE: ./packages/loki/src/ranged_indexes.ts + 1 modules\nvar ranged_indexes = __webpack_require__(4);\n\n// EXTERNAL MODULE: ./packages/common/plugin.ts\nvar common_plugin = __webpack_require__(1);\n\n// CONCATENATED MODULE: ./packages/loki/src/collection.ts\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return collection_Collection; });\n\n\n\n\n\n\n\n\nfunction average(array) {\n    return (array.reduce((a, b) => a + b, 0)) / array.length;\n}\nfunction standardDeviation(values) {\n    const avg = average(values);\n    const squareDiffs = values.map((value) => {\n        const diff = value - avg;\n        return diff * diff;\n    });\n    const avgSquareDiff = average(squareDiffs);\n    return Math.sqrt(avgSquareDiff);\n}\n/**\n * Returns an array with the value of a nested property of an object.\n * Returns an array of values if the nested property is across child arrays.\n * @param {object} obj - the object\n * @param {string[]} path - the path of the nested property\n * @param {any[]} array - the result array\n * @param {number} pathIdx - the current path idx\n * @returns {boolean} true if nested property is across child arrays, otherwise false\n */\nfunction getNestedPropertyValue(obj, path, array, pathIdx = 0) {\n    if (obj === undefined) {\n        return false;\n    }\n    if (pathIdx + 1 === path.length) {\n        array.push(obj[path[pathIdx]]);\n        return false;\n    }\n    const curr = obj[path[pathIdx]];\n    if (Array.isArray(curr)) {\n        for (let i = 0; i < curr.length; i++) {\n            getNestedPropertyValue(curr[i], path, array, pathIdx + 1);\n        }\n        return true;\n    }\n    else {\n        return getNestedPropertyValue(curr, path, array, pathIdx + 1);\n    }\n}\n/**\n * Collection class that handles documents of same type\n * @extends LokiEventEmitter\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nclass collection_Collection extends event_emitter[\"a\" /* LokiEventEmitter */] {\n    /**\n     * @param {string} name - collection name\n     * @param {(object)} [options={}] - a configuration object\n     * @param {string[]} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {string[]} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {RangedIndexOptions} [options.rangedIndexes] - configuration object for ranged indexes\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are invoked asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes API\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {boolean} [options.serializableIndexes=true] - converts date values on binary indexed property values are serializable\n     * @param {string} [options.cloneMethod=\"deep\"] - the clone method\n     * @param {number} [options.transactional=false] - ?\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale.\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @param {string} [options.unindexedSortComparator=\"js\"] \"js\", \"abstract\", \"abstract-date\", \"loki\" or other registered comparator name\n     * @param {string} [options.defaultLokiOperatorPackage=\"js\"] \"js\", \"loki\", \"comparator\" (or user defined) query ops package\n     * @param {FullTextSearch.FieldOptions} [options.fullTextSearch=] - the full-text search options\n     * @see {@link Loki#addCollection} for normal creation of collections\n     */\n    constructor(name, options = {}) {\n        super();\n        // the data held by the collection\n        this._data = [];\n        // index of id\n        this._idIndex = [];\n        // user defined indexes\n        this._rangedIndexes = {};\n        // loki obj map\n        this._lokimap = {};\n        // default comparator name to use for unindexed sorting\n        this._unindexedSortComparator = \"js\";\n        // default LokiOperatorPackage ('default' uses fastest 'javascript' comparisons)\n        this._defaultLokiOperatorPackage = \"js\";\n        /**\n         * Unique constraints contain duplicate object references, so they are not persisted.\n         * We will keep track of properties which have unique constraints applied here, and regenerate on load.\n         */\n        this._constraints = { unique: {} };\n        /**\n         * Transforms will be used to store frequently used query chains as a series of steps which itself can be stored along\n         * with the database.\n         */\n        this._transforms = {};\n        /**\n         * In autosave scenarios we will use collection level dirty flags to determine whether save is needed.\n         * currently, if any collection is dirty we will autosave the whole database if autosave is configured.\n         * Defaulting to true since this is called from addCollection and adding a collection should trigger save.\n         */\n        this._dirty = true;\n        // private holder for cached data\n        this._cached = null;\n        /**\n         * Name of path of used nested properties.\n         */\n        this._nestedProperties = [];\n        /**\n         * Option to activate a cleaner daemon - clears \"aged\" documents at set intervals.\n         */\n        this._ttl = {\n            age: null,\n            ttlInterval: null,\n            daemon: null\n        };\n        // currentMaxId - change manually at your own peril!\n        this._maxId = 0;\n        this._dynamicViews = [];\n        /**\n         * Changes are tracked by collection and aggregated by the db.\n         */\n        this._changes = [];\n        /**\n         * stages: a map of uniquely identified 'stages', which hold copies of objects to be\n         * manipulated without affecting the data in the original collection\n         */\n        this._stages = {};\n        this._commitLog = [];\n        // Consistency checks.\n        if (options && options.disableMeta === true) {\n            if (options.disableChangesApi === false) {\n                throw new Error(\"disableMeta option cannot be passed as true when disableChangesApi is passed as false\");\n            }\n            if (options.disableDeltaChangesApi === false) {\n                throw new Error(\"disableMeta option cannot be passed as true when disableDeltaChangesApi is passed as false\");\n            }\n            if (typeof options.ttl === \"number\" && options.ttl > 0) {\n                throw new Error(\"disableMeta option cannot be passed as true when ttl is enabled\");\n            }\n        }\n        // the name of the collection\n        this.name = name;\n        /* OPTIONS */\n        this._unindexedSortComparator = options.unindexedSortComparator || \"js\";\n        this._defaultLokiOperatorPackage = options.defaultLokiOperatorPackage || \"js\";\n        // exact match and unique constraints\n        if (options.unique !== undefined) {\n            if (!Array.isArray(options.unique)) {\n                options.unique = [options.unique];\n            }\n            options.unique.forEach((prop) => {\n                this._constraints.unique[prop] = new UniqueIndex(prop);\n            });\n        }\n        // Full text search\n        if (common_plugin[\"a\" /* PLUGINS */][\"FullTextSearch\"] !== undefined) {\n            this._fullTextSearch = options.fullTextSearch !== undefined\n                ? new (common_plugin[\"a\" /* PLUGINS */][\"FullTextSearch\"])(options.fullTextSearch) : null;\n        }\n        else {\n            this._fullTextSearch = null;\n        }\n        // .\n        this._transactional = options.transactional !== undefined ? options.transactional : false;\n        // .\n        this._cloneObjects = options.clone !== undefined ? options.clone : false;\n        // .\n        this._asyncListeners = options.asyncListeners !== undefined ? options.asyncListeners : false;\n        // .\n        this._disableMeta = options.disableMeta !== undefined ? options.disableMeta : false;\n        // .\n        this._disableChangesApi = options.disableChangesApi !== undefined ? options.disableChangesApi : true;\n        // .\n        this._disableDeltaChangesApi = options.disableDeltaChangesApi !== undefined ? options.disableDeltaChangesApi : true;\n        // .\n        this._cloneMethod = options.cloneMethod !== undefined ? options.cloneMethod : \"deep\";\n        if (this._disableChangesApi) {\n            this._disableDeltaChangesApi = true;\n        }\n        // .\n        this._serializableIndexes = options.serializableIndexes !== undefined ? options.serializableIndexes : true;\n        // .\n        if (options.nestedProperties != undefined) {\n            for (let i = 0; i < options.nestedProperties.length; i++) {\n                const nestedProperty = options.nestedProperties[i];\n                if (typeof nestedProperty === \"string\") {\n                    this._nestedProperties.push({ name: nestedProperty, path: nestedProperty.split(\".\") });\n                }\n                else {\n                    this._nestedProperties.push(nestedProperty);\n                }\n            }\n        }\n        this.setTTL(options.ttl || -1, options.ttlInterval);\n        // events\n        this._events = {\n            \"insert\": [],\n            \"update\": [],\n            \"pre-insert\": [],\n            \"pre-update\": [],\n            \"close\": [],\n            \"flushbuffer\": [],\n            \"error\": [],\n            \"delete\": [],\n            \"warning\": []\n        };\n        // initialize the id index\n        this._ensureId();\n        let rangedIndexes = options.rangedIndexes || {};\n        for (let ri in rangedIndexes) {\n            // Todo: any way to type annotate this as typesafe generic?\n            this.ensureRangedIndex(ri, rangedIndexes[ri].indexTypeName, rangedIndexes[ri].comparatorName);\n        }\n        this.setChangesApi(this._disableChangesApi, this._disableDeltaChangesApi);\n        // for de-serialization purposes\n        this.flushChanges();\n    }\n    toJSON() {\n        return {\n            name: this.name,\n            unindexedSortComparator: this._unindexedSortComparator,\n            defaultLokiOperatorPackage: this._defaultLokiOperatorPackage,\n            _dynamicViews: this._dynamicViews,\n            uniqueNames: Object.keys(this._constraints.unique),\n            transforms: this._transforms,\n            rangedIndexes: this._rangedIndexes,\n            _data: this._data,\n            idIndex: this._idIndex,\n            maxId: this._maxId,\n            _dirty: this._dirty,\n            _nestedProperties: this._nestedProperties,\n            transactional: this._transactional,\n            asyncListeners: this._asyncListeners,\n            disableMeta: this._disableMeta,\n            disableChangesApi: this._disableChangesApi,\n            disableDeltaChangesApi: this._disableDeltaChangesApi,\n            cloneObjects: this._cloneObjects,\n            cloneMethod: this._cloneMethod,\n            changes: this._changes,\n            _fullTextSearch: this._fullTextSearch\n        };\n    }\n    static fromJSONObject(obj, options) {\n        // instantiate collection with options needed by constructor\n        let coll = new collection_Collection(obj.name, {\n            disableChangesApi: obj.disableChangesApi,\n            disableDeltaChangesApi: obj.disableDeltaChangesApi,\n            unindexedSortComparator: obj.unindexedSortComparator,\n            defaultLokiOperatorPackage: obj.defaultLokiOperatorPackage\n        });\n        coll._transactional = obj.transactional;\n        coll._asyncListeners = obj.asyncListeners;\n        coll._disableMeta = obj.disableMeta;\n        coll._disableChangesApi = obj.disableChangesApi;\n        coll._cloneObjects = obj.cloneObjects;\n        coll._cloneMethod = obj.cloneMethod || \"deep\";\n        coll._changes = obj.changes;\n        coll._nestedProperties = obj._nestedProperties;\n        coll._rangedIndexes = obj.rangedIndexes || {};\n        coll._dirty = (options && options.retainDirtyFlags === true) ? obj._dirty : false;\n        function makeLoader(coll) {\n            const collOptions = options[coll.name];\n            if (collOptions.proto) {\n                const inflater = collOptions.inflate || ((src, dest) => {\n                    for (let prop in src) {\n                        dest[prop] = src[prop];\n                    }\n                });\n                return (data) => {\n                    const collObj = new (collOptions.proto)();\n                    inflater(data, collObj);\n                    return collObj;\n                };\n            }\n            return collOptions.inflate;\n        }\n        // load each element individually\n        if (options && options[obj.name] !== undefined) {\n            let loader = makeLoader(obj);\n            for (let j = 0; j < obj._data.length; j++) {\n                coll._data[j] = coll._defineNestedProperties(loader(obj._data[j]));\n                // regenerate lokimap\n                coll._lokimap[coll._data[j].$loki] = coll._data[j];\n            }\n        }\n        else {\n            for (let j = 0; j < obj._data.length; j++) {\n                coll._data[j] = coll._defineNestedProperties(obj._data[j]);\n                // regenerate lokimap\n                coll._lokimap[coll._data[j].$loki] = coll._data[j];\n            }\n        }\n        coll._maxId = (obj.maxId === undefined) ? 0 : obj.maxId;\n        coll._idIndex = obj.idIndex;\n        if (obj.transforms !== undefined) {\n            coll._transforms = obj.transforms;\n        }\n        // inflate rangedindexes\n        for (let ri in obj.rangedIndexes) {\n            // shortcut reference to serialized meta\n            let sri = obj.rangedIndexes[ri];\n            // lookup index factory function in map based on index type name\n            let rif = ranged_indexes[\"a\" /* RangedIndexFactoryMap */][sri.indexTypeName];\n            // lookup comparator function in map based on comparator name\n            let ricmp = comparators[\"a\" /* ComparatorMap */][sri.comparatorName];\n            // using index type (from meta), index factory and comparator... create instance of ranged index\n            let rii = rif(ri, ricmp);\n            // now ask new index instance to inflate from plain object\n            rii.restore(sri.index);\n            // attach class instance to our collection's ranged index's (index) instance property\n            coll._rangedIndexes[ri].index = rii;\n        }\n        coll._ensureId();\n        // regenerate unique indexes\n        if (obj.uniqueNames !== undefined) {\n            for (let j = 0; j < obj.uniqueNames.length; j++) {\n                coll.ensureUniqueIndex(obj.uniqueNames[j]);\n            }\n        }\n        // in case they are loading a database created before we added dynamic views, handle undefined\n        if (obj._dynamicViews !== undefined) {\n            // reinflate DynamicViews and attached ResultSets\n            for (let idx = 0; idx < obj._dynamicViews.length; idx++) {\n                coll._dynamicViews.push(dynamic_view_DynamicView.fromJSONObject(coll, obj._dynamicViews[idx]));\n            }\n        }\n        if (obj._fullTextSearch) {\n            coll._fullTextSearch = common_plugin[\"a\" /* PLUGINS */][\"FullTextSearch\"].fromJSONObject(obj._fullTextSearch, options.fullTextSearch);\n        }\n        return coll;\n    }\n    /**\n     * Adds a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {array} transform - an array of transformation 'step' objects to save into the collection\n     */\n    addTransform(name, transform) {\n        if (this._transforms[name] !== undefined) {\n            throw new Error(\"a transform by that name already exists\");\n        }\n        this._transforms[name] = transform;\n    }\n    /**\n     * Retrieves a named transform from the collection.\n     * @param {string} name - name of the transform to lookup.\n     */\n    getTransform(name) {\n        return this._transforms[name];\n    }\n    /**\n     * Updates a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {object} transform - a transformation object to save into collection\n     */\n    setTransform(name, transform) {\n        this._transforms[name] = transform;\n    }\n    /**\n     * Removes a named collection transform from the collection\n     * @param {string} name - name of collection transform to remove\n     */\n    removeTransform(name) {\n        delete this._transforms[name];\n    }\n    /*----------------------------+\n     | TTL                        |\n     +----------------------------*/\n    setTTL(age, interval) {\n        if (age < 0) {\n            clearInterval(this._ttl.daemon);\n        }\n        else {\n            this._ttl.age = age;\n            this._ttl.ttlInterval = interval;\n            this._ttl.daemon = setInterval(() => {\n                const now = Date.now();\n                const toRemove = this.chain().where((member) => {\n                    const timestamp = member.meta.updated || member.meta.created;\n                    const diff = now - timestamp;\n                    return this._ttl.age < diff;\n                });\n                toRemove.remove();\n            }, interval);\n        }\n    }\n    /*----------------------------+\n     | INDEXING                   |\n     +----------------------------*/\n    /**\n     * Create a row filter that covers all documents in the collection.\n     */\n    _prepareFullDocIndex() {\n        const indexes = new Array(this._data.length);\n        for (let i = 0; i < indexes.length; i++) {\n            indexes[i] = i;\n        }\n        return indexes;\n    }\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field\n     * @param indexTypeName\n     * @param comparatorName\n     */\n    ensureIndex(field, indexTypeName, comparatorName) {\n        this.ensureRangedIndex(field, indexTypeName, comparatorName);\n    }\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field Property to create an index on (need to look into contraining on keyof T)\n     * @param indexTypeName Name of IndexType factory within (global?) hashmap to create IRangedIndex from\n     * @param comparatorName Name of Comparator within (global?) hashmap\n     */\n    ensureRangedIndex(field, indexTypeName, comparatorName) {\n        indexTypeName = indexTypeName || \"avl\";\n        comparatorName = comparatorName || \"loki\";\n        if (!ranged_indexes[\"a\" /* RangedIndexFactoryMap */][indexTypeName]) {\n            throw new Error(\"ensureRangedIndex: Unknown range index type\");\n        }\n        if (!comparators[\"a\" /* ComparatorMap */][comparatorName]) {\n            throw new Error(\"ensureRangedIndex: Unknown comparator\");\n        }\n        let rif = ranged_indexes[\"a\" /* RangedIndexFactoryMap */][indexTypeName];\n        let comparator = comparators[\"a\" /* ComparatorMap */][comparatorName];\n        this._rangedIndexes[field] = {\n            index: rif(field, comparator),\n            indexTypeName: indexTypeName,\n            comparatorName: comparatorName\n        };\n        let rii = this._rangedIndexes[field].index;\n        for (let i = 0; i < this._data.length; i++) {\n            rii.insert(this._data[i].$loki, this._data[i][field]);\n        }\n    }\n    ensureUniqueIndex(field) {\n        let index = new UniqueIndex(field);\n        // if index already existed, (re)loading it will likely cause collisions, rebuild always\n        this._constraints.unique[field] = index;\n        for (let i = 0; i < this._data.length; i++) {\n            index.set(this._data[i].$loki, this._data[i][field]);\n        }\n        return index;\n    }\n    /**\n     * Quickly determine number of documents in collection (or query)\n     * @param {object} query - (optional) query object to count results of\n     * @returns {number} number of documents in the collection\n     */\n    count(query) {\n        if (!query) {\n            return this._data.length;\n        }\n        return this.chain().find(query)._filteredRows.length;\n    }\n    /**\n     * Rebuild idIndex\n     */\n    _ensureId() {\n        this._idIndex = [];\n        for (let i = 0; i < this._data.length; i++) {\n            this._idIndex.push(this._data[i].$loki);\n        }\n    }\n    /**\n     * Add a dynamic view to the collection\n     * @param {string} name - name of dynamic view to add\n     * @param {object} options - (optional) options to configure dynamic view with\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=SortPriority.PASSIVE] - the sort priority\n     * @param {number} options.minRebuildInterval - minimum rebuild interval (need clarification to docs here)\n     * @returns {DynamicView} reference to the dynamic view added\n     **/\n    addDynamicView(name, options) {\n        const dv = new dynamic_view_DynamicView(this, name, options);\n        this._dynamicViews.push(dv);\n        return dv;\n    }\n    /**\n     * Remove a dynamic view from the collection\n     * @param {string} name - name of dynamic view to remove\n     **/\n    removeDynamicView(name) {\n        for (let idx = 0; idx < this._dynamicViews.length; idx++) {\n            if (this._dynamicViews[idx].name === name) {\n                this._dynamicViews.splice(idx, 1);\n            }\n        }\n    }\n    /**\n     * Look up dynamic view reference from within the collection\n     * @param {string} name - name of dynamic view to retrieve reference of\n     * @returns {DynamicView} A reference to the dynamic view with that name\n     **/\n    getDynamicView(name) {\n        for (let idx = 0; idx < this._dynamicViews.length; idx++) {\n            if (this._dynamicViews[idx].name === name) {\n                return this._dynamicViews[idx];\n            }\n        }\n        return null;\n    }\n    /**\n     * Applies a 'mongo-like' find query object and passes all results to an update function.\n     * @param {object} filterObject - the 'mongo-like' query object\n     * @param {function} updateFunction - the update function\n     */\n    findAndUpdate(filterObject, updateFunction) {\n        this.chain().find(filterObject).update(updateFunction);\n    }\n    /**\n     * Applies a 'mongo-like' find query object removes all documents which match that filter.\n     * @param {object} filterObject - 'mongo-like' query object\n     */\n    findAndRemove(filterObject) {\n        this.chain().find(filterObject).remove();\n    }\n    insert(doc) {\n        if (!Array.isArray(doc)) {\n            return this.insertOne(doc);\n        }\n        // holder to the clone of the object inserted if collections is set to clone objects\n        let obj;\n        let results = [];\n        this.emit(\"pre-insert\", doc);\n        for (let i = 0; i < doc.length; i++) {\n            obj = this.insertOne(doc[i], true);\n            if (!obj) {\n                return undefined;\n            }\n            results.push(obj);\n        }\n        // at the 'batch' level, if clone option is true then emitted docs are clones\n        this.emit(\"insert\", results);\n        // if clone option is set, clone return values\n        results = this._cloneObjects ? clone(results, this._cloneMethod) : results;\n        return results.length === 1 ? results[0] : results;\n    }\n    /**\n     * Adds a single object, ensures it has meta properties, clone it if necessary, etc.\n     * @param {object} doc - the document to be inserted\n     * @param {boolean} bulkInsert - quiet pre-insert and insert event emits\n     * @returns {object} document or 'undefined' if there was a problem inserting it\n     */\n    insertOne(doc, bulkInsert = false) {\n        let err = null;\n        let returnObj;\n        if (typeof doc !== \"object\") {\n            err = new TypeError(\"Document needs to be an object\");\n        }\n        else if (doc === null) {\n            err = new TypeError(\"Object cannot be null\");\n        }\n        if (err !== null) {\n            this.emit(\"error\", err);\n            throw err;\n        }\n        // if configured to clone, do so now... otherwise just use same obj reference\n        const obj = this._defineNestedProperties(this._cloneObjects ? clone(doc, this._cloneMethod) : doc);\n        if (!this._disableMeta && obj.meta === undefined) {\n            obj.meta = {\n                version: 0,\n                revision: 0,\n                created: 0\n            };\n        }\n        // both 'pre-insert' and 'insert' events are passed internal data reference even when cloning\n        // insert needs internal reference because that is where loki itself listens to add meta\n        if (!bulkInsert) {\n            this.emit(\"pre-insert\", obj);\n        }\n        if (!this._add(obj)) {\n            return undefined;\n        }\n        // update meta and store changes if ChangesAPI is enabled\n        // (moved from \"insert\" event listener to allow internal reference to be used)\n        if (this._disableChangesApi) {\n            this._insertMeta(obj);\n        }\n        else {\n            this._insertMetaWithChange(obj);\n        }\n        // if cloning is enabled, emit insert event with clone of new object\n        returnObj = this._cloneObjects ? clone(obj, this._cloneMethod) : obj;\n        if (!bulkInsert) {\n            this.emit(\"insert\", returnObj);\n        }\n        return returnObj;\n    }\n    /**\n     * Refers nested properties of an object to the root of it.\n     * @param {T} data - the object\n     * @returns {T & TNested} the object with nested properties\n     * @hidden\n     */\n    _defineNestedProperties(data) {\n        for (let i = 0; i < this._nestedProperties.length; i++) {\n            const name = this._nestedProperties[i].name;\n            const path = this._nestedProperties[i].path;\n            Object.defineProperty(data, name, {\n                get() {\n                    // Get the value of the nested property.\n                    const array = [];\n                    if (getNestedPropertyValue(this, path, array)) {\n                        return array;\n                    }\n                    else {\n                        return array[0];\n                    }\n                },\n                set(val) {\n                    // Set the value of the nested property.\n                    path.slice(0, path.length - 1).reduce((obj, part) => (obj && obj[part]) ? obj[part] : null, this)[path[path.length - 1]] = val;\n                },\n                enumerable: false,\n                configurable: true\n            });\n        }\n        return data;\n    }\n    /**\n     * Empties the collection.\n     * @param {boolean} [removeIndices=false] - remove indices\n     */\n    clear({ removeIndices: removeIndices = false } = {}) {\n        this._data = [];\n        this._idIndex = [];\n        this._cached = null;\n        this._maxId = 0;\n        this._dynamicViews = [];\n        this._dirty = true;\n        // if removing indices entirely\n        if (removeIndices === true) {\n            this._rangedIndexes = {};\n            this._constraints = {\n                unique: {}\n            };\n        }\n        // clear indices but leave definitions in place\n        else {\n            // re-instance ranged indexes\n            for (let ri in this._rangedIndexes) {\n                this.ensureRangedIndex(ri, this._rangedIndexes[ri].indexTypeName, this._rangedIndexes[ri].comparatorName);\n            }\n            // clear entire unique indices definition\n            const uniqueNames = Object.keys(this._constraints.unique);\n            for (let i = 0; i < uniqueNames.length; i++) {\n                this._constraints.unique[uniqueNames[i]].clear();\n            }\n        }\n        if (this._fullTextSearch !== null) {\n            this._fullTextSearch.clear();\n        }\n    }\n    /**\n     * Updates an object and notifies collection that the document has changed.\n     * @param {object} doc - document to update within the collection\n     */\n    update(doc) {\n        if (Array.isArray(doc)) {\n            for (let i = 0; i < doc.length; i++) {\n                this.update(doc[i]);\n            }\n            return;\n        }\n        // Verify object is a properly formed document.\n        if (doc.$loki === undefined) {\n            throw new Error(\"Trying to update unsynced document. Please save the document first by using insert() or addMany()\");\n        }\n        try {\n            this.startTransaction();\n            const arr = this.get(doc.$loki, true);\n            if (!arr) {\n                throw new Error(\"Trying to update a document not in collection.\");\n            }\n            // ref to existing obj\n            let oldInternal = arr[0]; // -internal- obj ref\n            let position = arr[1]; // position in data array\n            // ref to new internal obj\n            // if configured to clone, do so now... otherwise just use same obj reference\n            let newInternal = this._defineNestedProperties(this._cloneObjects || !this._disableDeltaChangesApi ? clone(doc, this._cloneMethod) : doc);\n            this.emit(\"pre-update\", doc);\n            Object.keys(this._constraints.unique).forEach((key) => {\n                this._constraints.unique[key].update(newInternal.$loki, newInternal[key]);\n            });\n            // operate the update\n            this._data[position] = newInternal;\n            this._lokimap[doc.$loki] = newInternal;\n            // now that we can efficiently determine the data[] position of newly added document,\n            // submit it for all registered DynamicViews to evaluate for inclusion/exclusion\n            for (let idx = 0; idx < this._dynamicViews.length; idx++) {\n                this._dynamicViews[idx]._evaluateDocument(position, false);\n            }\n            // Notify all ranged indexes of (possible) value update\n            for (let ri in this._rangedIndexes) {\n                this._rangedIndexes[ri].index.update(doc.$loki, doc[ri]);\n            }\n            this._idIndex[position] = newInternal.$loki;\n            // FullTextSearch.\n            if (this._fullTextSearch !== null) {\n                this._fullTextSearch.updateDocument(doc, position);\n            }\n            this.commit();\n            this._dirty = true; // for autosave scenarios\n            // update meta and store changes if ChangesAPI is enabled\n            if (this._disableChangesApi) {\n                this._updateMeta(newInternal);\n            }\n            else {\n                this._updateMetaWithChange(newInternal, oldInternal);\n            }\n            let returnObj = newInternal;\n            // if cloning is enabled, emit 'update' event and return with clone of new object\n            if (this._cloneObjects) {\n                returnObj = clone(newInternal, this._cloneMethod);\n            }\n            this.emit(\"update\", returnObj, oldInternal);\n        }\n        catch (err) {\n            this.rollback();\n            this.emit(\"error\", err);\n            throw (err); // re-throw error so user does not think it succeeded\n        }\n    }\n    /**\n     * Add object to collection\n     */\n    _add(obj) {\n        // if parameter isn't object exit with throw\n        if (\"object\" !== typeof obj) {\n            throw new TypeError(\"Object being added needs to be an object\");\n        }\n        // if object you are adding already has id column it is either already in the collection\n        // or the object is carrying its own 'id' property.  If it also has a meta property,\n        // then this is already in collection so throw error, otherwise rename to originalId and continue adding.\n        if (obj[\"$loki\"] !== undefined) {\n            throw new Error(\"Document is already in collection, please use update()\");\n        }\n        /*\n         * try adding object to collection\n         */\n        try {\n            this.startTransaction();\n            this._maxId++;\n            if (isNaN(this._maxId)) {\n                this._maxId = (this._data[this._data.length - 1].$loki + 1);\n            }\n            const newDoc = obj;\n            newDoc.$loki = this._maxId;\n            if (!this._disableMeta) {\n                newDoc.meta.version = 0;\n            }\n            const constrUnique = this._constraints.unique;\n            for (const key in constrUnique) {\n                if (constrUnique[key] !== undefined) {\n                    constrUnique[key].set(newDoc.$loki, newDoc[key]);\n                }\n            }\n            // add new obj id to idIndex\n            this._idIndex.push(newDoc.$loki);\n            // update lokimap\n            this._lokimap[newDoc.$loki] = newDoc;\n            // add the object\n            this._data.push(newDoc);\n            const addedPos = this._data.length - 1;\n            // now that we can efficiently determine the data[] position of newly added document,\n            // submit it for all registered DynamicViews to evaluate for inclusion/exclusion\n            const dvlen = this._dynamicViews.length;\n            for (let i = 0; i < dvlen; i++) {\n                this._dynamicViews[i]._evaluateDocument(addedPos, true);\n            }\n            // add id/val kvp to ranged index\n            for (let ri in this._rangedIndexes) {\n                // ensure Dates are converted to unix epoch time if serializableIndexes is true\n                if (this._serializableIndexes && newDoc[ri] instanceof Date) {\n                    newDoc[ri] = newDoc[ri].getTime();\n                }\n                this._rangedIndexes[ri].index.insert(obj[\"$loki\"], obj[ri]);\n            }\n            // FullTextSearch.\n            if (this._fullTextSearch !== null) {\n                this._fullTextSearch.addDocument(newDoc, addedPos);\n            }\n            this.commit();\n            this._dirty = true; // for autosave scenarios\n            return (this._cloneObjects) ? (clone(newDoc, this._cloneMethod)) : (newDoc);\n        }\n        catch (err) {\n            this.rollback();\n            this.emit(\"error\", err);\n            throw (err); // re-throw error so user does not think it succeeded\n        }\n    }\n    /**\n     * Applies a filter function and passes all results to an update function.\n     * @param {function} filterFunction - the filter function\n     * @param {function} updateFunction - the update function\n     */\n    updateWhere(filterFunction, updateFunction) {\n        const results = this.where(filterFunction);\n        try {\n            for (let i = 0; i < results.length; i++) {\n                this.update(updateFunction(results[i]));\n            }\n        }\n        catch (err) {\n            this.rollback();\n            throw err;\n        }\n    }\n    /**\n     * Remove all documents matching supplied filter function.\n     * @param {function} filterFunction - the filter function\n     */\n    removeWhere(filterFunction) {\n        this.remove(this._data.filter(filterFunction));\n    }\n    removeDataOnly() {\n        this.remove(this._data.slice());\n    }\n    /**\n     * Remove a document from the collection\n     * @param {number|object} doc - document to remove from collection\n     */\n    remove(doc) {\n        if (typeof doc === \"number\") {\n            doc = this.get(doc);\n        }\n        if (Array.isArray(doc)) {\n            let k = 0;\n            const len = doc.length;\n            for (k; k < len; k++) {\n                this.remove(doc[k]);\n            }\n            return;\n        }\n        if (doc.$loki === undefined) {\n            throw new Error(\"Object is not a document stored in the collection\");\n        }\n        try {\n            this.startTransaction();\n            const arr = this.get(doc.$loki, true);\n            const position = arr[1];\n            // already converted but let's narrow to make typescript happy\n            let aDoc = (typeof doc === \"number\") ? this.get(doc) : doc;\n            Object.keys(this._constraints.unique).forEach((key) => {\n                if (key in aDoc) {\n                    this._constraints.unique[key].remove(aDoc.$loki);\n                }\n            });\n            // now that we can efficiently determine the data[] position of newly added document,\n            // submit it for all registered DynamicViews to remove\n            for (let idx = 0; idx < this._dynamicViews.length; idx++) {\n                this._dynamicViews[idx]._removeDocument(position);\n            }\n            this._data.splice(position, 1);\n            // remove id from idIndex\n            this._idIndex.splice(position, 1);\n            // remove from lokimap\n            delete this._lokimap[doc.$loki];\n            // remove id/val kvp from binary tree index\n            for (let ri in this._rangedIndexes) {\n                this._rangedIndexes[ri].index.remove(doc.$loki);\n            }\n            // FullTextSearch.\n            if (this._fullTextSearch !== null) {\n                this._fullTextSearch.removeDocument(doc, position);\n            }\n            this.commit();\n            this._dirty = true; // for autosave scenarios\n            if (!this._disableChangesApi) {\n                this._createChange(this.name, \"R\", arr[0]);\n            }\n            this.emit(\"delete\", arr[0]);\n            delete doc.$loki;\n            delete doc.meta;\n        }\n        catch (err) {\n            this.rollback();\n            this.emit(\"error\", err);\n            throw err;\n        }\n    }\n    /*------------+\n     | Change API |\n     +------------*/\n    /**\n     * Returns all changes.\n     * @returns {Collection.Change[]}\n     */\n    getChanges() {\n        return this._changes;\n    }\n    /**\n     * Enables/disables changes api.\n     * @param {boolean} disableChangesApi\n     * @param {boolean} disableDeltaChangesApi\n     */\n    setChangesApi(disableChangesApi, disableDeltaChangesApi = true) {\n        this._disableChangesApi = disableChangesApi;\n        this._disableDeltaChangesApi = disableChangesApi ? true : disableDeltaChangesApi;\n    }\n    /**\n     * Clears all the changes.\n     */\n    flushChanges() {\n        this._changes = [];\n    }\n    _getObjectDelta(oldObject, newObject) {\n        const propertyNames = newObject !== null && typeof newObject === \"object\" ? Object.keys(newObject) : null;\n        if (propertyNames && propertyNames.length && [\"string\", \"boolean\", \"number\"].indexOf(typeof (newObject)) < 0) {\n            const delta = {};\n            for (let i = 0; i < propertyNames.length; i++) {\n                const propertyName = propertyNames[i];\n                if (newObject.hasOwnProperty(propertyName)) {\n                    if (!oldObject.hasOwnProperty(propertyName) || this._constraints.unique[propertyName] !== undefined\n                        || propertyName === \"$loki\" || propertyName === \"meta\") {\n                        delta[propertyName] = newObject[propertyName];\n                    }\n                    else {\n                        const propertyDelta = this._getObjectDelta(oldObject[propertyName], newObject[propertyName]);\n                        if (propertyDelta !== undefined && propertyDelta !== {}) {\n                            delta[propertyName] = propertyDelta;\n                        }\n                    }\n                }\n            }\n            return Object.keys(delta).length === 0 ? undefined : delta;\n        }\n        else {\n            return oldObject === newObject ? undefined : newObject;\n        }\n    }\n    /**\n     * Compare changed object (which is a forced clone) with existing object and return the delta\n     */\n    _getChangeDelta(obj, old) {\n        if (old) {\n            return this._getObjectDelta(old, obj);\n        }\n        else {\n            return JSON.parse(JSON.stringify(obj));\n        }\n    }\n    /**\n     * Creates a clone of the current status of an object and associates operation and collection name,\n     * so the parent db can aggregate and generate a changes object for the entire db\n     */\n    _createChange(name, op, obj, old) {\n        this._changes.push({\n            name,\n            operation: op,\n            obj: op === \"U\" && !this._disableDeltaChangesApi\n                ? this._getChangeDelta(obj, old)\n                : JSON.parse(JSON.stringify(obj))\n        });\n    }\n    _createInsertChange(obj) {\n        this._createChange(this.name, \"I\", obj);\n    }\n    _createUpdateChange(obj, old) {\n        this._createChange(this.name, \"U\", obj, old);\n    }\n    _insertMetaWithChange(obj) {\n        this._insertMeta(obj);\n        this._createInsertChange(obj);\n    }\n    _updateMetaWithChange(obj, old) {\n        this._updateMeta(obj);\n        this._createUpdateChange(obj, old);\n    }\n    _insertMeta(obj) {\n        if (this._disableMeta) {\n            return;\n        }\n        if (!obj.meta) {\n            obj.meta = {\n                version: 0,\n                revision: 0,\n                created: 0\n            };\n        }\n        obj.meta.created = (new Date()).getTime();\n        obj.meta.revision = 0;\n    }\n    _updateMeta(obj) {\n        if (this._disableMeta) {\n            return;\n        }\n        obj.meta.updated = (new Date()).getTime();\n        obj.meta.revision += 1;\n    }\n    get(id, returnPosition = false) {\n        if (!returnPosition) {\n            let doc = this._lokimap[id];\n            if (doc === undefined)\n                return null;\n            return doc;\n        }\n        const data = this._idIndex;\n        let max = data.length - 1;\n        let min = 0;\n        let mid = (min + max) >> 1;\n        id = typeof id === \"number\" ? id : parseInt(id, 10);\n        if (isNaN(id)) {\n            throw new TypeError(\"Passed id is not an integer\");\n        }\n        while (data[min] < data[max]) {\n            mid = (min + max) >> 1;\n            if (data[mid] < id) {\n                min = mid + 1;\n            }\n            else {\n                max = mid;\n            }\n        }\n        if (max === min && data[min] === id) {\n            if (returnPosition) {\n                return [this._data[min], min];\n            }\n            return this._data[min];\n        }\n        return null;\n    }\n    /**\n     * Retrieve doc by Unique index\n     * @param {string} field - name of uniquely indexed property to use when doing lookup\n     * @param {any} value - unique value to search for\n     * @returns {object} document matching the value passed\n     */\n    by(field, value) {\n        // for least amount of overhead, we will directly\n        // access index rather than use find codepath\n        let lokiId = this._constraints.unique[field].get(value);\n        if (!this._cloneObjects) {\n            return this._lokimap[lokiId];\n        }\n        else {\n            return clone(this._lokimap[lokiId], this._cloneMethod);\n        }\n    }\n    /**\n     * Find one object by index property, by property equal to value\n     * @param {object} query - query object used to perform search with\n     * @returns {(object|null)} First matching document, or null if none\n     */\n    findOne(query) {\n        query = query || {};\n        // Instantiate ResultSet and exec find op passing firstOnly = true param\n        const result = this.chain().find(query, true).data();\n        if (Array.isArray(result) && result.length === 0) {\n            return null;\n        }\n        else {\n            if (!this._cloneObjects) {\n                return result[0];\n            }\n            else {\n                return clone(result[0], this._cloneMethod);\n            }\n        }\n    }\n    /**\n     * Chain method, used for beginning a series of chained find() and/or view() operations\n     * on a collection.\n     *\n     * @param {array} transform - Ordered array of transform step objects similar to chain\n     * @param {object} parameters - Object containing properties representing parameters to substitute\n     * @returns {ResultSet} (this) ResultSet, or data array if any map or join functions where called\n     */\n    chain(transform, parameters) {\n        const rs = new result_set_ResultSet(this);\n        if (transform === undefined) {\n            return rs;\n        }\n        return rs.transform(transform, parameters);\n    }\n    /**\n     * Find method, api is similar to mongodb.\n     * for more complex queries use [chain()]{@link Collection#chain} or [where()]{@link Collection#where}.\n     * @example {@tutorial Query Examples}\n     * @param {object} query - 'mongo-like' query object\n     * @returns {array} Array of matching documents\n     */\n    find(query) {\n        return this.chain().find(query).data();\n    }\n    /**\n     * Find object by unindexed field by property equal to value,\n     * simply iterates and returns the first element matching the query\n     */\n    findOneUnindexed(prop, value) {\n        let i = this._data.length;\n        let doc;\n        while (i--) {\n            if (this._data[i][prop] === value) {\n                doc = this._data[i];\n                return doc;\n            }\n        }\n        return null;\n    }\n    /**\n     * Transaction methods\n     */\n    /**\n     * start the transation\n     */\n    startTransaction() {\n        if (this._transactional) {\n            // backup any ranged indexes\n            let rib = {};\n            for (let ri in this._rangedIndexes) {\n                rib[ri].indexTypeName = this._rangedIndexes[ri].indexTypeName;\n                rib[ri].comparatorName = this._rangedIndexes[ri].comparatorName;\n                rib[ri].index = this._rangedIndexes[ri].index.backup();\n            }\n            this._cached = {\n                index: this._idIndex,\n                data: clone(this._data, this._cloneMethod),\n                rangedIndexes: rib,\n            };\n            // propagate startTransaction to dynamic views\n            for (let idx = 0; idx < this._dynamicViews.length; idx++) {\n                this._dynamicViews[idx].startTransaction();\n            }\n        }\n    }\n    /**\n     * Commit the transaction.\n     */\n    commit() {\n        if (this._transactional) {\n            this._cached = null;\n            // propagate commit to dynamic views\n            for (let idx = 0; idx < this._dynamicViews.length; idx++) {\n                this._dynamicViews[idx].commit();\n            }\n        }\n    }\n    /**\n     * Rollback the transaction.\n     */\n    rollback() {\n        if (this._transactional) {\n            if (this._cached !== null) {\n                this._idIndex = this._cached.index;\n                this._data = this._cached.data;\n                for (let i = 0; i < this._data.length; i++) {\n                    this._data[i] = this._defineNestedProperties(this._data[i]);\n                }\n                // restore ranged indexes\n                for (let ri in this._cached.rangedIndexes) {\n                    // shortcut reference to serialized meta\n                    let sri = this._cached.rangedIndexes[ri];\n                    // lookup index factory function in map based on index type name\n                    let rif = ranged_indexes[\"a\" /* RangedIndexFactoryMap */][sri.indexTypeName];\n                    // lookup comparator function in map based on comparator name\n                    let ricmp = comparators[\"a\" /* ComparatorMap */][sri.comparatorName];\n                    // using index type (from meta), index factory and comparator... create instance of ranged index\n                    let rii = rif(ri, ricmp);\n                    // now ask new index instance to inflate from plain object\n                    rii.restore(sri.index);\n                    // attach class instance to our collection's ranged index's (index) instance property\n                    this._rangedIndexes[ri].index = rii;\n                }\n                // propagate rollback to dynamic views\n                for (let idx = 0; idx < this._dynamicViews.length; idx++) {\n                    this._dynamicViews[idx].rollback();\n                }\n            }\n        }\n    }\n    /**\n     * Query the collection by supplying a javascript filter function.\n     * @example\n     * let results = coll.where(function(obj) {\n       *   return obj.legs === 8;\n       * });\n     * @param {function} fun - filter function to run against all collection docs\n     * @returns {array} all documents which pass your filter function\n     */\n    where(fun) {\n        return this.chain().where(fun).data();\n    }\n    /**\n     * Map Reduce operation\n     * @param {function} mapFunction - function to use as map function\n     * @param {function} reduceFunction - function to use as reduce function\n     * @returns {data} The result of your mapReduce operation\n     */\n    mapReduce(mapFunction, reduceFunction) {\n        return reduceFunction(this._data.map(mapFunction));\n    }\n    /**\n     * Join two collections on specified properties\n     * @param {array} joinData - array of documents to 'join' to this collection\n     * @param {string} leftJoinProp - property name in collection\n     * @param {string} rightJoinProp - property name in joinData\n     * @param {function} mapFun - (Optional) map function to use\n     * @param dataOptions - options to data() before input to your map function\n     * @param [dataOptions.removeMeta] - allows removing meta before calling mapFun\n     * @param [dataOptions.forceClones] - forcing the return of cloned objects to your map object\n     * @param [dataOptions.forceCloneMethod] - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} Result of the mapping operation\n     */\n    eqJoin(joinData, leftJoinProp, rightJoinProp, mapFun, dataOptions) {\n        return new result_set_ResultSet(this).eqJoin(joinData, leftJoinProp, rightJoinProp, mapFun, dataOptions);\n    }\n    /* ------ STAGING API -------- */\n    /**\n     * (Staging API) create a stage and/or retrieve it\n     */\n    getStage(name) {\n        if (!this._stages[name]) {\n            this._stages[name] = {};\n        }\n        return this._stages[name];\n    }\n    /**\n     * a collection of objects recording the changes applied through a commmitStage\n     */\n    /**\n     * (Staging API) create a copy of an object and insert it into a stage\n     */\n    stage(stageName, obj) {\n        const copy = JSON.parse(JSON.stringify(obj));\n        this.getStage(stageName)[obj.$loki] = copy;\n        return copy;\n    }\n    /**\n     * (Staging API) re-attach all objects to the original collection, so indexes and views can be rebuilt\n     * then create a message to be inserted in the commitlog\n     * @param {string} stageName - name of stage\n     * @param {string} message\n     */\n    commitStage(stageName, message) {\n        const stage = this.getStage(stageName);\n        const timestamp = new Date().getTime();\n        for (const prop in stage) {\n            this.update(stage[prop]);\n            this._commitLog.push({\n                timestamp,\n                message,\n                data: JSON.parse(JSON.stringify(stage[prop]))\n            });\n        }\n        this._stages[stageName] = {};\n    }\n    /**\n     * Returns all values of a field.\n     * @param {string} field - the field name\n     * @return {any}: the array of values\n     */\n    extract(field) {\n        const result = [];\n        for (let i = 0; i < this._data.length; i++) {\n            result.push(this._data[i][field]);\n        }\n        return result;\n    }\n    /**\n     * Finds the minimum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the minimum value\n     */\n    min(field) {\n        return Math.min.apply(null, this.extractNumerical(field));\n    }\n    /**\n     * Finds the maximum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the maximum value\n     */\n    max(field) {\n        return Math.max.apply(null, this.extractNumerical(field));\n    }\n    /**\n     * Finds the minimum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    minRecord(field) {\n        const result = {\n            index: 0,\n            value: 0\n        };\n        if (this._data.length === 0) {\n            result.index = null;\n            result.value = null;\n            return result;\n        }\n        result.index = this._data[0].$loki;\n        result.value = parseFloat(this._data[0][field]);\n        for (let i = 1; i < this._data.length; i++) {\n            const val = parseFloat(this._data[i][field]);\n            if (result.value > val) {\n                result.value = val;\n                result.index = this._data[i].$loki;\n            }\n        }\n        return result;\n    }\n    /**\n     * Finds the maximum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    maxRecord(field) {\n        const result = {\n            index: 0,\n            value: 0\n        };\n        if (this._data.length === 0) {\n            result.index = null;\n            result.value = null;\n            return result;\n        }\n        result.index = this._data[0].$loki;\n        result.value = parseFloat(this._data[0][field]);\n        for (let i = 1; i < this._data.length; i++) {\n            const val = parseFloat(this._data[i][field]);\n            if (result.value < val) {\n                result.value = val;\n                result.index = this._data[i].$loki;\n            }\n        }\n        return result;\n    }\n    /**\n     * Returns all values of a field as numbers (if possible).\n     * @param {string} field - the field name\n     * @return {number[]} - the number array\n     */\n    extractNumerical(field) {\n        return this.extract(field).map(parseFloat).filter(Number).filter((n) => !(isNaN(n)));\n    }\n    /**\n     * Calculates the average numerical value of a field\n     * @param {string} field - the field name\n     * @returns {number} average of property in all docs in the collection\n     */\n    avg(field) {\n        return average(this.extractNumerical(field));\n    }\n    /**\n     * Calculate the standard deviation of a field.\n     * @param {string} field - the field name\n     * @return {number} the standard deviation\n     */\n    stdDev(field) {\n        return standardDeviation(this.extractNumerical(field));\n    }\n    /**\n     * Calculates the mode of a field.\n     * @param {string} field - the field name\n     * @return {number} the mode\n     */\n    mode(field) {\n        const dict = {};\n        const data = this.extractNumerical(field);\n        let mode = data[0];\n        let maxCount = -Infinity;\n        for (let i = 0; i < data.length; i++) {\n            const el = data[i];\n            if (dict[el]) {\n                dict[el]++;\n            }\n            else {\n                dict[el] = 1;\n            }\n            if (dict[el] > maxCount) {\n                mode = el;\n                maxCount = dict[el];\n            }\n        }\n        return mode;\n    }\n    /**\n     * Calculates the median of a field.\n     * @param {string} field - the field name\n     * @return {number} the median\n     */\n    median(field) {\n        const values = this.extractNumerical(field);\n        values.sort((a, b) => a - b);\n        const half = Math.floor(values.length / 2);\n        if (values.length % 2) {\n            return values[half];\n        }\n        else {\n            return (values[half - 1] + values[half]) / 2.0;\n        }\n    }\n}\n\n\n/***/ }),\n/* 4 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// CONCATENATED MODULE: ./packages/loki/src/avl_index.ts\n/**\n * LokiDB AVL Balanced Binary Tree Index implementation.\n * To support duplicates, we use siblings (array) in tree nodes.\n * Basic AVL components guided by William Fiset tutorials at :\n * https://github.com/williamfiset/data-structures/blob/master/com/williamfiset/datastructures/balancedtree/AVLTreeRecursive.java\n * https://www.youtube.com/watch?v=g4y2h70D6Nk&list=PLDV1Zeh2NRsD06x59fxczdWLhDDszUHKt\n */\nclass AvlTreeIndex {\n    /**\n     * Initializes index with property name and a comparer function.\n     */\n    constructor(name, comparator) {\n        this.nodes = {};\n        this.apex = null;\n        this.name = name;\n        this.comparator = comparator;\n    }\n    backup() {\n        let result = new AvlTreeIndex(this.name, this.comparator);\n        result.nodes = JSON.parse(JSON.stringify(this.nodes));\n        result.apex = this.apex;\n        return result;\n    }\n    restore(tree) {\n        this.name = tree.name;\n        this.comparator = tree.comparator;\n        this.nodes = JSON.parse(JSON.stringify(tree.nodes));\n        this.apex = tree.apex;\n    }\n    /**\n     * Used for inserting a new value into the BinaryTreeIndex\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val Value to be indexed and inserted into binary tree\n     */\n    insert(id, val) {\n        if (id <= 0) {\n            throw new Error(\"avl index ids are required to be numbers greater than zero\");\n        }\n        let node = this.nodes[id] = {\n            id: id,\n            value: val,\n            parent: null,\n            balance: 0,\n            height: 0,\n            left: null,\n            right: null,\n            siblings: []\n        };\n        if (!this.apex) {\n            this.apex = id;\n            return;\n        }\n        this.insertNode(this.nodes[this.apex], node);\n    }\n    /**\n     * Recursively inserts a treenode and re-balances if needed.\n     * @param current\n     * @param node\n     */\n    insertNode(current, node) {\n        switch (this.comparator(node.value, current.value)) {\n            case 0:\n                // eq\n                current.siblings.push(node.id);\n                node.parent = current.id;\n                break;\n            case 1:\n                // gt\n                if (current.right) {\n                    this.insertNode(this.nodes[current.right], node);\n                    this.updateBalance(current);\n                }\n                else {\n                    current.right = node.id;\n                    node.parent = current.id;\n                    this.updateBalance(current);\n                }\n                break;\n            case -1:\n                // lt\n                if (current.left) {\n                    this.insertNode(this.nodes[current.left], node);\n                    this.updateBalance(current);\n                }\n                else {\n                    current.left = node.id;\n                    node.parent = current.id;\n                    this.updateBalance(current);\n                }\n                break;\n            default: throw new Error(\"Invalid comparator result\");\n        }\n        if (current.balance < -1) {\n            if (current.left === null) {\n                throw new Error(\"insertNode.balance() : left child should not be null\");\n            }\n            if (this.nodes[current.left].balance <= 0) {\n                this.leftLeftCase(current);\n            }\n            else {\n                this.leftRightCase(current);\n            }\n        }\n        if (current.balance > 1) {\n            if (current.right === null) {\n                throw new Error(\"insertNode.balance() : right child should not be null\");\n            }\n            if (this.nodes[current.right].balance >= 0) {\n                this.rightRightCase(current);\n            }\n            else {\n                this.rightLeftCase(current);\n            }\n        }\n        return current.height;\n    }\n    /**\n     * Updates height and balance (calculation) for tree node\n     * @param node\n     */\n    updateBalance(node) {\n        let hl = node.left ? this.nodes[node.left].height : -1;\n        let hr = node.right ? this.nodes[node.right].height : -1;\n        //node.height = 1 + Math.max(hl, hr);\n        node.height = (hl > hr) ? 1 + hl : 1 + hr;\n        node.balance = hr - hl;\n    }\n    /**\n     * Balance the 'double left-heavy' condition\n     * @param node\n     */\n    leftLeftCase(node) {\n        return this.rotateRight(node);\n    }\n    /**\n     * Balance the '(parent) left heavy, (child) right heavy' condition\n     * @param node\n     */\n    leftRightCase(node) {\n        if (!node.left) {\n            throw new Error(\"leftRightCase: left child not set\");\n        }\n        node.left = this.rotateLeft(this.nodes[node.left]).id;\n        return this.rotateRight(node);\n    }\n    /**\n     * Balance the 'double right-heavy' condition\n     * @param node\n     */\n    rightRightCase(node) {\n        return this.rotateLeft(node);\n    }\n    /**\n     * Balance the '(parent) right heavy, (child) left heavy' condition\n     * @param node\n     */\n    rightLeftCase(node) {\n        if (!node.right) {\n            throw new Error(\"rightLeftCase: right child not set\");\n        }\n        node.right = this.rotateRight(this.nodes[node.right]).id;\n        return this.rotateLeft(node);\n    }\n    /**\n     * Left rotation of node. Swaps right child into current location.\n     * @param node\n     */\n    rotateLeft(node) {\n        if (!node.right) {\n            throw new Error(\"rotateLeft: right child was unavailable.\");\n        }\n        let parent = (node.parent) ? this.nodes[node.parent] : null;\n        let right = this.nodes[node.right];\n        // assume rights (old) left branch as our (new) right branch\n        node.right = right.left;\n        if (node.right) {\n            this.nodes[node.right].parent = node.id;\n        }\n        // right will be new parent to node and assume old node's parent\n        right.left = node.id;\n        right.parent = node.parent;\n        node.parent = right.id;\n        // remap parent child pointer to right\n        if (parent) {\n            if (parent.left === node.id) {\n                parent.left = right.id;\n            }\n            else if (parent.right === node.id) {\n                parent.right = right.id;\n            }\n            else {\n                throw new Error(\"rotateLeft() : attempt to remap parent back to child failed... not found\");\n            }\n        }\n        else {\n            if (this.apex !== node.id) {\n                throw new Error(\"rightRotate expecting parentless node to be apex\");\n            }\n            this.apex = right.id;\n        }\n        // recalculate height and balance for swapped nodes\n        this.updateBalance(node);\n        this.updateBalance(right);\n        return right;\n    }\n    /**\n     * Right rotation of node. Swaps left child into current location.\n     * @param node\n     */\n    rotateRight(node) {\n        if (!node.left) {\n            throw new Error(\"rotateRight : left child unavailable\");\n        }\n        let parent = (node.parent) ? this.nodes[node.parent] : null;\n        let left = this.nodes[node.left];\n        // assume left's (old) right branch as our (new) left branch\n        node.left = left.right;\n        if (left.right) {\n            this.nodes[left.right].parent = node.id;\n        }\n        // 'node' will be right child of left\n        left.right = node.id;\n        left.parent = node.parent;\n        node.parent = left.id;\n        if (parent) {\n            if (parent.left === node.id) {\n                parent.left = left.id;\n            }\n            else {\n                parent.right = left.id;\n            }\n        }\n        else {\n            if (this.apex !== node.id) {\n                throw new Error(\"rightRotate expecting parentless node to be apex\");\n            }\n            this.apex = left.id;\n        }\n        // recalculate height and balance for swapped nodes\n        this.updateBalance(node);\n        this.updateBalance(left);\n        return left;\n    }\n    /**\n     * Diagnostic method for examining tree contents and structure\n     * @param node\n     */\n    getValuesAsTree(node) {\n        if (this.apex === null)\n            return null;\n        node = node || this.nodes[this.apex];\n        return {\n            id: node.id,\n            val: node.value,\n            siblings: node.siblings,\n            balance: node.balance,\n            height: node.height,\n            left: node.left ? this.getValuesAsTree(this.nodes[node.left]) : null,\n            right: node.right ? this.getValuesAsTree(this.nodes[node.right]) : null,\n        };\n    }\n    /**\n     * Updates a value, possibly relocating it, within binary tree\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val New value to be indexed within binary tree\n     */\n    update(id, val) {\n        let node = this.nodes[id];\n        let cmp = this.comparator(node.value, val);\n        // if the value did not change, or changed to value considered equal to itself, return.\n        if (cmp === 0)\n            return;\n        this.remove(id);\n        this.insert(id, val);\n    }\n    /**\n     * Removes a value from the binary tree index\n     * @param id\n     */\n    remove(id) {\n        if (!this.apex) {\n            throw new Error(\"remove() : attempting remove when tree has no apex\");\n        }\n        this.removeNode(this.nodes[this.apex], id);\n    }\n    /**\n     * Recursive node removal and rebalancer\n     * @param node\n     * @param val\n     */\n    removeNode(node, id) {\n        if (!this.nodes[id]) {\n            throw new Error(\"removeNode: attempting to remove a node which is not in hashmap\");\n        }\n        let val = this.nodes[id].value;\n        switch (this.comparator(val, node.value)) {\n            case 0:\n                // eq - handle siblings if present\n                if (node.siblings.length > 0) {\n                    // if node to remove is alpha sibling...\n                    if (node.id === id) {\n                        // get first sibling as replacement\n                        let alphaSiblingId = node.siblings.shift();\n                        let alphaSibling = this.nodes[alphaSiblingId];\n                        // remap all properties but id and value from node onto alphasibling\n                        alphaSibling.parent = node.parent;\n                        this.updateChildLink(node.parent, id, alphaSiblingId);\n                        if (node.left) {\n                            this.nodes[node.left].parent = alphaSiblingId;\n                        }\n                        if (node.right) {\n                            this.nodes[node.right].parent = alphaSiblingId;\n                        }\n                        alphaSibling.left = node.left;\n                        alphaSibling.right = node.right;\n                        alphaSibling.siblings = node.siblings;\n                        alphaSibling.height = node.height;\n                        alphaSibling.balance = node.balance;\n                        if (this.apex === id) {\n                            this.apex = alphaSiblingId;\n                        }\n                        // parent all remaining siblings alphaSibling (new parent)\n                        for (let si of alphaSibling.siblings) {\n                            this.nodes[si].parent = alphaSiblingId;\n                        }\n                        // delete old node from nodes and return\n                        delete this.nodes[id];\n                        return;\n                    }\n                    // else we are inner sibling\n                    else {\n                        let idx = node.siblings.indexOf(id);\n                        if (idx === -1) {\n                            throw new Error(\"Unable to remove sibling from parented sibling\");\n                        }\n                        node.siblings.splice(idx, 1);\n                        delete this.nodes[id];\n                        return;\n                    }\n                }\n                // else we have no siblings, node will be removed\n                else {\n                    // if node to delete has no children\n                    if (!node.left && !node.right) {\n                        // if we have a parent, remove us from either left or right child link\n                        this.updateChildLink(node.parent, node.id, null);\n                        delete this.nodes[id];\n                        if (id === this.apex) {\n                            this.apex = null;\n                        }\n                        return;\n                    }\n                    // if node to delete has only one child we can do simple copy/replace\n                    if (!node.left || !node.right) {\n                        if (node.left) {\n                            this.promoteChild(node, this.nodes[node.left]);\n                            if (this.apex === id) {\n                                this.apex = node.left;\n                            }\n                        }\n                        if (node.right) {\n                            this.promoteChild(node, this.nodes[node.right]);\n                            if (this.apex === id) {\n                                this.apex = node.right;\n                            }\n                        }\n                        return;\n                    }\n                    // node to delete has two children, need swap with inorder successor\n                    // use find inorder successor by default\n                    this.promoteSuccessor(node);\n                    return;\n                }\n            case 1:\n                // gt - search right branch\n                if (!node.right) {\n                    throw new Error(\"removeNode: Unable to find value in tree\");\n                }\n                this.removeNode(this.nodes[node.right], id);\n                break;\n            case -1:\n                // lt - search left branch\n                if (!node.left) {\n                    throw new Error(\"removeNode: Unable to find value in tree\");\n                }\n                this.removeNode(this.nodes[node.left], id);\n                break;\n        }\n        this.updateBalance(node);\n        if (node.balance < -1) {\n            if (node.left === null) {\n                throw new Error(\"insertNode.balance() : left child should not be null\");\n            }\n            if (this.nodes[node.left].balance <= 0) {\n                this.leftLeftCase(node);\n            }\n            else {\n                this.leftRightCase(node);\n            }\n        }\n        if (node.balance > 1) {\n            if (node.right === null) {\n                throw new Error(\"insertNode.balance() : right child should not be null\");\n            }\n            if (this.nodes[node.right].balance >= 0) {\n                this.rightRightCase(node);\n            }\n            else {\n                this.rightLeftCase(node);\n            }\n        }\n    }\n    /**\n     * Utility method for updating a parent's child link when it changes\n     * @param parentId\n     * @param oldChildId\n     * @param newChildId\n     */\n    updateChildLink(parentId, oldChildId, newChildId) {\n        if (parentId === null)\n            return;\n        let parent = this.nodes[parentId];\n        if (parent.left === oldChildId) {\n            parent.left = newChildId;\n        }\n        else if (parent.right === oldChildId) {\n            parent.right = newChildId;\n        }\n    }\n    /**\n     * When removing a parent with only child, this does simple remap of child to grandParent.\n     * @param grandParent New parent of 'child'.\n     * @param parent Node being removed.\n     * @param child Node to reparent to grandParent.\n     */\n    promoteChild(parent, child) {\n        let gpId = parent.parent;\n        if (gpId) {\n            let gp = this.nodes[gpId];\n            if (gp.left === parent.id) {\n                gp.left = child.id;\n            }\n            else if (gp.right === parent.id) {\n                gp.right = child.id;\n            }\n        }\n        // remap (grand) child's parent pointer to grandparent (new parent) or null if new apex\n        child.parent = gpId;\n        // remove parent from bst hashmap\n        delete this.nodes[parent.id];\n        return;\n    }\n    /**\n     * Finds a successor to a node and replaces that node with it.\n     * @param node\n     */\n    promoteSuccessor(node) {\n        let oldId = node.id;\n        // assume successor/right branch (for now)\n        if (!node.right || !node.left) {\n            throw new Error(\"promoteSuccessor() : node to replace does not have two children\");\n        }\n        let successor = null;\n        let glsId;\n        let glsValue;\n        let glsSiblings;\n        // if tree is already left heavy,\n        // let's replace with predecessor (greatest val in left branch)\n        if (node.balance < 0) {\n            let lchild = this.nodes[node.left];\n            successor = this.findGreaterLeaf(lchild);\n            glsId = successor.id;\n            glsValue = successor.value;\n            glsSiblings = successor.siblings;\n            successor.siblings = [];\n            this.removeNode(lchild, glsId);\n        }\n        // otherwise the tree is either balanced or right heavy,\n        // so let's use sucessor (least value in right branch)\n        else {\n            let rchild = this.nodes[node.right];\n            successor = this.findLesserLeaf(rchild);\n            glsId = successor.id;\n            glsValue = successor.value;\n            glsSiblings = successor.siblings;\n            // dont leave any siblings when we (temporarily) 'remove' or they will assume ownership of old node\n            successor.siblings = [];\n            this.removeNode(rchild, glsId);\n        }\n        // update any parent pointers to node being replaced\n        if (node.parent) {\n            let p = this.nodes[node.parent];\n            if (p.left === oldId)\n                p.left = glsId;\n            if (p.right === oldId)\n                p.right = glsId;\n        }\n        // update any child points to node being replaced\n        if (node.left)\n            this.nodes[node.left].parent = glsId;\n        if (node.right)\n            this.nodes[node.right].parent = glsId;\n        // update (reuse) node instance id and value with that of successor\n        node.id = glsId;\n        node.value = glsValue;\n        node.siblings = glsSiblings;\n        // update hashmap\n        this.nodes[glsId] = node;\n        delete this.nodes[oldId];\n        // if old was apex, update apex to point to successor\n        if (this.apex === oldId)\n            this.apex = glsId;\n        this.updateBalance(node);\n    }\n    /**\n     * Utility method for finding In-Order predecessor to the provided node\n     * @param node Parent node to find leaf node of greatest 'value'\n    */\n    findGreaterLeaf(node) {\n        if (!node.right) {\n            return node;\n        }\n        let result = this.findGreaterLeaf(this.nodes[node.right]);\n        return result ? result : node;\n    }\n    /**\n     * Utility method for finding In-Order successor to the provided node\n     * @param node Parent Node to find leaf node of least 'value'\n     */\n    findLesserLeaf(node) {\n        if (!node.left) {\n            return node;\n        }\n        let result = this.findLesserLeaf(this.nodes[node.left]);\n        return result ? result : node;\n    }\n    /**\n     *  Interface method to support ranged queries.  Results sorted by index property.\n     * @param range Options for ranged request.\n     */\n    rangeRequest(range) {\n        if (!this.apex)\n            return [];\n        // if requesting all id's sorted by their value\n        if (!range) {\n            return this.collateIds(this.nodes[this.apex]);\n        }\n        if (range.op === \"$eq\") {\n            let match = this.locate(this.nodes[this.apex], range.val);\n            if (match === null) {\n                return [];\n            }\n            if (match.siblings.length) {\n                return [match.id, ...match.siblings];\n            }\n            return [match.id];\n        }\n        let result = this.collateRequest(this.nodes[this.apex], range);\n        return result;\n    }\n    /**\n     * Implements ranged request operations.\n     * @param node\n     * @param range\n     */\n    collateRequest(node, range) {\n        let result = [];\n        if (range.op === \"$eq\") {\n            // we use locate instead for $eq range requests\n            throw new Error(\"collateRequest does not support $eq range request\");\n        }\n        let cmp1 = this.comparator(node.value, range.val);\n        let cmp2 = 0;\n        if (range.op === \"$between\") {\n            if (range.high === null || range.high === undefined) {\n                throw new Error(\"collateRequest: $between request missing high range value\");\n            }\n            cmp2 = this.comparator(node.value, range.high);\n        }\n        if (node.left) {\n            switch (range.op) {\n                case \"$lt\":\n                case \"$lte\":\n                    result = this.collateRequest(this.nodes[node.left], range);\n                    break;\n                case \"$gt\":\n                case \"$gte\":\n                    // if the current node is still greater than compare value,\n                    // it's possible left child will be too\n                    if (cmp1 === 1) {\n                        result = this.collateRequest(this.nodes[node.left], range);\n                    }\n                    break;\n                case \"$between\":\n                    // only pursue left path if current node greater than (low) range val\n                    if (cmp1 === 1) {\n                        result = this.collateRequest(this.nodes[node.left], range);\n                    }\n                    break;\n                default: break;\n            }\n        }\n        if (!range) {\n            result.push(node.id);\n            result.push(...node.siblings);\n        }\n        else {\n            switch (range.op) {\n                case \"$lt\":\n                    if (cmp1 === -1) {\n                        result.push(node.id);\n                        result.push(...node.siblings);\n                    }\n                    break;\n                case \"$lte\":\n                    if (cmp1 === -1 || cmp1 === 0) {\n                        result.push(node.id);\n                        result.push(...node.siblings);\n                    }\n                    break;\n                case \"$gt\":\n                    if (cmp1 === 1) {\n                        result.push(node.id);\n                        result.push(...node.siblings);\n                    }\n                    break;\n                case \"$gte\":\n                    if (cmp1 === 1 || cmp1 === 0) {\n                        result.push(node.id);\n                        result.push(...node.siblings);\n                    }\n                    break;\n                case \"$between\":\n                    if (cmp1 >= 0 && cmp2 <= 0) {\n                        result.push(node.id);\n                        result.push(...node.siblings);\n                    }\n                    break;\n                default: break;\n            }\n        }\n        if (node.right) {\n            if (!range) {\n                result.push(...this.collateRequest(this.nodes[node.right], range));\n            }\n            else {\n                switch (range.op) {\n                    case \"$lt\":\n                    case \"$lte\":\n                        // if the current node is still less than compare value,\n                        // it's possible right child will be too\n                        if (cmp1 === -1) {\n                            result.push(...this.collateRequest(this.nodes[node.right], range));\n                        }\n                        break;\n                    case \"$gt\":\n                    case \"$gte\":\n                        result.push(...this.collateRequest(this.nodes[node.right], range));\n                        break;\n                    case \"$between\":\n                        // only pursue right path if current node less than (high) range val\n                        if (cmp2 === -1) {\n                            result.push(...this.collateRequest(this.nodes[node.right], range));\n                        }\n                        break;\n                    default: break;\n                }\n            }\n        }\n        return result;\n    }\n    /**\n     * Used on a branch node to return an array of id within that branch, sorted by their value\n     * @param node\n     */\n    collateIds(node) {\n        let result = [];\n        // debug diagnostic\n        if (!node) {\n            return [];\n        }\n        if (node.left) {\n            result = this.collateIds(this.nodes[node.left]);\n        }\n        result.push(node.id);\n        result.push(...node.siblings);\n        if (node.right) {\n            result.push(...this.collateIds(this.nodes[node.right]));\n        }\n        return result;\n    }\n    /**\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    /*\n    private locate(node: TreeNode<T>, val: any): TreeNode<T> {\n       switch (this.comparator.compare(val, node.value)) {\n          case 0: return node;\n          case 1:\n             if (!node.right) {\n                return null;\n             }\n  \n             return this.locate(this.nodes[node.right], val);\n          case -1:\n             if (!node.left) {\n                return null;\n             }\n  \n             return this.locate(this.nodes[node.left], val);\n       }\n    }\n    */\n    /**\n     * Inline/Non-recusive 'single value' ($eq) lookup.\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    locate(node, val) {\n        while (node !== null) {\n            switch (this.comparator(val, node.value)) {\n                case 0: return node;\n                case 1:\n                    if (!node.right) {\n                        return null;\n                    }\n                    node = this.nodes[node.right];\n                    break;\n                case -1:\n                    if (!node.left) {\n                        return null;\n                    }\n                    node = this.nodes[node.left];\n                    break;\n            }\n        }\n        return null;\n    }\n    /**\n     * Index integrity check (IRangedIndex interface function)\n     */\n    validateIndex() {\n        // handle null apex condition and verify empty tree and nodes\n        if (!this.apex) {\n            if (Object.keys(this.nodes).length !== 0) {\n                return false;\n            }\n            return true;\n        }\n        // ensure apex has no parent\n        if (this.nodes[this.apex].parent !== null) {\n            return false;\n        }\n        // high level verification - retrieve all node ids ordered by their values\n        let result = this.collateIds(this.nodes[this.apex]);\n        let nc = Object.keys(this.nodes).length;\n        // verify the inorder traversal returned same number of elements as nodes hashmap\n        if (result.length !== nc) {\n            return false;\n        }\n        // if only one result\n        if (result.length === 1) {\n            if (this.nodes[result[0]].parent !== null)\n                return false;\n            if (this.nodes[result[0]].left !== null)\n                return false;\n            if (this.nodes[result[0]].right !== null)\n                return false;\n            return true;\n        }\n        // iterate results and ensure next value is greater or equal to current\n        for (let i = 0; i < result.length - 1; i++) {\n            if (this.comparator(this.nodes[result[i]].value, this.nodes[result[i + 1]].value) === 1) {\n                return false;\n            }\n        }\n        return this.validateNode(this.nodes[this.apex]);\n    }\n    /**\n     * Recursive Node validation routine\n     * @param node\n     */\n    validateNode(node) {\n        // should never have parent or child pointers reference self\n        if ([node.parent, node.left, node.right].indexOf(node.id) !== -1) {\n            return false;\n        }\n        // validate height and balance\n        let hl = (node.left) ? this.nodes[node.left].height : -1;\n        let hr = (node.right) ? this.nodes[node.right].height : -1;\n        let eh = 1 + Math.max(hl, hr);\n        if (node.height !== eh) {\n            return false;\n        }\n        if (node.balance !== hr - hl) {\n            return false;\n        }\n        // verify any siblings parent back to self\n        if (node.siblings.length > 0) {\n            for (let sid of node.siblings) {\n                if (this.nodes[sid].parent !== node.id)\n                    return false;\n            }\n        }\n        // if there is a left child, verify it parents to self and recurse it\n        if (node.left) {\n            if (this.nodes[node.left].parent !== node.id) {\n                return false;\n            }\n            if (!this.validateNode(this.nodes[node.left])) {\n                return false;\n            }\n        }\n        // if there is a right child, verify it parents to self and recurse it\n        if (node.right) {\n            if (this.nodes[node.right].parent !== node.id) {\n                return false;\n            }\n            if (!this.validateNode(this.nodes[node.right])) {\n                return false;\n            }\n        }\n        return true;\n    }\n}\n\n// CONCATENATED MODULE: ./packages/loki/src/ranged_indexes.ts\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return RangedIndexFactoryMap; });\n\n/** Map/Register of named factory functions returning IRangedIndex instances */\nlet RangedIndexFactoryMap = {\n    \"avl\": (name, comparator) => { return new AvlTreeIndex(name, comparator); }\n};\n\n\n/***/ }),\n/* 5 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return LokiEventEmitter; });\n/**\n * LokiEventEmitter is a minimalist version of EventEmitter. It enables any\n * constructor that inherits EventEmitter to emit events and trigger\n * listeners that have been added to the event through the on(event, callback) method\n *\n * @constructor LokiEventEmitter\n */\nclass LokiEventEmitter {\n    constructor() {\n        /**\n         * A map, with each property being an array of callbacks.\n         */\n        this._events = {};\n        /**\n         * Determines whether or not the callbacks associated with each event should happen in an async fashion or not.\n         * Default is false, which means events are synchronous\n         */\n        this._asyncListeners = false;\n    }\n    /**\n     * Adds a listener to the queue of callbacks associated to an event\n     * @param {string|string[]} eventName - the name(s) of the event(s) to listen to\n     * @param {function} listener - callback function of listener to attach\n     * @returns {int} the index of the callback in the array of listeners for a particular event\n     */\n    on(eventName, listener) {\n        let event;\n        if (Array.isArray(eventName)) {\n            eventName.forEach((currentEventName) => {\n                this.on(currentEventName, listener);\n            });\n            return listener;\n        }\n        event = this._events[eventName];\n        if (!event) {\n            event = this._events[eventName] = [];\n        }\n        event.push(listener);\n        return listener;\n    }\n    /**\n     * Emits a particular event\n     * with the option of passing optional parameters which are going to be processed by the callback\n     * provided signatures match (i.e. if passing emit(event, arg0, arg1) the listener should take two parameters)\n     * @param {string} eventName - the name of the event\n     * @param {object} data - optional object passed with the event\n     */\n    emit(eventName, ...data) {\n        if (eventName && this._events[eventName]) {\n            this._events[eventName].forEach((listener) => {\n                if (this._asyncListeners) {\n                    setTimeout(() => {\n                        listener(...data);\n                    }, 1);\n                }\n                else {\n                    listener(...data);\n                }\n            });\n        }\n    }\n    /**\n     * Alias of EventEmitter.on().\n     */\n    addListener(eventName, listener) {\n        return this.on(eventName, listener);\n    }\n    /**\n     * Removes the listener at position 'index' from the event 'eventName'\n     * @param {string|string[]} eventName - the name(s) of the event(s) which the listener is attached to\n     * @param {function} listener - the listener callback function to remove from emitter\n     */\n    removeListener(eventName, listener) {\n        if (Array.isArray(eventName)) {\n            eventName.forEach((currentEventName) => {\n                this.removeListener(currentEventName, listener);\n            });\n        }\n        if (this._events[eventName]) {\n            const listeners = this._events[eventName];\n            listeners.splice(listeners.indexOf(listener), 1);\n        }\n    }\n}\n\n\n/***/ }),\n/* 6 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return Loki; });\n/* harmony import */ var _event_emitter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5);\n/* harmony import */ var _collection__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);\n/* harmony import */ var _common_plugin__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1);\n/* harmony import */ var _comparators__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(0);\n/* harmony import */ var _ranged_indexes__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(4);\n/* harmony import */ var _operator_packages__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(2);\n\n\n\n\n\n\nfunction getENV() {\n    if (global !== undefined && (global[\"android\"] || global[\"NSObject\"])) {\n        return \"NATIVESCRIPT\";\n    }\n    const isNode = global !== undefined && ({}).toString.call(global.process) === \"[object process]\";\n    if (isNode) {\n        if (global[\"window\"]) {\n            return \"NODEJS\"; //node-webkit\n        }\n        else {\n            return \"NODEJS\";\n        }\n    }\n    if (document !== undefined) {\n        if (document.URL.indexOf(\"http://\") === -1 && document.URL.indexOf(\"https://\") === -1) {\n            return \"CORDOVA\";\n        }\n        return \"BROWSER\";\n    }\n    const isBrowser = window !== undefined && ({}).toString.call(window) === \"[object Window]\";\n    if (isBrowser) {\n        return \"BROWSER\";\n    }\n    throw SyntaxError(\"Unknown environment...\");\n}\nclass Loki extends _event_emitter__WEBPACK_IMPORTED_MODULE_0__[/* LokiEventEmitter */ \"a\"] {\n    /**\n     * Constructs the main database class.\n     * @param {string} filename - name of the file to be saved to\n     * @param {object} [options={}] - options\n     * @param {Loki.Environment} [options.env] - the javascript environment\n     * @param {Loki.SerializationMethod} [options.serializationMethod=NORMAL] - the serialization method\n     * @param {string} [options.destructureDelimiter=\"$<\\n\"] - string delimiter used for destructured serialization\n     * @param {IComparatorMap} [options.comparatorMap] allows injecting or overriding registered comparators\n     * @param {IRangedIndexFactoryMap} [options.rangedIndexFactoryMap] allows injecting or overriding registered ranged index factories\n     * @param {ILokiOperatorPackageMap} [options.lokiOperatorPackageMap] allows injecting or overriding registered loki operator packages\n     */\n    constructor(filename = \"loki.db\", options = {}) {\n        super();\n        // persist version of code which created the database to the database.\n        // could use for upgrade scenarios\n        this.databaseVersion = 1.5; // TODO\n        this.engineVersion = 1.5;\n        // persistenceMethod could be 'fs', 'localStorage', or 'adapter'\n        // this is optional option param, otherwise environment detection will be used\n        // if user passes their own adapter we will force this method to 'adapter' later, so no need to pass method option.\n        this._persistenceMethod = null;\n        // retain reference to optional (non-serializable) persistenceAdapter 'instance'\n        this._persistenceAdapter = null;\n        // flags used to throttle saves\n        this._throttledSaves = true;\n        this._throttledSaveRunning = null;\n        this._throttledSavePending = null;\n        // autosave support (disabled by default)\n        this._autosave = false;\n        this._autosaveInterval = 5000;\n        this._autosaveRunning = false;\n        this._autosaveHandler = Promise.resolve();\n        this.filename = filename;\n        this._collections = [];\n        ({\n            serializationMethod: this._serializationMethod = \"normal\",\n            destructureDelimiter: this._destructureDelimiter = \"$<\\n\",\n            env: this._env = getENV()\n        } = options);\n        this._events = {\n            \"init\": [],\n            \"loaded\": [],\n            \"flushChanges\": [],\n            \"close\": [],\n            \"changes\": [],\n            \"warning\": []\n        };\n        // allow users to inject their own comparators\n        if (options.comparatorMap) {\n            for (let c in options.comparatorMap) {\n                _comparators__WEBPACK_IMPORTED_MODULE_3__[/* ComparatorMap */ \"a\"][c] = options.comparatorMap[c];\n            }\n        }\n        // allow users to register their own rangedIndex factory functions\n        if (options.rangedIndexFactoryMap) {\n            for (let rif in options.rangedIndexFactoryMap) {\n                _ranged_indexes__WEBPACK_IMPORTED_MODULE_4__[/* RangedIndexFactoryMap */ \"a\"][rif] = options.rangedIndexFactoryMap[rif];\n            }\n        }\n        // allow users to register their own LokiOperatorPackages or inject functionality within existing ones\n        if (options.lokiOperatorPackageMap) {\n            for (let lop in options.lokiOperatorPackageMap) {\n                _operator_packages__WEBPACK_IMPORTED_MODULE_5__[/* LokiOperatorPackageMap */ \"a\"][lop] = options.lokiOperatorPackageMap[lop];\n            }\n        }\n        this.on(\"init\", this.clearChanges);\n    }\n    /**\n     * configures options related to database persistence.\n     *\n     * @param {Loki.PersistenceOptions} [options={}] - options\n     * @param {adapter} [options.adapter=auto] - an instance of a loki persistence adapter\n     * @param {boolean} [options.autosave=false] - enables autosave\n     * @param {int} [options.autosaveInterval=5000] - time interval (in milliseconds) between saves (if dirty)\n     * @param {boolean} [options.autoload=false] - enables autoload on loki instantiation\n     * @param {object} options.inflate - options that are passed to loadDatabase if autoload enabled\n     * @param {boolean} [options.throttledSaves=true] - if true, it batches multiple calls to to saveDatabase reducing number of\n     *   disk I/O operations and guaranteeing proper serialization of the calls. Default value is true.\n     * @param {Loki.PersistenceMethod} options.persistenceMethod - a persistence method which should be used (FS_STORAGE, LOCAL_STORAGE...)\n     * @returns {Promise} a Promise that resolves after initialization and (if enabled) autoloading the database\n     */\n    initializePersistence(options = {}) {\n        let loaded = this._autosaveDisable();\n        ({\n            autosave: this._autosave = false,\n            autosaveInterval: this._autosaveInterval = 5000,\n            persistenceMethod: this._persistenceMethod,\n            // TODO\n            //inflate: this.options.inflate,\n            throttledSaves: this._throttledSaves = true\n        } = options);\n        const DEFAULT_PERSISTENCE = {\n            \"NODEJS\": [\"fs-storage\"],\n            \"BROWSER\": [\"local-storage\", \"indexed-storage\"],\n            \"CORDOVA\": [\"local-storage\", \"indexed-storage\"],\n            \"MEMORY\": [\"memory-storage\"]\n        };\n        const PERSISTENCE_METHODS = {\n            \"fs-storage\": _common_plugin__WEBPACK_IMPORTED_MODULE_2__[/* PLUGINS */ \"a\"][\"FSStorage\"],\n            \"local-storage\": _common_plugin__WEBPACK_IMPORTED_MODULE_2__[/* PLUGINS */ \"a\"][\"LocalStorage\"],\n            \"indexed-storage\": _common_plugin__WEBPACK_IMPORTED_MODULE_2__[/* PLUGINS */ \"a\"][\"IndexedStorage\"],\n            \"memory-storage\": _common_plugin__WEBPACK_IMPORTED_MODULE_2__[/* PLUGINS */ \"a\"][\"MemoryStorage\"]\n        };\n        // process the options\n        if (this._persistenceMethod !== undefined) {\n            // check if the specified persistence method is known\n            if (typeof (PERSISTENCE_METHODS[this._persistenceMethod]) === \"function\") {\n                this._persistenceAdapter = new (PERSISTENCE_METHODS[this._persistenceMethod]);\n            }\n            else {\n                throw Error(\"Unknown persistence method.\");\n            }\n        }\n        // if user passes adapter, set persistence mode to adapter and retain persistence adapter instance\n        if (options.adapter !== undefined) {\n            this._persistenceMethod = \"adapter\";\n            this._persistenceAdapter = options.adapter;\n        }\n        // if by now there is no adapter specified by user nor derived from persistenceMethod: use sensible defaults\n        if (this._persistenceAdapter === null) {\n            let possiblePersistenceMethods = DEFAULT_PERSISTENCE[this._env];\n            if (possiblePersistenceMethods) {\n                for (let i = 0; i < possiblePersistenceMethods.length; i++) {\n                    if (PERSISTENCE_METHODS[possiblePersistenceMethods[i]]) {\n                        this._persistenceMethod = possiblePersistenceMethods[i];\n                        this._persistenceAdapter = new (PERSISTENCE_METHODS[possiblePersistenceMethods[i]]);\n                        break;\n                    }\n                }\n            }\n        }\n        // if they want to load database on loki instantiation, now is a good time to load... after adapter set and before\n        // possible autosave initiation\n        if (options.autoload) {\n            loaded = loaded.then(() => this._loadDatabase(options.inflate, true));\n        }\n        return loaded.then(() => {\n            this._autosaveEnable();\n        });\n    }\n    /**\n     * Copies 'this' database into a new Loki instance. Object references are shared to make lightweight.\n     * @param {object} options - options\n     * @param {boolean} options.removeNonSerializable - nulls properties not safe for serialization.\n     */\n    copy(options = {}) {\n        const databaseCopy = new Loki(this.filename, { env: this._env });\n        // currently inverting and letting loadJSONObject do most of the work\n        databaseCopy.loadJSONObject(this, {\n            retainDirtyFlags: true\n        });\n        // since our toJSON is not invoked for reference database adapters, this will let us mimic\n        if (options.removeNonSerializable) {\n            databaseCopy._persistenceAdapter = null;\n            for (let idx = 0; idx < databaseCopy._collections.length; idx++) {\n                databaseCopy._collections[idx]._constraints = null;\n                databaseCopy._collections[idx]._ttl = null;\n            }\n        }\n        return databaseCopy;\n    }\n    /**\n     * Adds a collection to the database.\n     * @param {string} name - name of collection to add\n     * @param {object} [options={}] - options to configure collection with.\n     * @param {array} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {array} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {array} [options.indices=[]] - array property names to define binary indexes for\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are called asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes Api\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {string} [options.cloneMethod=CloneMethod.DEEP] - the clone method\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @returns {Collection} a reference to the collection which was just added\n     */\n    addCollection(name, options = {}) {\n        // Return an existing collection if a collection with the same name already exists.\n        for (let i = 0; i < this._collections.length; i++) {\n            if (this._collections[i].name === name) {\n                return this._collections[i];\n            }\n        }\n        // Create a new collection otherwise.\n        const collection = new _collection__WEBPACK_IMPORTED_MODULE_1__[/* Collection */ \"a\"](name, options);\n        this._collections.push(collection);\n        return collection;\n    }\n    loadCollection(collection) {\n        if (!collection.name) {\n            throw new Error(\"Collection must have a name property to be loaded\");\n        }\n        this._collections.push(collection);\n    }\n    /**\n     * Retrieves reference to a collection by name.\n     * @param {string} name - name of collection to look up\n     * @returns {Collection} Reference to collection in database by that name, or null if not found\n     */\n    getCollection(name) {\n        for (let i = 0; i < this._collections.length; i++) {\n            if (this._collections[i].name === name) {\n                return this._collections[i];\n            }\n        }\n        // no such collection\n        this.emit(\"warning\", \"collection \" + name + \" not found\");\n        return null;\n    }\n    /**\n     * Renames an existing loki collection\n     * @param {string} oldName - name of collection to rename\n     * @param {string} newName - new name of collection\n     * @returns {Collection} reference to the newly renamed collection\n     */\n    renameCollection(oldName, newName) {\n        const c = this.getCollection(oldName);\n        if (c) {\n            c.name = newName;\n        }\n        return c;\n    }\n    listCollections() {\n        const colls = [];\n        for (let i = 0; i < this._collections.length; i++) {\n            colls.push({\n                name: this._collections[i].name,\n                count: this._collections[i].count()\n            });\n        }\n        return colls;\n    }\n    /**\n     * Removes a collection from the database.\n     * @param {string} collectionName - name of collection to remove\n     */\n    removeCollection(collectionName) {\n        for (let i = 0; i < this._collections.length; i++) {\n            if (this._collections[i].name === collectionName) {\n                const tmpcol = new _collection__WEBPACK_IMPORTED_MODULE_1__[/* Collection */ \"a\"](collectionName, {});\n                const curcol = this._collections[i];\n                for (const prop in curcol) {\n                    if (curcol[prop] !== undefined && tmpcol[prop] !== undefined) {\n                        curcol[prop] = tmpcol[prop];\n                    }\n                }\n                this._collections.splice(i, 1);\n                return;\n            }\n        }\n    }\n    /**\n     * Serialize database to a string which can be loaded via {@link Loki#loadJSON}\n     *\n     * @returns {string} Stringified representation of the loki database.\n     */\n    serialize(options = {}) {\n        if (options.serializationMethod === undefined) {\n            options.serializationMethod = this._serializationMethod;\n        }\n        switch (options.serializationMethod) {\n            case \"normal\":\n                return JSON.stringify(this);\n            case \"pretty\":\n                return JSON.stringify(this, null, 2);\n            case \"destructured\":\n                return this.serializeDestructured(); // use default options\n            default:\n                return JSON.stringify(this);\n        }\n    }\n    // alias of serialize\n    toJSON() {\n        return {\n            _env: this._env,\n            _serializationMethod: this._serializationMethod,\n            _autosave: this._autosave,\n            _autosaveInterval: this._autosaveInterval,\n            _collections: this._collections,\n            databaseVersion: this.databaseVersion,\n            engineVersion: this.engineVersion,\n            filename: this.filename,\n            _persistenceAdapter: this._persistenceAdapter,\n            _persistenceMethod: this._persistenceMethod,\n            _throttledSaves: this._throttledSaves\n        };\n    }\n    /**\n     * Database level destructured JSON serialization routine to allow alternate serialization methods.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {object} options - output format options for use externally to loki\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to only output an individual collection or db (-1)\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {string|Array} A custom, restructured aggregation of independent serializations.\n     */\n    serializeDestructured(options = {}) {\n        if (options.partitioned === undefined) {\n            options.partitioned = false;\n        }\n        if (options.delimited === undefined) {\n            options.delimited = true;\n        }\n        if (options.delimiter === undefined) {\n            options.delimiter = this._destructureDelimiter;\n        }\n        // 'partitioned' along with 'partition' of 0 or greater is a request for single collection serialization\n        if (options.partitioned === true && options.partition !== undefined && options.partition >= 0) {\n            return this.serializeCollection({\n                delimited: options.delimited,\n                delimiter: options.delimiter,\n                collectionIndex: options.partition\n            });\n        }\n        // not just an individual collection, so we will need to serialize db container via shallow copy\n        let dbcopy = new Loki(this.filename);\n        dbcopy.loadJSONObject(this);\n        for (let idx = 0; idx < dbcopy._collections.length; idx++) {\n            dbcopy._collections[idx]._data = [];\n        }\n        // if we -only- wanted the db container portion, return it now\n        if (options.partitioned === true && options.partition === -1) {\n            // since we are deconstructing, override serializationMethod to normal for here\n            return dbcopy.serialize({\n                serializationMethod: \"normal\"\n            });\n        }\n        // at this point we must be deconstructing the entire database\n        // start by pushing db serialization into first array element\n        const reconstruct = [];\n        reconstruct.push(dbcopy.serialize({\n            serializationMethod: \"normal\"\n        }));\n        dbcopy = null;\n        // push collection data into subsequent elements\n        for (let idx = 0; idx < this._collections.length; idx++) {\n            let result = this.serializeCollection({\n                delimited: options.delimited,\n                delimiter: options.delimiter,\n                collectionIndex: idx\n            });\n            // NDA : Non-Delimited Array : one iterable concatenated array with empty string collection partitions\n            if (options.partitioned === false && options.delimited === false) {\n                if (!Array.isArray(result)) {\n                    throw new Error(\"a nondelimited, non partitioned collection serialization did not return an expected array\");\n                }\n                // Array.concat would probably duplicate memory overhead for copying strings.\n                // Instead copy each individually, and clear old value after each copy.\n                // Hopefully this will allow g.c. to reduce memory pressure, if needed.\n                for (let sidx = 0; sidx < result.length; sidx++) {\n                    reconstruct.push(result[sidx]);\n                    result[sidx] = null;\n                }\n                reconstruct.push(\"\");\n            }\n            else {\n                reconstruct.push(result);\n            }\n        }\n        // Reconstruct / present results according to four combinations : D, DA, NDA, NDAA\n        if (options.partitioned) {\n            // DA : Delimited Array of strings [0] db [1] collection [n] collection { partitioned: true, delimited: true }\n            // useful for simple future adaptations of existing persistence adapters to save collections separately\n            if (options.delimited) {\n                return reconstruct;\n            }\n            // NDAA : Non-Delimited Array with subArrays. db at [0] and collection subarrays at [n] { partitioned: true, delimited : false }\n            // This format might be the most versatile for 'rolling your own' partitioned sync or save.\n            // Memory overhead can be reduced by specifying a specific partition, but at this code path they did not, so its all.\n            else {\n                return reconstruct;\n            }\n        }\n        else {\n            // D : one big Delimited string { partitioned: false, delimited : true }\n            // This is the method Loki will use internally if 'destructured'.\n            // Little memory overhead improvements but does not require multiple asynchronous adapter call scheduling\n            if (options.delimited) {\n                // indicate no more collections\n                reconstruct.push(\"\");\n                return reconstruct.join(options.delimiter);\n            }\n            // NDA : Non-Delimited Array : one iterable array with empty string collection partitions { partitioned: false, delimited: false }\n            // This format might be best candidate for custom synchronous syncs or saves\n            else {\n                // indicate no more collections\n                reconstruct.push(\"\");\n                return reconstruct;\n            }\n        }\n    }\n    /**\n     * Collection level utility method to serialize a collection in a 'destructured' format\n     *\n     * @param {object} options - used to determine output of method\n     * @param {int} options.delimited - whether to return single delimited string or an array\n     * @param {string} options.delimiter - (optional) if delimited, this is delimiter to use\n     * @param {int} options.collectionIndex -  specify which collection to serialize data for\n     *\n     * @returns {string|array} A custom, restructured aggregation of independent serializations for a single collection.\n     */\n    serializeCollection(options = {}) {\n        if (options.delimited === undefined) {\n            options.delimited = true;\n        }\n        if (options.collectionIndex === undefined) {\n            throw new Error(\"serializeCollection called without 'collectionIndex' option\");\n        }\n        const doccount = this._collections[options.collectionIndex].count();\n        let resultlines = [];\n        for (let docidx = 0; docidx < doccount; docidx++) {\n            resultlines.push(JSON.stringify(this._collections[options.collectionIndex]._data[docidx]));\n        }\n        // D and DA\n        if (options.delimited) {\n            // indicate no more documents in collection (via empty delimited string)\n            resultlines.push(\"\");\n            return resultlines.join(options.delimiter);\n        }\n        else {\n            // NDAA and NDA\n            return resultlines;\n        }\n    }\n    /**\n     * Database level destructured JSON deserialization routine to minimize memory overhead.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {string|array} destructuredSource - destructured json or array to deserialize from\n     * @param {object} options - source format options\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to deserialize only a single partition\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {object|array} An object representation of the deserialized database, not yet applied to 'this' db or document array\n     */\n    deserializeDestructured(destructuredSource, options = {}) {\n        if (options.partitioned === undefined) {\n            options.partitioned = false;\n        }\n        if (options.delimited === undefined) {\n            options.delimited = true;\n        }\n        if (options.delimiter === undefined) {\n            options.delimiter = this._destructureDelimiter;\n        }\n        // Partitioned\n        // DA : Delimited Array of strings [0] db [1] collection [n] collection { partitioned: true, delimited: true }\n        // NDAA : Non-Delimited Array with subArrays. db at [0] and collection subarrays at [n] { partitioned: true, delimited : false }\n        // -or- single partition\n        if (options.partitioned) {\n            // handle single partition\n            if (options.partition !== undefined) {\n                // db only\n                if (options.partition === -1) {\n                    return JSON.parse(destructuredSource[0]);\n                }\n                // single collection, return doc array\n                return this.deserializeCollection(destructuredSource[options.partition + 1], options);\n            }\n            // Otherwise we are restoring an entire partitioned db\n            const cdb = JSON.parse(destructuredSource[0]);\n            const collCount = cdb._collections.length;\n            for (let collIndex = 0; collIndex < collCount; collIndex++) {\n                // attach each collection docarray to container collection data, add 1 to collection array index since db is at 0\n                cdb._collections[collIndex]._data = this.deserializeCollection(destructuredSource[collIndex + 1], options);\n            }\n            return cdb;\n        }\n        // Non-Partitioned\n        // D : one big Delimited string { partitioned: false, delimited : true }\n        // NDA : Non-Delimited Array : one iterable array with empty string collection partitions { partitioned: false, delimited: false }\n        let workarray = [];\n        // D\n        if (options.delimited) {\n            workarray = destructuredSource.split(options.delimiter);\n            destructuredSource = null; // lower memory pressure\n            if (workarray.length === 0) {\n                return null;\n            }\n        }\n        // NDA\n        else {\n            workarray = destructuredSource;\n        }\n        // first line is database and collection shells\n        const cdb = JSON.parse(workarray[0]);\n        const collCount = cdb._collections.length;\n        workarray[0] = null;\n        let collIndex = 0;\n        let lineIndex = 1;\n        let done = false;\n        while (!done) {\n            // empty string indicates either end of collection or end of file\n            if (workarray[lineIndex] === \"\") {\n                // if no more collections to load into, we are done\n                if (++collIndex > collCount) {\n                    done = true;\n                }\n            }\n            else {\n                cdb._collections[collIndex]._data.push(JSON.parse(workarray[lineIndex]));\n            }\n            // lower memory pressure and advance iterator\n            workarray[lineIndex++] = null;\n        }\n        return cdb;\n    }\n    /**\n     * Collection level utility function to deserializes a destructured collection.\n     *\n     * @param {string|string[]} destructuredSource - destructured representation of collection to inflate\n     * @param {object} options - used to describe format of destructuredSource input\n     * @param {int} [options.delimited=false] - whether source is delimited string or an array\n     * @param {string} options.delimiter - if delimited, this is delimiter to use (if other than default)\n     *\n     * @returns {Array} an array of documents to attach to collection.data.\n     */\n    deserializeCollection(destructuredSource, options = {}) {\n        if (options.partitioned === undefined) {\n            options.partitioned = false;\n        }\n        if (options.delimited === undefined) {\n            options.delimited = true;\n        }\n        if (options.delimiter === undefined) {\n            options.delimiter = this._destructureDelimiter;\n        }\n        let workarray = [];\n        if (options.delimited) {\n            workarray = destructuredSource.split(options.delimiter);\n            workarray.pop();\n        }\n        else {\n            workarray = destructuredSource;\n        }\n        for (let idx = 0; idx < workarray.length; idx++) {\n            workarray[idx] = JSON.parse(workarray[idx]);\n        }\n        return workarray;\n    }\n    /**\n     * Inflates a loki database from a serialized JSON string\n     *\n     * @param {string} serializedDb - a serialized loki database string\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSON(serializedDb, options) {\n        let dbObject;\n        if (serializedDb.length === 0) {\n            dbObject = {};\n        }\n        else {\n            // using option defined in instantiated db not what was in serialized db\n            switch (this._serializationMethod) {\n                case \"normal\":\n                case \"pretty\":\n                    dbObject = JSON.parse(serializedDb);\n                    break;\n                case \"destructured\":\n                    dbObject = this.deserializeDestructured(serializedDb);\n                    break;\n                default:\n                    dbObject = JSON.parse(serializedDb);\n                    break;\n            }\n        }\n        this.loadJSONObject(dbObject, options);\n    }\n    loadJSONObject(dbObject, options = {}) {\n        const len = dbObject._collections ? dbObject._collections.length : 0;\n        this.filename = dbObject.filename;\n        this._collections = [];\n        for (let i = 0; i < len; ++i) {\n            this._collections.push(_collection__WEBPACK_IMPORTED_MODULE_1__[/* Collection */ \"a\"].fromJSONObject(dbObject._collections[i], options));\n        }\n    }\n    /**\n     * Emits the close event. In autosave scenarios, if the database is dirty, this will save and disable timer.\n     * Does not actually destroy the db.\n     *\n     * @returns {Promise} a Promise that resolves after closing the database succeeded\n     */\n    close() {\n        // for autosave scenarios, we will let close perform final save (if dirty)\n        // For web use, you might call from window.onbeforeunload to shutdown database, saving pending changes\n        if (this._autosave) {\n            return this._autosaveDisable()\n                .then(() => {\n                if (this._autosaveDirty()) {\n                    return this.saveDatabase();\n                }\n                return Promise.resolve();\n            });\n        }\n        return Promise.resolve().then(() => {\n            this.emit(\"close\");\n        });\n    }\n    /**-------------------------+\n     | Changes API               |\n     +--------------------------*/\n    /**\n     * The Changes API enables the tracking the changes occurred in the collections since the beginning of the session,\n     * so it's possible to create a differential dataset for synchronization purposes (possibly to a remote db)\n     */\n    /**\n     * (Changes API) : takes all the changes stored in each\n     * collection and creates a single array for the entire database. If an array of names\n     * of collections is passed then only the included collections will be tracked.\n     *\n     * @param {Array} [arrayOfCollectionNames=] - array of collection names. No arg means all collections are processed.\n     * @returns {Array} array of changes\n     * @see private method _createChange() in Collection\n     */\n    generateChangesNotification(arrayOfCollectionNames) {\n        let changes = [];\n        const selectedCollections = arrayOfCollectionNames\n            || this._collections.map((coll) => coll.name);\n        this._collections.forEach((coll) => {\n            if (selectedCollections.indexOf(coll.name) !== -1) {\n                changes = changes.concat(coll.getChanges());\n            }\n        });\n        return changes;\n    }\n    /**\n     * (Changes API) - stringify changes for network transmission\n     * @returns {string} string representation of the changes\n     */\n    serializeChanges(collectionNamesArray) {\n        return JSON.stringify(this.generateChangesNotification(collectionNamesArray));\n    }\n    /**\n     * (Changes API) : clears all the changes in all collections.\n     */\n    clearChanges() {\n        this._collections.forEach((coll) => {\n            if (coll.flushChanges) {\n                coll.flushChanges();\n            }\n        });\n    }\n    /**\n     * Wait for throttledSaves to complete and invoke your callback when drained or duration is met.\n     *\n     * @param {object} options - configuration options\n     * @param {boolean} [options.recursiveWait=true] - if after queue is drained, another save was kicked off, wait for it\n     * @param {boolean} [options.recursiveWaitLimit=false] - limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDuration=2000] - cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves when save queue is drained, it is passed a sucess parameter value\n     */\n    throttledSaveDrain(options = {}) {\n        const now = (new Date()).getTime();\n        if (!this._throttledSaves) {\n            return Promise.resolve();\n        }\n        if (options.recursiveWait === undefined) {\n            options.recursiveWait = true;\n        }\n        if (options.recursiveWaitLimit === undefined) {\n            options.recursiveWaitLimit = false;\n        }\n        if (options.recursiveWaitLimitDuration === undefined) {\n            options.recursiveWaitLimitDuration = 2000;\n        }\n        if (options.started === undefined) {\n            options.started = new Date();\n        }\n        // if save is pending\n        if (this._throttledSaves && this._throttledSaveRunning !== null) {\n            // if we want to wait until we are in a state where there are no pending saves at all\n            if (options.recursiveWait) {\n                // queue the following meta callback for when it completes\n                return Promise.resolve(Promise.all([this._throttledSaveRunning, this._throttledSavePending])).then(() => {\n                    if (this._throttledSaveRunning !== null || this._throttledSavePending !== null) {\n                        if (options.recursiveWaitLimit && (now - options.started.getTime() > options.recursiveWaitLimitDuration)) {\n                            return Promise.reject({});\n                        }\n                        return this.throttledSaveDrain(options);\n                    }\n                    else {\n                        return Promise.resolve();\n                    }\n                });\n            }\n            // just notify when current queue is depleted\n            else {\n                return Promise.resolve(this._throttledSaveRunning);\n            }\n        }\n        // no save pending, just callback\n        else {\n            return Promise.resolve();\n        }\n    }\n    /**\n     * Internal load logic, decoupled from throttling/contention logic\n     *\n     * @param {object} options - an object containing inflation options for each collection\n     * @param {boolean} ignore_not_found - does not raise an error if database is not found\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    _loadDatabase(options = {}, ignore_not_found = false) {\n        // the persistenceAdapter should be present if all is ok, but check to be sure.\n        if (this._persistenceAdapter === null) {\n            return Promise.reject(new Error(\"persistenceAdapter not configured\"));\n        }\n        return Promise.resolve(this._persistenceAdapter.loadDatabase(this.filename))\n            .then((dbString) => {\n            if (typeof (dbString) === \"string\") {\n                this.loadJSON(dbString, options);\n                this.emit(\"load\", this);\n                // if adapter has returned a js object (other than null or error) attempt to load from JSON object\n            }\n            else if (typeof (dbString) === \"object\" && dbString !== null && !(dbString instanceof Error)) {\n                this.loadJSONObject(dbString, options);\n                this.emit(\"load\", this);\n            }\n            else {\n                throw dbString;\n            }\n        }).catch(e => {\n            if (e instanceof Error) {\n                throw e;\n            }\n            else if (e != null) {\n                throw new TypeError(\"The persistence adapter did not load a serialized DB string or object.\");\n            }\n            else if (!ignore_not_found) {\n                throw new Error(\"Database not found.\");\n            }\n        });\n    }\n    /**\n     * Handles manually loading from an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *    To avoid contention with any throttledSaves, we will drain the save queue first.\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @param {object} [options={}] - if throttling saves and loads, this controls how we drain save queue before loading\n     * @param {boolean} [options.recursiveWait=true] wait recursively until no saves are queued\n     * @param {boolean} [options.recursiveWaitLimit=false] limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDelay=2000] cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    loadDatabase(options = {}) {\n        // if throttling disabled, just call internal\n        if (!this._throttledSaves) {\n            return this._loadDatabase(options);\n        }\n        // try to drain any pending saves in the queue to lock it for loading\n        return this.throttledSaveDrain(options).then(() => {\n            // pause/throttle saving until loading is done\n            this._throttledSaveRunning = this._loadDatabase(options).then(() => {\n                // now that we are finished loading, if no saves were throttled, disable flag\n                this._throttledSaveRunning = null;\n            });\n            return this._throttledSaveRunning;\n        }, () => {\n            throw new Error(\"Unable to pause save throttling long enough to read database\");\n        });\n    }\n    _saveDatabase() {\n        // the persistenceAdapter should be present if all is ok, but check to be sure.\n        if (this._persistenceAdapter === null) {\n            return Promise.reject(new Error(\"persistenceAdapter not configured\"));\n        }\n        // check if the adapter is requesting (and supports) a 'reference' mode export\n        if (this._persistenceAdapter.mode === \"reference\" && typeof this._persistenceAdapter.exportDatabase === \"function\") {\n            // filename may seem redundant but loadDatabase will need to expect this same filename\n            return Promise.resolve(this._persistenceAdapter.exportDatabase(this.filename, this.copy({ removeNonSerializable: true })))\n                .then(() => {\n                this._autosaveClearFlags();\n                this.emit(\"save\");\n            });\n        }\n        // otherwise just pass the serialized database to adapter\n        // persistenceAdapter might be asynchronous, so we must clear `dirty` immediately\n        // or autosave won't work if an update occurs between here and the callback\n        this._autosaveClearFlags();\n        return Promise.resolve(this._persistenceAdapter.saveDatabase(this.filename, this.serialize()))\n            .then(() => {\n            this.emit(\"save\");\n        });\n    }\n    /**\n     * Handles manually saving to an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @returns {Promise} a Promise that resolves after the database is persisted\n     */\n    saveDatabase() {\n        if (!this._throttledSaves) {\n            return this._saveDatabase();\n        }\n        // if the db save is currently running, a new promise for a next db save is created\n        // all calls to save db will get this new promise which will be processed right after\n        // the current db save is finished\n        if (this._throttledSaveRunning !== null && this._throttledSavePending === null) {\n            this._throttledSavePending = Promise.resolve(this._throttledSaveRunning).then(() => {\n                this._throttledSaveRunning = null;\n                this._throttledSavePending = null;\n                return this.saveDatabase();\n            });\n        }\n        if (this._throttledSavePending !== null) {\n            return this._throttledSavePending;\n        }\n        this._throttledSaveRunning = this._saveDatabase().then(() => {\n            this._throttledSaveRunning = null;\n        });\n        return this._throttledSaveRunning;\n    }\n    /**\n     * Handles deleting a database from the underlying storage adapter\n     *\n     * @returns {Promise} a Promise that resolves after the database is deleted\n     */\n    deleteDatabase() {\n        // the persistenceAdapter should be present if all is ok, but check to be sure.\n        if (this._persistenceAdapter === null) {\n            return Promise.reject(new Error(\"persistenceAdapter not configured\"));\n        }\n        return Promise.resolve(this._persistenceAdapter.deleteDatabase(this.filename));\n    }\n    /****************\n     * Autosave API\n     ****************/\n    /**\n     * Check whether any collections are \"dirty\" meaning we need to save the (entire) database\n     * @returns {boolean} - true if database has changed since last autosave, otherwise false\n     */\n    _autosaveDirty() {\n        for (let idx = 0; idx < this._collections.length; idx++) {\n            if (this._collections[idx]._dirty) {\n                return true;\n            }\n        }\n        return false;\n    }\n    /**\n     * Resets dirty flags on all collections.\n     */\n    _autosaveClearFlags() {\n        for (let idx = 0; idx < this._collections.length; idx++) {\n            this._collections[idx]._dirty = false;\n        }\n    }\n    /**\n     * Starts periodically saves to the underlying storage adapter.\n     */\n    _autosaveEnable() {\n        if (!this._autosave || this._autosaveRunning) {\n            return;\n        }\n        this._autosaveRunning = true;\n        const interval = setInterval(() => {\n            if (!this._autosaveRunning) {\n                clearInterval(interval);\n            }\n            else if (this._autosaveDirty()) {\n                this._autosaveHandler = this._autosaveHandler\n                    .then(() => {\n                    return this.saveDatabase();\n                });\n            }\n        }, this._autosaveInterval);\n    }\n    /**\n     * Stops the autosave interval timer.\n     */\n    _autosaveDisable() {\n        this._autosaveRunning = false;\n        return this._autosaveHandler;\n    }\n}\n\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(7)))\n\n/***/ }),\n/* 7 */\n/***/ (function(module, exports) {\n\nvar g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || Function(\"return this\")() || (1, eval)(\"this\");\n} catch (e) {\n\t// This works if the window reference is available\n\tif (typeof window === \"object\") g = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n\n\n/***/ }),\n/* 8 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _loki__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"Loki\", function() { return _loki__WEBPACK_IMPORTED_MODULE_0__[\"a\"]; });\n\n/* harmony import */ var _collection__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"Collection\", function() { return _collection__WEBPACK_IMPORTED_MODULE_1__[\"a\"]; });\n\n\n\n_loki__WEBPACK_IMPORTED_MODULE_0__[/* Loki */ \"a\"][\"Collection\"] = _collection__WEBPACK_IMPORTED_MODULE_1__[/* Collection */ \"a\"];\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (_loki__WEBPACK_IMPORTED_MODULE_0__[/* Loki */ \"a\"]);\n\n\n/***/ })\n/******/ ]);\n});\n//# sourceMappingURL=lokidb.loki.js.map"
  },
  {
    "path": "dist/packages/loki/types/common/plugin.d.ts",
    "content": "/**\n * @hidden\n */\nexport declare const PLUGINS: void;\n"
  },
  {
    "path": "dist/packages/loki/types/common/types.d.ts",
    "content": "/**\n * @hidden\n */\nimport { Loki } from \"../loki/src/loki\";\nexport interface StorageAdapter {\n    loadDatabase(dbname: string): Promise<any>;\n    saveDatabase?(dbname: string, serialization: string): Promise<void>;\n    deleteDatabase?(dbname: string): Promise<void>;\n    mode?: string;\n    exportDatabase?(dbname: string, dbref: Loki): Promise<void>;\n}\nexport declare type Doc<T extends object = object> = T & {\n    $loki: number;\n    meta?: {\n        created: number;\n        revision: number;\n        version: number;\n        updated?: number;\n    };\n};\nexport interface Dict<T> {\n    [index: string]: T;\n    [index: number]: T;\n}\n"
  },
  {
    "path": "dist/packages/loki/types/fs-storage/src/fs_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists using node fs module.\n */\nexport declare class FSStorage implements StorageAdapter {\n    /**\n     * Registers the fs storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the fs storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * Load data from file, will throw an error if the file does not exist\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Save data to file, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Delete the database file, will throw an error if the\n     * file can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\n"
  },
  {
    "path": "dist/packages/loki/types/fs-storage/src/index.d.ts",
    "content": "import { FSStorage } from \"./fs_storage\";\nexport { FSStorage };\nexport default FSStorage;\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search/src/analyzer/analyzer.d.ts",
    "content": "import { CharacterFilter } from \"./character_filter\";\nimport { Tokenizer, whitespaceTokenizer } from \"./tokenizer\";\nimport { lowercaseTokenFilter, TokenFilter } from \"./token_filter\";\n/**\n * A analyzer converts a string into tokens which are added to the inverted index for searching.\n */\nexport interface Analyzer {\n    /**\n     * The character filters of the analyzer.\n     */\n    char_filter?: CharacterFilter[];\n    /**\n     * The tokenizer of the analyzer.\n     */\n    tokenizer: Tokenizer;\n    /**\n     * The token filters of the analyzer.\n     */\n    token_filter?: TokenFilter[];\n}\n/**\n * Analyzes a given string.\n * @param {Analyzer} analyzer - the analyzer\n * @param {string} str - the string\n * @returns {string[]} - the tokens\n */\nexport declare function analyze(analyzer: Analyzer, str: string): string[];\n/**\n * An analyzer with the whitespace tokenizer and the lowercase token filter.\n */\nexport declare class StandardAnalyzer implements Analyzer {\n    tokenizer: typeof whitespaceTokenizer;\n    token_filter: (typeof lowercaseTokenFilter)[];\n}\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search/src/analyzer/character_filter.d.ts",
    "content": "/**\n * A character filter is used to preprocess a string before it is passed to a tokenizer.\n */\nexport declare type CharacterFilter = (value: string) => string;\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search/src/analyzer/token_filter.d.ts",
    "content": "/**\n * A token filter takes tokens from a tokenizer and modify, delete or add tokens.\n */\nexport declare type TokenFilter = (value: string, index: number, array: string[]) => string;\n/**\n * Converts a token to lowercase.\n * @param {string} token - the token\n * @returns {string} - the lowercased token\n */\nexport declare function lowercaseTokenFilter(token: string): string;\n/**\n * Converts a token to uppercase.\n * @param {string} token - the token\n * @returns {string} - the uppercased token\n */\nexport declare function uppercaseTokenFilter(token: string): string;\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search/src/analyzer/tokenizer.d.ts",
    "content": "/**\n * A tokenizer splits a string into individual tokens.\n */\nexport declare type Tokenizer = (value: string) => string[];\n/**\n * Splits a string at whitespace characters into tokens.\n * @param {string} value - the string\n * @returns {string[]} - the tokens\n */\nexport declare function whitespaceTokenizer(value: string): string[];\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search/src/full_text_search.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\nimport { Scorer } from \"./scorer\";\nimport { Analyzer } from \"./analyzer/analyzer\";\nexport declare class FullTextSearch {\n    private _id;\n    private _docs;\n    private _idxSearcher;\n    private _invIdxs;\n    /**\n     * Registers the full-text search as plugin.\n     */\n    static register(): void;\n    /**\n     * Initialize the full-text search for the given fields.\n     * @param {object[]} fieldOptions - the field options\n     * @param {string} fieldOptions.field - the name of the property field\n     * @param {boolean=true} fieldOptions.store - flag to indicate if the full-text search should be stored on serialization or\n     *  rebuild on deserialization\n     * @param {boolean=true} fieldOptions.optimizeChanges - flag to optimize updating and deleting of documents\n     *    (requires more memory but performs faster)\n     * @param {Analyzer} fieldOptions.analyzer - an analyzer for the field\n     * @param {string} [id] - the property name of the document index\n     */\n    constructor(fieldOptions?: FullTextSearch.FieldOptions[], id?: string);\n    addDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    removeDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    updateDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    clear(): void;\n    search(query: Query): Scorer.ScoreResults;\n    toJSON(): FullTextSearch.Serialization;\n    static fromJSONObject(serialized: FullTextSearch.Serialization, analyzers?: Dict<Analyzer>): FullTextSearch;\n}\nexport declare namespace FullTextSearch {\n    interface FieldOptions extends InvertedIndex.FieldOptions {\n        field: string;\n    }\n    interface Serialization {\n        id: string;\n        ii: Dict<InvertedIndex.Serialization>;\n    }\n}\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search/src/fuzzy/automaton.d.ts",
    "content": "/**\n * Transition with dest, min and max.\n * @hidden\n */\nexport declare type Transition = [number, number, number];\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MIN_CODE_POINT = 0;\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MAX_CODE_POINT = 1114111;\n/**\n * From org/apache/lucene/util/automaton/Automaton.java\n * @hidden\n */\nexport declare class Automaton {\n    private _stateTransitions;\n    private _accept;\n    private _nextState;\n    private _currState;\n    private _transitions;\n    constructor();\n    isAccept(n: number): boolean;\n    createState(): number;\n    setAccept(state: number, accept: boolean): void;\n    finishState(): void;\n    private _finishCurrentState();\n    getStartPoints(): number[];\n    step(state: number, label: number): number;\n    getNumStates(): number;\n    addTransition(source: number, dest: number, min: number, max: number): void;\n}\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search/src/fuzzy/lev1t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev1TParametricDescription.java\n * @hidden\n */\nexport declare class Lev1TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search/src/fuzzy/lev2t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev2TParametricDescription.java\n * @hidden\n */\nexport declare class Lev2TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search/src/fuzzy/levenshtein_automata.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java\n * @hidden\n */\nexport declare class LevenshteinAutomata {\n    private _word;\n    private _numRanges;\n    private _rangeLower;\n    private _rangeUpper;\n    private _description;\n    private _alphabet;\n    private _editDistance;\n    constructor(input: number[], editDistance: number);\n    /**\n     * Transforms the NDFA to a DFA.\n     * @returns {Automaton}\n     */\n    toAutomaton(): Automaton;\n    private _getVector(x, pos, end);\n}\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search/src/fuzzy/long.d.ts",
    "content": "/**\n * Class supports 64Bit integer operations.\n * A cut-down version of dcodeIO/long.js.\n * @hidden\n */\nexport declare class Long {\n    private _low;\n    private _high;\n    constructor(low?: number, high?: number);\n    /**\n     * Returns this long with bits arithmetically shifted to the right by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftRight(numBits: number): Long;\n    /**\n     * Returns this long with bits arithmetically shifted to the left by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftLeft(numBits: number): Long;\n    /**\n     * Returns the bitwise AND of this Long and the specified.\n     * @param {Long} other - the other Long\n     * @returns {Long} the long\n     */\n    and(other: Long): Long;\n    /**\n     * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.\n     * @returns {number}\n     */\n    toInt(): number;\n}\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search/src/fuzzy/parametric_description.d.ts",
    "content": "import { Long } from \"./long\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java#ParametricDescription\n * @hidden\n */\nexport declare class ParametricDescription {\n    protected _w: number;\n    private _n;\n    private _minErrors;\n    constructor(w: number, n: number, minErrors: number[]);\n    /**\n     * Return the number of states needed to compute a Levenshtein DFA\n     */\n    size(): number;\n    /**\n     * Returns true if the <code>state</code> in any Levenshtein DFA is an accept state (final state).\n     */\n    isAccept(absState: number): boolean;\n    /**\n     * Returns the position in the input word for a given <code>state</code>.\n     * This is the minimal boundary for the state.\n     */\n    getPosition(absState: number): number;\n    static unpack(data: Long[], index: number, bitsPerValue: number): number;\n}\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search/src/fuzzy/run_automaton.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/RunAutomaton.java\n * @hidden\n */\nexport declare class RunAutomaton {\n    private _points;\n    private _accept;\n    private _transitions;\n    private _classmap;\n    constructor(automaton: Automaton);\n    getCharClass(c: number): number;\n    step(state: number, c: number): number;\n    isAccept(state: number): boolean;\n}\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search/src/index.d.ts",
    "content": "import { FullTextSearch } from \"./full_text_search\";\nimport { analyze, StandardAnalyzer } from \"./analyzer/analyzer\";\nimport { whitespaceTokenizer } from \"./analyzer/tokenizer\";\nimport { lowercaseTokenFilter, uppercaseTokenFilter } from \"./analyzer/token_filter\";\nexport { FullTextSearch, analyze, StandardAnalyzer, whitespaceTokenizer, lowercaseTokenFilter, uppercaseTokenFilter };\nexport default FullTextSearch;\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search/src/index_searcher.d.ts",
    "content": "import { Scorer } from \"./scorer\";\nimport { InvertedIndex } from \"./inverted_index\";\nimport { Query } from \"./query_types\";\nimport { Dict } from \"../../common/types\";\n/**\n * @hidden\n */\nexport declare class IndexSearcher {\n    private _invIdxs;\n    private _docs;\n    private _scorer;\n    /**\n     * Constructs an index searcher.\n     * @param {Dict<InvertedIndex>} invIdxs - the inverted indexes\n     * @param {Set<number>} docs - the ids of the documents\n     */\n    constructor(invIdxs: Dict<InvertedIndex>, docs: Set<InvertedIndex.DocumentIndex>);\n    search(query: Query): Scorer.ScoreResults;\n    setDirty(): void;\n    private _recursive(query, doScoring);\n    private _getUnique(queries, doScoring, queryResults);\n    private _getAll(queries, doScoring, queryResults?);\n}\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search/src/inverted_index.d.ts",
    "content": "import { Analyzer } from \"./analyzer/analyzer\";\n/**\n * Converts a string into an array of code points.\n * @param str - the string\n * @returns {number[]} to code points\n * @hidden\n */\nexport declare function toCodePoints(str: string): number[];\n/**\n * Inverted index class handles featured text search for specific document fields.\n * @hidden\n */\nexport declare class InvertedIndex {\n    analyzer: Analyzer;\n    docCount: number;\n    docStore: Map<InvertedIndex.DocumentIndex, InvertedIndex.DocStore>;\n    totalFieldLength: number;\n    root: InvertedIndex.Index;\n    private _store;\n    private _optimizeChanges;\n    /**\n     * @param {boolean} [options.store=true] - inverted index will be stored at serialization rather than rebuilt on load\n     * @param {boolean} [options.optimizeChanges=true] - flag to store additional metadata inside the index for better\n     *  performance if an existing field is updated or removed\n     * @param {Analyzer} [options.analyzer=] - the analyzer of this inverted index\n     */\n    constructor(options?: InvertedIndex.FieldOptions);\n    /**\n     * Adds defined fields of a document to the inverted index.\n     * @param {string} field - the field to add\n     * @param {number} docId - the doc id of the field\n     */\n    insert(field: string, docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Removes all relevant terms of a document from the inverted index.\n     * @param {number} docId - the document.\n     */\n    remove(docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Gets the term index of a term.\n     * @param {string} term - the term\n     * @param {object} root - the term index to start from\n     * @param {number} start - the position of the term string to start from\n     * @return {object} - The term index or null if the term is not in the term tree.\n     */\n    static getTermIndex(term: number[], root: InvertedIndex.Index, start?: number): InvertedIndex.Index;\n    /**\n     * Extends a term index to all available term leafs.\n     * @param {object} idx - the term index to start from\n     * @param {number[]} [term=[]] - the current term\n     * @param {Array} termIndices - all extended indices with their term\n     * @returns {Array} - Array with term indices and extension\n     */\n    static extendTermIndex(idx: InvertedIndex.Index, term?: number[], termIndices?: InvertedIndex.IndexTerm[]): InvertedIndex.IndexTerm[];\n    /**\n     * Serialize the inverted index.\n     * @returns {{docStore: *, _fields: *, index: *}}\n     */\n    toJSON(): InvertedIndex.Serialization;\n    /**\n     * Deserialize the inverted index.\n     * @param {{docStore: *, _fields: *, index: *}} serialized - The serialized inverted index.\n     * @param {Analyzer} analyzer[undefined] - an analyzer\n     */\n    static fromJSONObject(serialized: InvertedIndex.Serialization, analyzer?: Analyzer): InvertedIndex;\n    private static _serializeIndex(idx);\n    private static _deserializeIndex(serialized);\n    /**\n     * Set parent of to each index and regenerate the indexRef.\n     * @param {Index} index - the index\n     * @param {Index} parent - the parent\n     */\n    private _regenerate(index, parent);\n    /**\n     * Iterate over the whole inverted index and remove the document.\n     * Delete branch if not needed anymore.\n     * Function is needed if index is used without optimization.\n     * @param {Index} idx - the index\n     * @param {number} docId - the doc id\n     * @returns {boolean} true if index is empty\n     */\n    private _remove(idx, docId);\n}\nexport declare namespace InvertedIndex {\n    interface FieldOptions {\n        store?: boolean;\n        optimizeChanges?: boolean;\n        analyzer?: Analyzer;\n    }\n    type Index = Map<number, any> & {\n        dc?: Map<DocumentIndex, number>;\n        df?: number;\n        pa?: Index;\n    };\n    type IndexTerm = {\n        index: Index;\n        term: number[];\n    };\n    interface SerializedIndex {\n        d?: {\n            df: number;\n            dc: [DocumentIndex, number][];\n        };\n        k?: number[];\n        v?: SerializedIndex[];\n    }\n    type Serialization = SpareSerialization | FullSerialization;\n    type SpareSerialization = {\n        _store: false;\n        _optimizeChanges: boolean;\n    };\n    type FullSerialization = {\n        _store: true;\n        _optimizeChanges: boolean;\n        docCount: number;\n        docStore: [DocumentIndex, DocStore][];\n        totalFieldLength: number;\n        root: SerializedIndex;\n    };\n    interface DocStore {\n        fieldLength?: number;\n        indexRef?: Index[];\n    }\n    type DocumentIndex = number | string;\n}\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search/src/query_types.d.ts",
    "content": "/**\n * Base query to enable boost to a query type.\n */\nexport interface BaseQuery<Type> {\n    type: Type;\n    boost?: number;\n}\n/**\n * A query which finds documents where a document field contains a term.\n */\nexport interface TermQuery extends BaseQuery<\"term\"> {\n    field: string;\n    value: string;\n}\n/**\n * A query which finds documents where a document field contains any of the terms.\n */\nexport interface TermsQuery extends BaseQuery<\"terms\"> {\n    field: string;\n    value: string[];\n}\n/**\n * A query which finds documents where the wildcard term can be applied at an existing document field term.\n */\nexport interface WildcardQuery extends BaseQuery<\"wildcard\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which finds documents where the fuzzy term can be transformed into an existing document field term within a\n * given edit distance.\n */\nexport interface FuzzyQuery extends BaseQuery<\"fuzzy\"> {\n    field: string;\n    value: string;\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query which matches documents containing the prefix of a term inside a field.\n */\nexport interface PrefixQuery extends BaseQuery<\"prefix\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which matches all documents with a given field.\n */\nexport interface ExistsQuery extends BaseQuery<\"exists\"> {\n    field: string;\n}\n/**\n * A query which tokenizes the given text into tokens and performs a sub query for each token. The results are combined\n * using a boolean operator.\n */\nexport interface MatchQuery extends BaseQuery<\"match\"> {\n    field: string;\n    value: string;\n    minimum_should_match?: number | string;\n    operator?: \"and\" | \"or\";\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query that matches all documents and giving them a constant score equal to the query boost.\n*/\nexport interface MatchQueryAll extends BaseQuery<\"match_all\"> {\n}\n/**\n * A query that wraps sub queries and returns a constant score equal to the query boost for every document in the filter.\n */\nexport interface ConstantScoreQuery extends BaseQuery<\"constant_score\"> {\n    filter: QueryTypes[];\n}\n/**\n * A query that matches documents matching boolean combinations of sub queries.\n */\nexport interface BoolQuery extends BaseQuery<\"bool\"> {\n    must?: QueryTypes[];\n    filter?: QueryTypes[];\n    should?: QueryTypes[];\n    not?: QueryTypes[];\n    minimum_should_match?: number | string;\n}\n/**\n * Union type of possible query types.\n */\nexport declare type QueryTypes = BoolQuery | ConstantScoreQuery | TermQuery | TermsQuery | WildcardQuery | FuzzyQuery | MatchQuery | MatchQueryAll | PrefixQuery | ExistsQuery;\n/**\n * The main query with the actually full-text search query and the scoring parameters.\n */\nexport interface Query {\n    query: QueryTypes;\n    calculate_scoring?: boolean;\n    explain?: boolean;\n    bm25?: {\n        k1: number;\n        b: number;\n    };\n}\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search/src/scorer.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\n/**\n * @hidden\n */\nexport declare class Scorer {\n    private _invIdxs;\n    private _cache;\n    constructor(invIdxs: Dict<InvertedIndex>);\n    setDirty(): void;\n    score(fieldName: string, boost: number, termIdx: InvertedIndex.Index, doScoring: boolean | null, queryResults: Scorer.QueryResults, term: number[], df?: number): void;\n    scoreConstant(boost: number, docId: InvertedIndex.DocumentIndex, queryResults: Scorer.QueryResults): Scorer.QueryResults;\n    finalScore(query: Query, queryResults: Scorer.QueryResults): Scorer.ScoreResults;\n    private static _calculateFieldLength(fieldLength);\n    private _getCache(fieldName);\n    /**\n     * Returns the idf by either calculate it or use a cached one.\n     * @param {string} fieldName - the name of the field\n     * @param {number} docFreq - the doc frequency of the term\n     * @returns {number} the idf\n     * @private\n     */\n    private _idf(fieldName, docFreq);\n    private _avgFieldLength(fieldName);\n}\nexport declare namespace Scorer {\n    interface IDFCache {\n        idfs: Dict<number>;\n        avgFieldLength: number;\n    }\n    interface QueryResult {\n        tf?: number;\n        idf?: number;\n        boost: number;\n        fieldName?: string;\n        term?: number[];\n    }\n    type QueryResults = Map<InvertedIndex.DocumentIndex, QueryResult[]>;\n    interface BM25Explanation {\n        boost: number;\n        score: number;\n        docID: number;\n        fieldName: string;\n        index: string;\n        idf: number;\n        tfNorm: number;\n        tf: number;\n        fieldLength: number;\n        avgFieldLength: number;\n    }\n    interface ConstantExplanation {\n        boost: number;\n        score: number;\n    }\n    type ScoreExplanation = BM25Explanation | ConstantExplanation;\n    type ScoreResult = {\n        score: number;\n        explanation?: ScoreExplanation[];\n    };\n    type ScoreResults = Dict<ScoreResult>;\n}\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search-language/src/index.d.ts",
    "content": "export { generateStopWordFilter, generateTrimmer, Among, SnowballProgram } from \"./language\";\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search-language/src/language.d.ts",
    "content": "export declare function generateTrimmer(wordCharacters: string): (token: string) => string;\nexport declare function generateStopWordFilter(stopWords: string[]): (token: string) => string;\nexport declare class Among {\n    s_size: number;\n    s: number[];\n    substring_i: number;\n    result: number;\n    method: any;\n    constructor(s: string, substring_i: number, result: number, method?: any);\n}\nexport declare class SnowballProgram {\n    current: string;\n    bra: number;\n    ket: number;\n    limit: number;\n    cursor: number;\n    limit_backward: number;\n    constructor();\n    setCurrent(word: string): void;\n    getCurrent(): string;\n    in_grouping(s: number[], min: number, max: number): boolean;\n    in_grouping_b(s: number[], min: number, max: number): boolean;\n    out_grouping(s: number[], min: number, max: number): boolean;\n    out_grouping_b(s: number[], min: number, max: number): boolean;\n    eq_s(s_size: number, s: string): boolean;\n    eq_s_b(s_size: number, s: string): boolean;\n    find_among(v: Among[], v_size: number): number;\n    find_among_b(v: Among[], v_size: number): number;\n    replace_s(c_bra: number, c_ket: number, s: string): number;\n    slice_check(): void;\n    slice_from(s: string): void;\n    slice_del(): void;\n    insert(c_bra: number, c_ket: number, s: string): void;\n    slice_to(): string;\n    eq_v_b(s: string): boolean;\n}\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search-language-de/src/german_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class GermanAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search-language-de/src/index.d.ts",
    "content": "import { GermanAnalyzer } from \"./german_analyzer\";\nexport { GermanAnalyzer };\nexport default GermanAnalyzer;\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search-language-en/src/english_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class EnglishAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/loki/types/full-text-search-language-en/src/index.d.ts",
    "content": "import { EnglishAnalyzer } from \"./english_analyzer\";\nexport { EnglishAnalyzer };\nexport default EnglishAnalyzer;\n"
  },
  {
    "path": "dist/packages/loki/types/indexed-storage/src/index.d.ts",
    "content": "import { IndexedStorage } from \"./indexed_storage\";\nexport { IndexedStorage };\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/loki/types/indexed-storage/src/indexed_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * Loki persistence adapter class for indexedDb.\n *     This class fulfills abstract adapter interface which can be applied to other storage methods.\n *     Utilizes the included LokiCatalog app/key/value database for actual database persistence.\n *     IndexedDb storage is provided per-domain, so we implement app/key/value database to\n *     allow separate contexts for separate apps within a domain.\n */\nexport declare class IndexedStorage implements StorageAdapter {\n    private _appname;\n    private catalog;\n    /**\n     * Registers the indexed storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the indexed storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {string} [appname=loki] - Application name context can be used to distinguish subdomains, \"loki\" by default\n     */\n    constructor(appname?: string);\n    /**\n     * Retrieves a serialized db string from the catalog.\n     *\n     * @example\n     * // LOAD\n     * var idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * var db = new loki(\"test\", { adapter: idbAdapter });\n     *   db.base(function(result) {\n       *   console.log(\"done\");\n       * });\n     *\n     * @param {string} dbname - the name of the database to retrieve.\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<{}>;\n    /**\n     * Saves a serialized db to the catalog.\n     *\n     * @example\n     * // SAVE : will save App/Key/Val as \"finance\"/\"test\"/{serializedDb}\n     * let idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * let db = new loki(\"test\", { adapter: idbAdapter });\n     * let coll = db.addCollection(\"testColl\");\n     * coll.insert({test: \"val\"});\n     * db.saveDatabase();  // could pass callback if needed for async complete\n     *\n     * @param {string} dbname - the name to give the serialized database within the catalog.\n     * @param {string} dbstring - the serialized db string to save.\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a serialized db from the catalog.\n     *\n     * @example\n     * // DELETE DATABASE\n     * // delete \"finance\"/\"test\" value from catalog\n     * idbAdapter.deleteDatabase(\"test\", function {\n       *   // database deleted\n       * });\n     *\n     * @param {string} dbname - the name of the database to delete from the catalog.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n    /**\n     * Removes all database partitions and pages with the base filename passed in.\n     * This utility method does not (yet) guarantee async deletions will be completed before returning\n     *\n     * @param {string} dbname - the base filename which container, partitions, or pages are derived\n     */\n    deleteDatabasePartitions(dbname: string): void;\n    /**\n     * Retrieves object array of catalog entries for current app.\n     *\n     * @example\n     * idbAdapter.getDatabaseList(function(result) {\n       *   // result is array of string names for that appcontext (\"finance\")\n       *   result.forEach(function(str) {\n       *     console.log(str);\n       *   });\n       * });\n     *\n     * @param {function} callback - should accept array of database names in the catalog for current app.\n     */\n    getDatabaseList(callback: (names: string[]) => void): void;\n    /**\n     * Allows retrieval of list of all keys in catalog along with size\n     * @param {function} callback - (Optional) callback to accept result array.\n     */\n    getCatalogSummary(callback: (entry: Entry[]) => void): void;\n}\nexport interface Entry {\n    app: string;\n    key: string;\n    size: number;\n}\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/loki/types/local-storage/src/index.d.ts",
    "content": "import { LocalStorage } from \"./local_storage\";\nexport { LocalStorage };\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/loki/types/local-storage/src/local_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists to web browser's local storage object\n * @constructor LocalStorageAdapter\n */\nexport declare class LocalStorage implements StorageAdapter {\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * loadDatabase() - Load data from localstorage\n     * @param {string} dbname - the name of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * saveDatabase() - save data to localstorage, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was saved\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * deleteDatabase() - delete the database from localstorage, will throw an error if it\n     * can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/loki/types/loki/src/avl_index.d.ts",
    "content": "import { IRangedIndex, IRangedIndexRequest } from \"./ranged_indexes\";\nimport { ILokiComparer } from \"./comparators\";\n/**\n * Treenode type for binary search tree (BST) implementation.\n *\n * To support duplicates, we may need to either repurpose parent to\n * point to 'elder' sibling or add a siblingId to point to owner of\n * node represented in tree.\n */\nexport declare type TreeNode<T> = {\n    id: number;\n    value: T;\n    parent: number | null;\n    balance: number;\n    height: number;\n    left: number | null;\n    right: number | null;\n    siblings: number[];\n};\nexport interface ITreeNodeHash<T> {\n    [id: number]: TreeNode<T>;\n}\n/**\n * LokiDB AVL Balanced Binary Tree Index implementation.\n * To support duplicates, we use siblings (array) in tree nodes.\n * Basic AVL components guided by William Fiset tutorials at :\n * https://github.com/williamfiset/data-structures/blob/master/com/williamfiset/datastructures/balancedtree/AVLTreeRecursive.java\n * https://www.youtube.com/watch?v=g4y2h70D6Nk&list=PLDV1Zeh2NRsD06x59fxczdWLhDDszUHKt\n */\nexport declare class AvlTreeIndex<T> implements IRangedIndex<T> {\n    name: string;\n    comparator: ILokiComparer<T>;\n    nodes: ITreeNodeHash<T>;\n    apex: number | null;\n    /**\n     * Initializes index with property name and a comparer function.\n     */\n    constructor(name: string, comparator: ILokiComparer<T>);\n    backup(): AvlTreeIndex<T>;\n    restore(tree: AvlTreeIndex<T>): void;\n    /**\n     * Used for inserting a new value into the BinaryTreeIndex\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val Value to be indexed and inserted into binary tree\n     */\n    insert(id: number, val: T): void;\n    /**\n     * Recursively inserts a treenode and re-balances if needed.\n     * @param current\n     * @param node\n     */\n    insertNode(current: TreeNode<T>, node: TreeNode<T>): number;\n    /**\n     * Updates height and balance (calculation) for tree node\n     * @param node\n     */\n    private updateBalance(node);\n    /**\n     * Balance the 'double left-heavy' condition\n     * @param node\n     */\n    private leftLeftCase(node);\n    /**\n     * Balance the '(parent) left heavy, (child) right heavy' condition\n     * @param node\n     */\n    private leftRightCase(node);\n    /**\n     * Balance the 'double right-heavy' condition\n     * @param node\n     */\n    private rightRightCase(node);\n    /**\n     * Balance the '(parent) right heavy, (child) left heavy' condition\n     * @param node\n     */\n    private rightLeftCase(node);\n    /**\n     * Left rotation of node. Swaps right child into current location.\n     * @param node\n     */\n    private rotateLeft(node);\n    /**\n     * Right rotation of node. Swaps left child into current location.\n     * @param node\n     */\n    private rotateRight(node);\n    /**\n     * Diagnostic method for examining tree contents and structure\n     * @param node\n     */\n    getValuesAsTree(node?: TreeNode<T>): any;\n    /**\n     * Updates a value, possibly relocating it, within binary tree\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val New value to be indexed within binary tree\n     */\n    update(id: number, val: T): void;\n    /**\n     * Removes a value from the binary tree index\n     * @param id\n     */\n    remove(id: number): void;\n    /**\n     * Recursive node removal and rebalancer\n     * @param node\n     * @param val\n     */\n    private removeNode(node, id);\n    /**\n     * Utility method for updating a parent's child link when it changes\n     * @param parentId\n     * @param oldChildId\n     * @param newChildId\n     */\n    private updateChildLink(parentId, oldChildId, newChildId);\n    /**\n     * When removing a parent with only child, this does simple remap of child to grandParent.\n     * @param grandParent New parent of 'child'.\n     * @param parent Node being removed.\n     * @param child Node to reparent to grandParent.\n     */\n    private promoteChild(parent, child);\n    /**\n     * Finds a successor to a node and replaces that node with it.\n     * @param node\n     */\n    private promoteSuccessor(node);\n    /**\n     * Utility method for finding In-Order predecessor to the provided node\n     * @param node Parent node to find leaf node of greatest 'value'\n    */\n    private findGreaterLeaf(node);\n    /**\n     * Utility method for finding In-Order successor to the provided node\n     * @param node Parent Node to find leaf node of least 'value'\n     */\n    private findLesserLeaf(node);\n    /**\n     *  Interface method to support ranged queries.  Results sorted by index property.\n     * @param range Options for ranged request.\n     */\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    /**\n     * Implements ranged request operations.\n     * @param node\n     * @param range\n     */\n    private collateRequest(node, range);\n    /**\n     * Used on a branch node to return an array of id within that branch, sorted by their value\n     * @param node\n     */\n    private collateIds(node);\n    /**\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    /**\n     * Inline/Non-recusive 'single value' ($eq) lookup.\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    private locate(node, val);\n    /**\n     * Index integrity check (IRangedIndex interface function)\n     */\n    validateIndex(): boolean;\n    /**\n     * Recursive Node validation routine\n     * @param node\n     */\n    private validateNode(node);\n}\n"
  },
  {
    "path": "dist/packages/loki/types/loki/src/clone.d.ts",
    "content": "export declare type CloneMethod = \"parse-stringify\" | \"deep\" | \"shallow\" | \"shallow-recurse\";\n/**\n * @hidden\n */\nexport declare function clone<T>(data: T, method?: CloneMethod): T;\n"
  },
  {
    "path": "dist/packages/loki/types/loki/src/collection.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { UniqueIndex } from \"./unique_index\";\nimport { ResultSet } from \"./result_set\";\nimport { DynamicView } from \"./dynamic_view\";\nimport { IRangedIndex } from \"./ranged_indexes\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc, Dict } from \"../../common/types\";\nimport { FullTextSearch } from \"../../full-text-search/src/full_text_search\";\nimport { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\n/**\n * Collection class that handles documents of same type\n * @extends LokiEventEmitter\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class Collection<TData extends object = object, TNested extends object = object, T extends TData & TNested = TData & TNested> extends LokiEventEmitter {\n    name: string;\n    _data: Doc<T>[];\n    private _idIndex;\n    _rangedIndexes: {\n        [P in keyof T]?: Collection.RangedIndexMeta;\n    };\n    _lokimap: {\n        [$loki: number]: Doc<T>;\n    };\n    _unindexedSortComparator: string;\n    _defaultLokiOperatorPackage: string;\n    /**\n     * Unique constraints contain duplicate object references, so they are not persisted.\n     * We will keep track of properties which have unique constraints applied here, and regenerate on load.\n     */\n    _constraints: {\n        unique: {\n            [P in keyof T]?: UniqueIndex;\n        };\n    };\n    /**\n     * Transforms will be used to store frequently used query chains as a series of steps which itself can be stored along\n     * with the database.\n     */\n    _transforms: Dict<Collection.Transform<T>[]>;\n    /**\n     * In autosave scenarios we will use collection level dirty flags to determine whether save is needed.\n     * currently, if any collection is dirty we will autosave the whole database if autosave is configured.\n     * Defaulting to true since this is called from addCollection and adding a collection should trigger save.\n     */\n    _dirty: boolean;\n    private _cached;\n    /**\n     * Is collection transactional.\n     */\n    private _transactional;\n    /**\n     * Options to clone objects when inserting them.\n     */\n    _cloneObjects: boolean;\n    /**\n     * Default clone method (if enabled) is parse-stringify.\n     */\n    _cloneMethod: CloneMethod;\n    /**\n     * If set to true we will not maintain a meta property for a document.\n     */\n    private _disableMeta;\n    /**\n     * Disable track changes.\n     */\n    private _disableChangesApi;\n    /**\n     * Disable delta update object style on changes.\n     */\n    _disableDeltaChangesApi: boolean;\n    /**\n     * By default, if you insert a document with a Date value for an indexed property, we will convert that value to number.\n     */\n    private _serializableIndexes;\n    /**\n     * Name of path of used nested properties.\n     */\n    private _nestedProperties;\n    /**\n     * Option to activate a cleaner daemon - clears \"aged\" documents at set intervals.\n     */\n    _ttl: Collection.TTL;\n    private _maxId;\n    private _dynamicViews;\n    /**\n     * Changes are tracked by collection and aggregated by the db.\n     */\n    private _changes;\n    /**\n     * stages: a map of uniquely identified 'stages', which hold copies of objects to be\n     * manipulated without affecting the data in the original collection\n     */\n    private _stages;\n    private _commitLog;\n    _fullTextSearch: FullTextSearch;\n    /**\n     * @param {string} name - collection name\n     * @param {(object)} [options={}] - a configuration object\n     * @param {string[]} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {string[]} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {RangedIndexOptions} [options.rangedIndexes] - configuration object for ranged indexes\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are invoked asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes API\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {boolean} [options.serializableIndexes=true] - converts date values on binary indexed property values are serializable\n     * @param {string} [options.cloneMethod=\"deep\"] - the clone method\n     * @param {number} [options.transactional=false] - ?\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale.\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @param {string} [options.unindexedSortComparator=\"js\"] \"js\", \"abstract\", \"abstract-date\", \"loki\" or other registered comparator name\n     * @param {string} [options.defaultLokiOperatorPackage=\"js\"] \"js\", \"loki\", \"comparator\" (or user defined) query ops package\n     * @param {FullTextSearch.FieldOptions} [options.fullTextSearch=] - the full-text search options\n     * @see {@link Loki#addCollection} for normal creation of collections\n     */\n    constructor(name: string, options?: Collection.Options<TData, TNested>);\n    toJSON(): Collection.Serialized;\n    static fromJSONObject(obj: Collection.Serialized, options?: Collection.DeserializeOptions): Collection<any, object, any>;\n    /**\n     * Adds a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {array} transform - an array of transformation 'step' objects to save into the collection\n     */\n    addTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Retrieves a named transform from the collection.\n     * @param {string} name - name of the transform to lookup.\n     */\n    getTransform(name: string): Collection.Transform<T>[];\n    /**\n     * Updates a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {object} transform - a transformation object to save into collection\n     */\n    setTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Removes a named collection transform from the collection\n     * @param {string} name - name of collection transform to remove\n     */\n    removeTransform(name: string): void;\n    private setTTL(age, interval);\n    /**\n     * Create a row filter that covers all documents in the collection.\n     */\n    _prepareFullDocIndex(): number[];\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field\n     * @param indexTypeName\n     * @param comparatorName\n     */\n    ensureIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field Property to create an index on (need to look into contraining on keyof T)\n     * @param indexTypeName Name of IndexType factory within (global?) hashmap to create IRangedIndex from\n     * @param comparatorName Name of Comparator within (global?) hashmap\n     */\n    ensureRangedIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    ensureUniqueIndex(field: keyof T): UniqueIndex;\n    /**\n     * Quickly determine number of documents in collection (or query)\n     * @param {object} query - (optional) query object to count results of\n     * @returns {number} number of documents in the collection\n     */\n    count(query?: ResultSet.Query<Doc<T>>): number;\n    /**\n     * Rebuild idIndex\n     */\n    private _ensureId();\n    /**\n     * Add a dynamic view to the collection\n     * @param {string} name - name of dynamic view to add\n     * @param {object} options - (optional) options to configure dynamic view with\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=SortPriority.PASSIVE] - the sort priority\n     * @param {number} options.minRebuildInterval - minimum rebuild interval (need clarification to docs here)\n     * @returns {DynamicView} reference to the dynamic view added\n     **/\n    addDynamicView(name: string, options?: DynamicView.Options): DynamicView<T>;\n    /**\n     * Remove a dynamic view from the collection\n     * @param {string} name - name of dynamic view to remove\n     **/\n    removeDynamicView(name: string): void;\n    /**\n     * Look up dynamic view reference from within the collection\n     * @param {string} name - name of dynamic view to retrieve reference of\n     * @returns {DynamicView} A reference to the dynamic view with that name\n     **/\n    getDynamicView(name: string): DynamicView<T>;\n    /**\n     * Applies a 'mongo-like' find query object and passes all results to an update function.\n     * @param {object} filterObject - the 'mongo-like' query object\n     * @param {function} updateFunction - the update function\n     */\n    findAndUpdate(filterObject: ResultSet.Query<Doc<T>>, updateFunction: (obj: Doc<T>) => any): void;\n    /**\n     * Applies a 'mongo-like' find query object removes all documents which match that filter.\n     * @param {object} filterObject - 'mongo-like' query object\n     */\n    findAndRemove(filterObject: ResultSet.Query<Doc<T>>): void;\n    /**\n     * Adds object(s) to collection, ensure object(s) have meta properties, clone it if necessary, etc.\n     * @param {(object|array)} doc - the document (or array of documents) to be inserted\n     * @returns {(object|array)} document or documents inserted\n     */\n    insert(doc: TData): Doc<T>;\n    insert(doc: TData[]): Doc<T>[];\n    /**\n     * Adds a single object, ensures it has meta properties, clone it if necessary, etc.\n     * @param {object} doc - the document to be inserted\n     * @param {boolean} bulkInsert - quiet pre-insert and insert event emits\n     * @returns {object} document or 'undefined' if there was a problem inserting it\n     */\n    insertOne(doc: TData, bulkInsert?: boolean): Doc<T>;\n    /**\n     * Refers nested properties of an object to the root of it.\n     * @param {T} data - the object\n     * @returns {T & TNested} the object with nested properties\n     * @hidden\n     */\n    _defineNestedProperties<U extends TData>(data: U): U & TNested;\n    /**\n     * Empties the collection.\n     * @param {boolean} [removeIndices=false] - remove indices\n     */\n    clear({removeIndices: removeIndices}?: {\n        removeIndices?: boolean;\n    }): void;\n    /**\n     * Updates an object and notifies collection that the document has changed.\n     * @param {object} doc - document to update within the collection\n     */\n    update(doc: Doc<T> | Doc<T>[]): void;\n    /**\n     * Add object to collection\n     */\n    private _add(obj);\n    /**\n     * Applies a filter function and passes all results to an update function.\n     * @param {function} filterFunction - the filter function\n     * @param {function} updateFunction - the update function\n     */\n    updateWhere(filterFunction: (obj: Doc<T>) => boolean, updateFunction: (obj: Doc<T>) => Doc<T>): void;\n    /**\n     * Remove all documents matching supplied filter function.\n     * @param {function} filterFunction - the filter function\n     */\n    removeWhere(filterFunction: (obj: Doc<T>) => boolean): void;\n    removeDataOnly(): void;\n    /**\n     * Remove a document from the collection\n     * @param {number|object} doc - document to remove from collection\n     */\n    remove(doc: number | Doc<T> | Doc<T>[]): void;\n    /**\n     * Returns all changes.\n     * @returns {Collection.Change[]}\n     */\n    getChanges(): Collection.Change[];\n    /**\n     * Enables/disables changes api.\n     * @param {boolean} disableChangesApi\n     * @param {boolean} disableDeltaChangesApi\n     */\n    setChangesApi(disableChangesApi: boolean, disableDeltaChangesApi?: boolean): void;\n    /**\n     * Clears all the changes.\n     */\n    flushChanges(): void;\n    private _getObjectDelta(oldObject, newObject);\n    /**\n     * Compare changed object (which is a forced clone) with existing object and return the delta\n     */\n    private _getChangeDelta(obj, old);\n    /**\n     * Creates a clone of the current status of an object and associates operation and collection name,\n     * so the parent db can aggregate and generate a changes object for the entire db\n     */\n    private _createChange(name, op, obj, old?);\n    private _createInsertChange(obj);\n    private _createUpdateChange(obj, old);\n    private _insertMetaWithChange(obj);\n    private _updateMetaWithChange(obj, old);\n    private _insertMeta(obj);\n    private _updateMeta(obj);\n    /**\n     * Get by Id - faster than other methods because of the searching algorithm\n     * @param {int} id - $loki id of document you want to retrieve\n     * @param {boolean} returnPosition - if 'true' we will return [object, position]\n     * @returns {(object|array|null)} Object reference if document was found, null if not,\n     *     or an array if 'returnPosition' was passed.\n     */\n    get(id: number): Doc<T>;\n    get(id: number, returnPosition: boolean): Doc<T> | [Doc<T>, number];\n    /**\n     * Retrieve doc by Unique index\n     * @param {string} field - name of uniquely indexed property to use when doing lookup\n     * @param {any} value - unique value to search for\n     * @returns {object} document matching the value passed\n     */\n    by(field: keyof T, value: any): Doc<T>;\n    /**\n     * Find one object by index property, by property equal to value\n     * @param {object} query - query object used to perform search with\n     * @returns {(object|null)} First matching document, or null if none\n     */\n    findOne(query: ResultSet.Query<Doc<T>>): Doc<T>;\n    /**\n     * Chain method, used for beginning a series of chained find() and/or view() operations\n     * on a collection.\n     *\n     * @param {array} transform - Ordered array of transform step objects similar to chain\n     * @param {object} parameters - Object containing properties representing parameters to substitute\n     * @returns {ResultSet} (this) ResultSet, or data array if any map or join functions where called\n     */\n    chain(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Find method, api is similar to mongodb.\n     * for more complex queries use [chain()]{@link Collection#chain} or [where()]{@link Collection#where}.\n     * @example {@tutorial Query Examples}\n     * @param {object} query - 'mongo-like' query object\n     * @returns {array} Array of matching documents\n     */\n    find(query?: ResultSet.Query<Doc<T>>): Doc<T>[];\n    /**\n     * Find object by unindexed field by property equal to value,\n     * simply iterates and returns the first element matching the query\n     */\n    findOneUnindexed(prop: string, value: any): Doc<T>;\n    /**\n     * Transaction methods\n     */\n    /**\n     * start the transation\n     */\n    startTransaction(): void;\n    /**\n     * Commit the transaction.\n     */\n    commit(): void;\n    /**\n     * Rollback the transaction.\n     */\n    rollback(): void;\n    /**\n     * Query the collection by supplying a javascript filter function.\n     * @example\n     * let results = coll.where(function(obj) {\n       *   return obj.legs === 8;\n       * });\n     * @param {function} fun - filter function to run against all collection docs\n     * @returns {array} all documents which pass your filter function\n     */\n    where(fun: (obj: Doc<T>) => boolean): Doc<T>[];\n    /**\n     * Map Reduce operation\n     * @param {function} mapFunction - function to use as map function\n     * @param {function} reduceFunction - function to use as reduce function\n     * @returns {data} The result of your mapReduce operation\n     */\n    mapReduce<U1, U2>(mapFunction: (value: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Join two collections on specified properties\n     * @param {array} joinData - array of documents to 'join' to this collection\n     * @param {string} leftJoinProp - property name in collection\n     * @param {string} rightJoinProp - property name in joinData\n     * @param {function} mapFun - (Optional) map function to use\n     * @param dataOptions - options to data() before input to your map function\n     * @param [dataOptions.removeMeta] - allows removing meta before calling mapFun\n     * @param [dataOptions.forceClones] - forcing the return of cloned objects to your map object\n     * @param [dataOptions.forceCloneMethod] - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} Result of the mapping operation\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinProp: string | ((obj: any) => string), rightJoinProp: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * (Staging API) create a stage and/or retrieve it\n     */\n    getStage(name: string): any;\n    /**\n     * a collection of objects recording the changes applied through a commmitStage\n     */\n    /**\n     * (Staging API) create a copy of an object and insert it into a stage\n     */\n    stage<F extends TData>(stageName: string, obj: Doc<F>): F;\n    /**\n     * (Staging API) re-attach all objects to the original collection, so indexes and views can be rebuilt\n     * then create a message to be inserted in the commitlog\n     * @param {string} stageName - name of stage\n     * @param {string} message\n     */\n    commitStage(stageName: string, message: string): void;\n    /**\n     * Returns all values of a field.\n     * @param {string} field - the field name\n     * @return {any}: the array of values\n     */\n    extract(field: keyof T): any[];\n    /**\n     * Finds the minimum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the minimum value\n     */\n    min(field: keyof T): number;\n    /**\n     * Finds the maximum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the maximum value\n     */\n    max(field: keyof T): number;\n    /**\n     * Finds the minimum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    minRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Finds the maximum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    maxRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Returns all values of a field as numbers (if possible).\n     * @param {string} field - the field name\n     * @return {number[]} - the number array\n     */\n    extractNumerical(field: keyof T): number[];\n    /**\n     * Calculates the average numerical value of a field\n     * @param {string} field - the field name\n     * @returns {number} average of property in all docs in the collection\n     */\n    avg(field: keyof T): number;\n    /**\n     * Calculate the standard deviation of a field.\n     * @param {string} field - the field name\n     * @return {number} the standard deviation\n     */\n    stdDev(field: keyof T): number;\n    /**\n     * Calculates the mode of a field.\n     * @param {string} field - the field name\n     * @return {number} the mode\n     */\n    mode(field: keyof T): number;\n    /**\n     * Calculates the median of a field.\n     * @param {string} field - the field name\n     * @return {number} the median\n     */\n    median(field: keyof T): number;\n}\nexport declare namespace Collection {\n    interface Options<TData extends object, TNested extends object = {}, T extends object = TData & TNested> {\n        unique?: (keyof T)[];\n        unindexedSortComparator?: string;\n        defaultLokiOperatorPackage?: string;\n        rangedIndexes?: RangedIndexOptions;\n        serializableIndexes?: boolean;\n        asyncListeners?: boolean;\n        disableMeta?: boolean;\n        disableChangesApi?: boolean;\n        disableDeltaChangesApi?: boolean;\n        clone?: boolean;\n        serializableIndices?: boolean;\n        cloneMethod?: CloneMethod;\n        transactional?: boolean;\n        ttl?: number;\n        ttlInterval?: number;\n        nestedProperties?: (keyof TNested | {\n            name: keyof TNested;\n            path: string[];\n        })[];\n        fullTextSearch?: FullTextSearch.FieldOptions[];\n    }\n    interface RangedIndexOptions {\n        [prop: string]: RangedIndexMeta;\n    }\n    interface DeserializeOptions {\n        retainDirtyFlags?: boolean;\n        fullTextSearch?: Dict<Analyzer>;\n        [collName: string]: any | {\n            proto?: any;\n            inflate?: (src: object, dest?: object) => void;\n        };\n    }\n    interface BinaryIndex {\n        dirty: boolean;\n        values: any;\n    }\n    interface RangedIndexMeta {\n        index?: IRangedIndex<any>;\n        indexTypeName?: string;\n        comparatorName?: string;\n    }\n    interface Change {\n        name: string;\n        operation: string;\n        obj: any;\n    }\n    interface Serialized {\n        name: string;\n        unindexedSortComparator: string;\n        defaultLokiOperatorPackage: string;\n        _dynamicViews: DynamicView[];\n        _nestedProperties: {\n            name: string;\n            path: string[];\n        }[];\n        uniqueNames: string[];\n        transforms: Dict<Transform[]>;\n        rangedIndexes: RangedIndexOptions;\n        _data: Doc<any>[];\n        idIndex: number[];\n        maxId: number;\n        _dirty: boolean;\n        transactional: boolean;\n        asyncListeners: boolean;\n        disableMeta: boolean;\n        disableChangesApi: boolean;\n        disableDeltaChangesApi: boolean;\n        cloneObjects: boolean;\n        cloneMethod: CloneMethod;\n        changes: any;\n        _fullTextSearch: FullTextSearch;\n    }\n    interface CheckIndexOptions {\n        randomSampling?: boolean;\n        randomSamplingFactor?: number;\n        repair?: boolean;\n    }\n    type Transform<T extends object = object> = {\n        type: \"find\";\n        value: ResultSet.Query<Doc<T>> | string;\n    } | {\n        type: \"where\";\n        value: ((obj: Doc<T>) => boolean) | string;\n    } | {\n        type: \"simplesort\";\n        property: keyof T;\n        options?: boolean | ResultSet.SimpleSortOptions;\n    } | {\n        type: \"compoundsort\";\n        value: (keyof T | [keyof T, boolean])[];\n    } | {\n        type: \"sort\";\n        value: (a: Doc<T>, b: Doc<T>) => number;\n    } | {\n        type: \"sortByScoring\";\n        desc?: boolean;\n    } | {\n        type: \"limit\";\n        value: number;\n    } | {\n        type: \"offset\";\n        value: number;\n    } | {\n        type: \"map\";\n        value: (obj: Doc<T>, index: number, array: Doc<T>[]) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"eqJoin\";\n        joinData: Collection<any> | ResultSet<any>;\n        leftJoinKey: string | ((obj: any) => string);\n        rightJoinKey: string | ((obj: any) => string);\n        mapFun?: (left: any, right: any) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"mapReduce\";\n        mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => any;\n        reduceFunction: (array: any[]) => any;\n    } | {\n        type: \"update\";\n        value: (obj: Doc<T>) => any;\n    } | {\n        type: \"remove\";\n    };\n    interface TTL {\n        age: number;\n        ttlInterval: number;\n        daemon: any;\n    }\n}\n"
  },
  {
    "path": "dist/packages/loki/types/loki/src/comparators.d.ts",
    "content": "export interface ILokiComparer<T> {\n    (a: T, b: T): -1 | 0 | 1;\n}\nexport interface IComparatorMap {\n    [name: string]: ILokiComparer<any>;\n}\n/** Map/Register of named ILokiComparer functions returning -1, 0, 1 for lt/eq/gt assertions for two passed parameters */\nexport declare let ComparatorMap: IComparatorMap;\n/** Typescript-friendly factory for strongly typed 'js' comparators */\nexport declare function CreateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'abstract js' comparators */\nexport declare function CreateAbstractJavascriptComparator<T>(): ILokiComparer<T>;\n/**\n * Comparator which attempts to deal with deal with dates at comparator level.\n * Should work for dates in any of the object, string, and number formats\n */\nexport declare function CreateAbstractDateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'loki' comparators */\nexport declare function CreateLokiComparator(): ILokiComparer<any>;\n"
  },
  {
    "path": "dist/packages/loki/types/loki/src/dynamic_view.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { ResultSet } from \"./result_set\";\nimport { Collection } from \"./collection\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\n/**\n * DynamicView class is a versatile 'live' view class which can have filters and sorts applied.\n *    Collection.addDynamicView(name) instantiates this DynamicView object and notifies it\n *    whenever documents are add/updated/removed so it can remain up-to-date. (chainable)\n *\n * @example\n * let mydv = mycollection.addDynamicView('test');  // default is non-persistent\n * mydv.applyFind({ 'doors' : 4 });\n * mydv.applyWhere(function(obj) { return obj.name === 'Toyota'; });\n * let results = mydv.data();\n *\n * @extends LokiEventEmitter\n\n * @see {@link Collection#addDynamicView} to construct instances of DynamicView\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class DynamicView<T extends object = object> extends LokiEventEmitter {\n    readonly name: string;\n    private _collection;\n    private _persistent;\n    private _sortPriority;\n    private _minRebuildInterval;\n    private _rebuildPending;\n    private _resultSet;\n    private _resultData;\n    private _resultDirty;\n    private _cachedResultSet;\n    private _filterPipeline;\n    private _sortFunction;\n    private _sortCriteria;\n    private _sortCriteriaSimple;\n    private _sortByScoring;\n    private _sortDirty;\n    /**\n     * Constructor.\n     * @param {Collection} collection - a reference to the collection to work agains\n     * @param {string} name - the name of this dynamic view\n     * @param {object} options - the options\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=\"passive\"] - the sort priority\n     * @param {number} [options.minRebuildInterval=1] - minimum rebuild interval (need clarification to docs here)\n     */\n    constructor(collection: Collection<T>, name: string, options?: DynamicView.Options);\n    /**\n     * Internally used immediately after deserialization (loading)\n     *    This will clear out and reapply filterPipeline ops, recreating the view.\n     *    Since where filters do not persist correctly, this method allows\n     *    restoring the view to state where user can re-apply those where filters.\n     *\n     * @param removeWhereFilters\n     * @returns {DynamicView} This dynamic view for further chained ops.\n     * @fires DynamicView.rebuild\n     */\n    private _rematerialize({removeWhereFilters});\n    /**\n     * Makes a copy of the internal ResultSet for branched queries.\n     * Unlike this dynamic view, the branched ResultSet will not be 'live' updated,\n     * so your branched query should be immediately resolved and not held for future evaluation.\n     * @param {(string|array=)} transform - Optional name of collection transform, or an array of transform steps\n     * @param {object} parameters - optional parameters (if optional transform requires them)\n     * @returns {ResultSet} A copy of the internal ResultSet for branched queries.\n     */\n    branchResultSet(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Override of toJSON to avoid circular references.\n     */\n    toJSON(): DynamicView.Serialized;\n    static fromJSONObject(collection: Collection, obj: DynamicView.Serialized): DynamicView;\n    /**\n     * Used to clear pipeline and reset dynamic view to initial state.\n     * Existing options should be retained.\n     * @param {boolean} queueSortPhase - (default: false) if true we will async rebuild view (maybe set default to true in future?)\n     */\n    removeFilters({queueSortPhase}?: {\n        queueSortPhase?: boolean;\n    }): void;\n    /**\n     * Used to apply a sort to the dynamic view\n     * @example\n     * dv.applySort(function(obj1, obj2) {\n       *   if (obj1.name === obj2.name) return 0;\n       *   if (obj1.name > obj2.name) return 1;\n       *   if (obj1.name < obj2.name) return -1;\n       * });\n     * @param {function} comparefun - a javascript compare function used for sorting\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applySort(comparefun: (lhs: Doc<T>, rhs: Doc<T>) => number): this;\n    /**\n     * Used to specify a property used for view translation.\n     * @param {string} field - the field name\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether we should sort descending.\n     * @param {boolean} [options.disableIndexIntersect=false] - whether we should explicity not use array intersection.\n     * @param {boolean} [options.forceIndexIntersect=false] - force array intersection (if binary index exists).\n     * @param {boolean} [options.useJavascriptSorting=false] - whether results are sorted via basic javascript sort.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     * @example\n     * dv.applySimpleSort(\"name\");\n     */\n    applySimpleSort(field: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @param {Array} criteria - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {DynamicView} Reference to this DynamicView, sorted, for future chain operations.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * dv.applySortCriteria(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * dv.applySortCriteria(['age', ['name', true]]);\n     * // to sort by age (descending) and then by name (descending)\n     * dv.applySortCriteria([['age', true], ['name', true]]);\n     */\n    applySortCriteria(criteria: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Used to apply a sort by the latest full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     */\n    applySortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Marks the beginning of a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    startTransaction(): this;\n    /**\n     * Commits a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    commit(): this;\n    /**\n     * Rolls back a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    rollback(): this;\n    /**\n     * Find the index of a filter in the pipeline, by that filter's ID.\n     * @param {(string|number)} uid - The unique ID of the filter.\n     * @returns {number}: index of the referenced filter in the pipeline; -1 if not found.\n     */\n    private _indexOfFilterWithId(uid);\n    /**\n     * Add the filter object to the end of view's filter pipeline and apply the filter to the ResultSet.\n     * @param {object} filter - The filter object. Refer to applyFilter() for extra details.\n     */\n    private _addFilter(filter);\n    /**\n     * Reapply all the filters in the current pipeline.\n     *\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    reapplyFilters(): this;\n    /**\n     * Adds or updates a filter in the DynamicView filter pipeline\n     * @param {object} filter - A filter object to add to the pipeline.\n     *    The object is in the format { 'type': filter_type, 'val', filter_param, 'uid', optional_filter_id }\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFilter(filter: DynamicView.Filter<T>): this;\n    /**\n     * applyFind() - Adds or updates a mongo-style query option in the DynamicView filter pipeline\n     *\n     * @param {object} query - A mongo-style query object to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFind(query: object, uid?: string | number): this;\n    /**\n     * Adds or updates a javascript filter function in the DynamicView filter pipeline\n     * @param {function} fun - A javascript filter function to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyWhere(fun: (obj: Doc<T>) => boolean, uid?: string | number): this;\n    /**\n     * Remove the specified filter from the DynamicView filter pipeline\n     * @param {(string|number)} uid - The unique ID of the filter to be removed.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    removeFilter(uid: string | number): this;\n    /**\n     * Returns the number of documents representing the current DynamicView contents.\n     * @returns {number} The number of documents representing the current DynamicView contents.\n     */\n    count(): number;\n    /**\n     * Resolves and pending filtering and sorting, then returns document array as result.\n     * @param {object} options - optional parameters to pass to ResultSet.data() if non-persistent\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values include 'parse-stringify', 'jquery-extend-deep', 'shallow', 'shallow-assign'\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} An array of documents representing the current DynamicView contents.\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * When the view is not sorted we may still wish to be notified of rebuild events.\n     * This event will throttle and queue a single rebuild event when batches of updates affect the view.\n     */\n    private _queueRebuildEvent();\n    /**\n     * If the view is sorted we will throttle sorting to either :\n     * (1) passive - when the user calls data(), or\n     * (2) active - once they stop updating and yield js thread control\n     */\n    private _queueSortPhase();\n    /**\n     * Invoked synchronously or asynchronously to perform final sort phase (if needed)\n     */\n    private _performSortPhase(options?);\n    /**\n     * (Re)evaluating document inclusion.\n     * Called by : collection.insert() and collection.update().\n     * @param {int} objIndex - index of document to (re)run through filter pipeline.\n     * @param {boolean} isNew - true if the document was just added to the collection.\n     * @hidden\n     */\n    _evaluateDocument(objIndex: number, isNew: boolean): void;\n    /**\n     * Internal function called on collection.delete().\n     * @hidden\n     */\n    _removeDocument(objIndex: number): void;\n    /**\n     * Data transformation via user supplied functions\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: T, index: number, array: T[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n}\nexport declare namespace DynamicView {\n    interface Options {\n        persistent?: boolean;\n        sortPriority?: SortPriority;\n        minRebuildInterval?: number;\n    }\n    type SortPriority = \"passive\" | \"active\";\n    interface Serialized {\n        name: string;\n        _persistent: boolean;\n        _sortPriority: SortPriority;\n        _minRebuildInterval: number;\n        _resultSet: ResultSet<any>;\n        _filterPipeline: Filter<any>[];\n        _sortCriteria: (string | [string, boolean])[];\n        _sortCriteriaSimple: {\n            field: string;\n            options: boolean | ResultSet.SimpleSortOptions;\n        };\n        _sortByScoring: boolean;\n        _sortDirty: boolean;\n    }\n    type Filter<T extends object = object> = {\n        type: \"find\";\n        val: ResultSet.Query<Doc<T>>;\n        uid: number | string;\n    } | {\n        type: \"where\";\n        val: (obj: Doc<T>) => boolean;\n        uid: number | string;\n    };\n}\n"
  },
  {
    "path": "dist/packages/loki/types/loki/src/event_emitter.d.ts",
    "content": "/**\n * LokiEventEmitter is a minimalist version of EventEmitter. It enables any\n * constructor that inherits EventEmitter to emit events and trigger\n * listeners that have been added to the event through the on(event, callback) method\n *\n * @constructor LokiEventEmitter\n */\nexport declare class LokiEventEmitter {\n    /**\n     * A map, with each property being an array of callbacks.\n     */\n    protected _events: object;\n    /**\n     * Determines whether or not the callbacks associated with each event should happen in an async fashion or not.\n     * Default is false, which means events are synchronous\n     */\n    protected _asyncListeners: boolean;\n    /**\n     * Adds a listener to the queue of callbacks associated to an event\n     * @param {string|string[]} eventName - the name(s) of the event(s) to listen to\n     * @param {function} listener - callback function of listener to attach\n     * @returns {int} the index of the callback in the array of listeners for a particular event\n     */\n    on(eventName: string | string[], listener: Function): Function;\n    /**\n     * Emits a particular event\n     * with the option of passing optional parameters which are going to be processed by the callback\n     * provided signatures match (i.e. if passing emit(event, arg0, arg1) the listener should take two parameters)\n     * @param {string} eventName - the name of the event\n     * @param {object} data - optional object passed with the event\n     */\n    protected emit(eventName: string, ...data: any[]): void;\n    /**\n     * Alias of EventEmitter.on().\n     */\n    addListener(eventName: string | string[], listener: Function): Function;\n    /**\n     * Removes the listener at position 'index' from the event 'eventName'\n     * @param {string|string[]} eventName - the name(s) of the event(s) which the listener is attached to\n     * @param {function} listener - the listener callback function to remove from emitter\n     */\n    removeListener(eventName: string | string[], listener: Function): void;\n}\n"
  },
  {
    "path": "dist/packages/loki/types/loki/src/index.d.ts",
    "content": "import { Loki } from \"./loki\";\nimport { Collection } from \"./collection\";\nexport { Loki, Collection };\nexport default Loki;\n"
  },
  {
    "path": "dist/packages/loki/types/loki/src/loki.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { Collection } from \"./collection\";\nimport { Doc, StorageAdapter } from \"../../common/types\";\nimport { IComparatorMap } from \"./comparators\";\nimport { IRangedIndexFactoryMap } from \"./ranged_indexes\";\nimport { ILokiOperatorPackageMap } from \"./operator_packages\";\nexport declare class Loki extends LokiEventEmitter {\n    filename: string;\n    private databaseVersion;\n    private engineVersion;\n    _collections: Collection[];\n    private _env;\n    private _serializationMethod;\n    private _destructureDelimiter;\n    private _persistenceMethod;\n    private _persistenceAdapter;\n    private _throttledSaves;\n    private _throttledSaveRunning;\n    private _throttledSavePending;\n    private _autosave;\n    private _autosaveInterval;\n    private _autosaveRunning;\n    private _autosaveHandler;\n    /**\n     * Constructs the main database class.\n     * @param {string} filename - name of the file to be saved to\n     * @param {object} [options={}] - options\n     * @param {Loki.Environment} [options.env] - the javascript environment\n     * @param {Loki.SerializationMethod} [options.serializationMethod=NORMAL] - the serialization method\n     * @param {string} [options.destructureDelimiter=\"$<\\n\"] - string delimiter used for destructured serialization\n     * @param {IComparatorMap} [options.comparatorMap] allows injecting or overriding registered comparators\n     * @param {IRangedIndexFactoryMap} [options.rangedIndexFactoryMap] allows injecting or overriding registered ranged index factories\n     * @param {ILokiOperatorPackageMap} [options.lokiOperatorPackageMap] allows injecting or overriding registered loki operator packages\n     */\n    constructor(filename?: string, options?: Loki.Options);\n    /**\n     * configures options related to database persistence.\n     *\n     * @param {Loki.PersistenceOptions} [options={}] - options\n     * @param {adapter} [options.adapter=auto] - an instance of a loki persistence adapter\n     * @param {boolean} [options.autosave=false] - enables autosave\n     * @param {int} [options.autosaveInterval=5000] - time interval (in milliseconds) between saves (if dirty)\n     * @param {boolean} [options.autoload=false] - enables autoload on loki instantiation\n     * @param {object} options.inflate - options that are passed to loadDatabase if autoload enabled\n     * @param {boolean} [options.throttledSaves=true] - if true, it batches multiple calls to to saveDatabase reducing number of\n     *   disk I/O operations and guaranteeing proper serialization of the calls. Default value is true.\n     * @param {Loki.PersistenceMethod} options.persistenceMethod - a persistence method which should be used (FS_STORAGE, LOCAL_STORAGE...)\n     * @returns {Promise} a Promise that resolves after initialization and (if enabled) autoloading the database\n     */\n    initializePersistence(options?: Loki.PersistenceOptions): Promise<void>;\n    /**\n     * Copies 'this' database into a new Loki instance. Object references are shared to make lightweight.\n     * @param {object} options - options\n     * @param {boolean} options.removeNonSerializable - nulls properties not safe for serialization.\n     */\n    copy(options?: Loki.CopyOptions): Loki;\n    /**\n     * Adds a collection to the database.\n     * @param {string} name - name of collection to add\n     * @param {object} [options={}] - options to configure collection with.\n     * @param {array} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {array} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {array} [options.indices=[]] - array property names to define binary indexes for\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are called asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes Api\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {string} [options.cloneMethod=CloneMethod.DEEP] - the clone method\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @returns {Collection} a reference to the collection which was just added\n     */\n    addCollection<TData extends object = object, TNested extends object = object>(name: string, options?: Collection.Options<TData, TNested>): Collection<TData, TNested>;\n    loadCollection(collection: Collection): void;\n    /**\n     * Retrieves reference to a collection by name.\n     * @param {string} name - name of collection to look up\n     * @returns {Collection} Reference to collection in database by that name, or null if not found\n     */\n    getCollection<TData extends object = object, TNested extends object = object>(name: string): Collection<TData, TNested>;\n    /**\n     * Renames an existing loki collection\n     * @param {string} oldName - name of collection to rename\n     * @param {string} newName - new name of collection\n     * @returns {Collection} reference to the newly renamed collection\n     */\n    renameCollection<TData extends object = object, TNested extends object = object>(oldName: string, newName: string): Collection<TData, TNested>;\n    listCollections(): {\n        name: string;\n        count: number;\n    }[];\n    /**\n     * Removes a collection from the database.\n     * @param {string} collectionName - name of collection to remove\n     */\n    removeCollection(collectionName: string): void;\n    /**\n     * Serialize database to a string which can be loaded via {@link Loki#loadJSON}\n     *\n     * @returns {string} Stringified representation of the loki database.\n     */\n    serialize(options?: Loki.SerializeOptions): string | string[];\n    toJSON(): Loki.Serialized;\n    /**\n     * Database level destructured JSON serialization routine to allow alternate serialization methods.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {object} options - output format options for use externally to loki\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to only output an individual collection or db (-1)\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {string|Array} A custom, restructured aggregation of independent serializations.\n     */\n    serializeDestructured(options?: Loki.SerializeDestructuredOptions): string | string[];\n    /**\n     * Collection level utility method to serialize a collection in a 'destructured' format\n     *\n     * @param {object} options - used to determine output of method\n     * @param {int} options.delimited - whether to return single delimited string or an array\n     * @param {string} options.delimiter - (optional) if delimited, this is delimiter to use\n     * @param {int} options.collectionIndex -  specify which collection to serialize data for\n     *\n     * @returns {string|array} A custom, restructured aggregation of independent serializations for a single collection.\n     */\n    serializeCollection(options?: {\n        delimited?: boolean;\n        collectionIndex?: number;\n        delimiter?: string;\n    }): string | string[];\n    /**\n     * Database level destructured JSON deserialization routine to minimize memory overhead.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {string|array} destructuredSource - destructured json or array to deserialize from\n     * @param {object} options - source format options\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to deserialize only a single partition\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {object|array} An object representation of the deserialized database, not yet applied to 'this' db or document array\n     */\n    deserializeDestructured(destructuredSource: string | string[], options?: Loki.SerializeDestructuredOptions): any;\n    /**\n     * Collection level utility function to deserializes a destructured collection.\n     *\n     * @param {string|string[]} destructuredSource - destructured representation of collection to inflate\n     * @param {object} options - used to describe format of destructuredSource input\n     * @param {int} [options.delimited=false] - whether source is delimited string or an array\n     * @param {string} options.delimiter - if delimited, this is delimiter to use (if other than default)\n     *\n     * @returns {Array} an array of documents to attach to collection.data.\n     */\n    deserializeCollection<T extends object = object>(destructuredSource: string | string[], options?: Loki.DeserializeCollectionOptions): Doc<T>[];\n    /**\n     * Inflates a loki database from a serialized JSON string\n     *\n     * @param {string} serializedDb - a serialized loki database string\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSON(serializedDb: string | string[], options?: Collection.DeserializeOptions): void;\n    /**\n     * Inflates a loki database from a JS object\n     *\n     * @param {object} dbObject - a serialized loki database object\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSONObject(dbObject: Loki, options?: Collection.DeserializeOptions): void;\n    loadJSONObject(dbObject: Loki.Serialized, options?: Collection.DeserializeOptions): void;\n    /**\n     * Emits the close event. In autosave scenarios, if the database is dirty, this will save and disable timer.\n     * Does not actually destroy the db.\n     *\n     * @returns {Promise} a Promise that resolves after closing the database succeeded\n     */\n    close(): Promise<void>;\n    /**-------------------------+\n     | Changes API               |\n     +--------------------------*/\n    /**\n     * The Changes API enables the tracking the changes occurred in the collections since the beginning of the session,\n     * so it's possible to create a differential dataset for synchronization purposes (possibly to a remote db)\n     */\n    /**\n     * (Changes API) : takes all the changes stored in each\n     * collection and creates a single array for the entire database. If an array of names\n     * of collections is passed then only the included collections will be tracked.\n     *\n     * @param {Array} [arrayOfCollectionNames=] - array of collection names. No arg means all collections are processed.\n     * @returns {Array} array of changes\n     * @see private method _createChange() in Collection\n     */\n    generateChangesNotification(arrayOfCollectionNames?: string[]): Collection.Change[];\n    /**\n     * (Changes API) - stringify changes for network transmission\n     * @returns {string} string representation of the changes\n     */\n    serializeChanges(collectionNamesArray?: string[]): string;\n    /**\n     * (Changes API) : clears all the changes in all collections.\n     */\n    clearChanges(): void;\n    /**\n     * Wait for throttledSaves to complete and invoke your callback when drained or duration is met.\n     *\n     * @param {object} options - configuration options\n     * @param {boolean} [options.recursiveWait=true] - if after queue is drained, another save was kicked off, wait for it\n     * @param {boolean} [options.recursiveWaitLimit=false] - limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDuration=2000] - cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves when save queue is drained, it is passed a sucess parameter value\n     */\n    throttledSaveDrain(options?: Loki.ThrottledDrainOptions): Promise<void>;\n    /**\n     * Internal load logic, decoupled from throttling/contention logic\n     *\n     * @param {object} options - an object containing inflation options for each collection\n     * @param {boolean} ignore_not_found - does not raise an error if database is not found\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    private _loadDatabase(options?, ignore_not_found?);\n    /**\n     * Handles manually loading from an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *    To avoid contention with any throttledSaves, we will drain the save queue first.\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @param {object} [options={}] - if throttling saves and loads, this controls how we drain save queue before loading\n     * @param {boolean} [options.recursiveWait=true] wait recursively until no saves are queued\n     * @param {boolean} [options.recursiveWaitLimit=false] limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDelay=2000] cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    loadDatabase(options?: Loki.LoadDatabaseOptions): Promise<void>;\n    private _saveDatabase();\n    /**\n     * Handles manually saving to an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @returns {Promise} a Promise that resolves after the database is persisted\n     */\n    saveDatabase(): Promise<void>;\n    /**\n     * Handles deleting a database from the underlying storage adapter\n     *\n     * @returns {Promise} a Promise that resolves after the database is deleted\n     */\n    deleteDatabase(): Promise<void>;\n    /****************\n     * Autosave API\n     ****************/\n    /**\n     * Check whether any collections are \"dirty\" meaning we need to save the (entire) database\n     * @returns {boolean} - true if database has changed since last autosave, otherwise false\n     */\n    private _autosaveDirty();\n    /**\n     * Resets dirty flags on all collections.\n     */\n    private _autosaveClearFlags();\n    /**\n     * Starts periodically saves to the underlying storage adapter.\n     */\n    private _autosaveEnable();\n    /**\n     * Stops the autosave interval timer.\n     */\n    private _autosaveDisable();\n}\nexport declare namespace Loki {\n    interface Options {\n        env?: Environment;\n        serializationMethod?: SerializationMethod;\n        destructureDelimiter?: string;\n        comparatorMap?: IComparatorMap;\n        rangedIndexFactoryMap?: IRangedIndexFactoryMap;\n        lokiOperatorPackageMap?: ILokiOperatorPackageMap;\n    }\n    interface PersistenceOptions {\n        adapter?: StorageAdapter;\n        autosave?: boolean;\n        autosaveInterval?: number;\n        autoload?: boolean;\n        throttledSaves?: boolean;\n        persistenceMethod?: Loki.PersistenceMethod;\n        inflate?: any;\n    }\n    interface CopyOptions {\n        removeNonSerializable?: boolean;\n    }\n    interface SerializeOptions {\n        serializationMethod?: SerializationMethod;\n    }\n    interface SerializeDestructuredOptions {\n        partitioned?: boolean;\n        partition?: number;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface DeserializeCollectionOptions {\n        partitioned?: boolean;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface ThrottledDrainOptions {\n        recursiveWait?: boolean;\n        recursiveWaitLimit?: boolean;\n        recursiveWaitLimitDuration?: number;\n        started?: Date;\n    }\n    interface Serialized {\n        _env: Environment;\n        _serializationMethod: SerializationMethod;\n        _autosave: boolean;\n        _autosaveInterval: number;\n        _collections: Collection[];\n        databaseVersion: number;\n        engineVersion: number;\n        filename: string;\n        _persistenceAdapter: StorageAdapter;\n        _persistenceMethod: PersistenceMethod;\n        _throttledSaves: boolean;\n    }\n    type LoadDatabaseOptions = Collection.DeserializeOptions & ThrottledDrainOptions;\n    type SerializationMethod = \"normal\" | \"pretty\" | \"destructured\";\n    type PersistenceMethod = \"fs-storage\" | \"local-storage\" | \"indexed-storage\" | \"memory-storage\" | \"adapter\";\n    type Environment = \"NATIVESCRIPT\" | \"NODEJS\" | \"CORDOVA\" | \"BROWSER\" | \"MEMORY\";\n}\n"
  },
  {
    "path": "dist/packages/loki/types/loki/src/operator_packages.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\n/** Hash interface for named LokiOperatorPackage registration */\nexport interface ILokiOperatorPackageMap {\n    [name: string]: LokiOperatorPackage;\n}\n/**\n * Helper function for determining 'loki' abstract equality which is a little more abstract than ==\n *     aeqHelper(5, '5') === true\n *     aeqHelper(5.0, '5') === true\n *     aeqHelper(new Date(\"1/1/2011\"), new Date(\"1/1/2011\")) === true\n *     aeqHelper({a:1}, {z:4}) === true (all objects sorted equally)\n *     aeqHelper([1, 2, 3], [1, 3]) === false\n *     aeqHelper([1, 2, 3], [1, 2, 3]) === true\n *     aeqHelper(undefined, null) === true\n * @param {any} prop1\n * @param {any} prop2\n * @returns {boolean}\n * @hidden\n */\nexport declare function aeqHelper(prop1: any, prop2: any): boolean;\n/**\n * Helper function for determining 'less-than' conditions for ops, sorting, and binary indices.\n *     In the future we might want $lt and $gt ops to use their own functionality/helper.\n *     Since binary indices on a property might need to index [12, NaN, new Date(), Infinity], we\n *     need this function (as well as gtHelper) to always ensure one value is LT, GT, or EQ to another.\n * @hidden\n */\nexport declare function ltHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @hidden\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} equal\n * @returns {boolean}\n */\nexport declare function gtHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} descending\n * @returns {number}\n * @hidden\n */\nexport declare function sortHelper(prop1: any, prop2: any, descending: boolean): number;\n/**\n * Default implementation of LokiOperatorPackage, using fastest javascript comparison operators.\n */\nexport declare class LokiOperatorPackage {\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n    $in(a: any, b: any): boolean;\n    $nin(a: any, b: any): boolean;\n    $keyin(a: string, b: object): boolean;\n    $nkeyin(a: string, b: object): boolean;\n    $definedin(a: string, b: object): boolean;\n    $undefinedin(a: string, b: object): boolean;\n    $regex(a: string, b: RegExp): boolean;\n    $containsNone(a: any, b: any): boolean;\n    $containsAny(a: any, b: any): boolean;\n    $contains(a: any, b: any): boolean;\n    $type(a: any, b: any): boolean;\n    $finite(a: number, b: boolean): boolean;\n    $size(a: any, b: any): boolean;\n    $len(a: any, b: any): boolean;\n    $where(a: any, b: any): boolean;\n    $not(a: any, b: any): boolean;\n    $and(a: any, b: any): boolean;\n    $or(a: any, b: any): boolean;\n    private doQueryOp(val, op);\n    private containsCheckFn(a);\n}\n/**\n * LokiOperatorPackage which utilizes abstract 'loki' comparisons for basic relational equality op implementations.\n */\nexport declare class LokiAbstractOperatorPackage extends LokiOperatorPackage {\n    constructor();\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * LokiOperatorPackage which utilizes provided comparator for basic relational equality op implementations.\n */\nexport declare class ComparatorOperatorPackage<T> extends LokiOperatorPackage {\n    comparator: ILokiComparer<T>;\n    constructor(comparator: ILokiComparer<T>);\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * Map/Register of named LokiOperatorPackages which implement all unindexed query ops within 'find' query objects\n */\nexport declare let LokiOperatorPackageMap: ILokiOperatorPackageMap;\n"
  },
  {
    "path": "dist/packages/loki/types/loki/src/ranged_indexes.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\nexport declare type RangedValueOperator = \"$gt\" | \"$gte\" | \"$lt\" | \"$lte\" | \"$eq\" | \"$neq\" | \"$between\";\nexport interface IRangedIndexRequest<T> {\n    op: RangedValueOperator;\n    val: T;\n    high?: T;\n}\n/** Defines interface which all loki ranged indexes need to implement */\nexport interface IRangedIndex<T> {\n    insert(id: number, val: T): void;\n    update(id: number, val: T): void;\n    remove(id: number): void;\n    restore(tree: any): void;\n    backup(): IRangedIndex<T>;\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    validateIndex(): boolean;\n}\n/** Hash Interface for global ranged index factory map*/\nexport interface IRangedIndexFactoryMap {\n    [name: string]: (name: string, comparator: ILokiComparer<any>) => IRangedIndex<any>;\n}\n/** Map/Register of named factory functions returning IRangedIndex instances */\nexport declare let RangedIndexFactoryMap: IRangedIndexFactoryMap;\n"
  },
  {
    "path": "dist/packages/loki/types/loki/src/result_set.d.ts",
    "content": "import { Collection } from \"./collection\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\nimport { Query as FullTextSearchQuery } from \"../../full-text-search/src/query_types\";\n/**\n * ResultSet class allowing chainable queries.  Intended to be instanced internally.\n *    Collection.find(), Collection.where(), and Collection.chain() instantiate this.\n *\n * @example\n *    mycollection.chain()\n *      .find({ 'doors' : 4 })\n *      .where(function(obj) { return obj.name === 'Toyota' })\n *      .data();\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class ResultSet<T extends object = object> {\n    _collection: Collection<T>;\n    _filteredRows: number[];\n    _filterInitialized: boolean;\n    private _scoring;\n    /**\n     * Constructor.\n     * @param {Collection} collection - the collection which this ResultSet will query against\n     */\n    constructor(collection: Collection<T>);\n    /**\n     * Reset the ResultSet to its initial state.\n     * @returns {ResultSet} Reference to this ResultSet, for future chain operations.\n     */\n    reset(): this;\n    /**\n     * Override of toJSON to avoid circular references\n     */\n    toJSON(): ResultSet<T>;\n    /**\n     * Allows you to limit the number of documents passed to next chain operation.\n     * A ResultSet copy() is made to avoid altering original ResultSet.\n     * @param {int} qty - The number of documents to return.\n     * @returns {ResultSet} Returns a copy of the ResultSet, limited by qty, for subsequent chain ops.\n     */\n    limit(qty: number): this;\n    /**\n     * Used for skipping 'pos' number of documents in the ResultSet.\n     * @param {int} pos - Number of documents to skip; all preceding documents are filtered out.\n     * @returns {ResultSet} Returns a copy of the ResultSet, containing docs starting at 'pos' for subsequent chain ops.\n     */\n    offset(pos: number): this;\n    /**\n     * To support reuse of ResultSet in branched query situations.\n     * @returns {ResultSet} Returns a copy of the ResultSet (set) but the underlying document references will be the same.\n     */\n    copy(): ResultSet<T>;\n    /**\n     * Executes a named collection transform or raw array of transform steps against the ResultSet.\n     * @param {(string|array)} transform - name of collection transform or raw transform array\n     * @param {object} [parameters=] - object property hash of parameters, if the transform requires them.\n     * @returns {ResultSet} either (this) ResultSet or a clone of of this ResultSet (depending on steps)\n     */\n    transform(transform: string | Collection.Transform<T>[], parameters?: object): this;\n    /**\n     * User supplied compare function is provided two documents to compare. (chainable)\n     * @example\n     *    rslt.sort(function(obj1, obj2) {\n       *      if (obj1.name === obj2.name) return 0;\n       *      if (obj1.name > obj2.name) return 1;\n       *      if (obj1.name < obj2.name) return -1;\n       *    });\n     * @param {function} comparefun - A javascript compare function used for sorting.\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    sort(comparefun: (a: Doc<T>, b: Doc<T>) => number): this;\n    /**\n     * Simpler, loose evaluation for user to sort based on a property name. (chainable).\n     * Sorting based on the same lt/gt helper functions used for binary indices.\n     * @param {string} propname - name of property to sort by.\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether to sort descending\n     * @param {string} [options.sortComparator] override default with name of comparator registered in ComparatorMap\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    simplesort(propname: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * rs.compoundsort(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * rs.compoundsort(['age', ['name', true]);\n     * @param {array} properties - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    compoundsort(properties: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Helper function for compoundsort(), performing individual object comparisons\n     * @param {Array} properties - array of property names, in order, by which to evaluate sort order\n     * @param {object} obj1 - first object to compare\n     * @param {object} obj2 - second object to compare\n     * @returns {number} 0, -1, or 1 to designate if identical (sortwise) or which should be first\n     */\n    private _compoundeval(properties, obj1, obj2);\n    /**\n     * Sorts the ResultSet based on the last full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     * @returns {ResultSet}\n     */\n    sortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Oversee the operation of OR'ed query expressions.\n     * OR'ed expression evaluation runs each expression individually against the full collection,\n     * and finally does a set OR on each expression's results.\n     * Each evaluation can utilize a binary index to prevent multiple linear array scans.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findOr(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $or(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Oversee the operation of AND'ed query expressions.\n     * AND'ed expression evaluation runs each expression progressively against the full collection,\n     * internally utilizing existing chained ResultSet functionality.\n     * Only the first filter can utilize a binary index.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findAnd(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $and(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Used for querying via a mongo-style query object.\n     *\n     * @param {object} query - A mongo-style query object used for filtering current results.\n     * @param {boolean} firstOnly - (Optional) Used by collection.findOne() - flag if this was invoked via findOne()\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    find(query?: ResultSet.Query<Doc<T>>, firstOnly?: boolean): this;\n    /**\n     * Used for filtering via a javascript filter function.\n     * @param {function} fun - A javascript function used for filtering current results by.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    where(fun: (obj: Doc<T>) => boolean): this;\n    /**\n     * Returns the number of documents in the ResultSet.\n     * @returns {number} The number of documents in the ResultSet.\n     */\n    count(): number;\n    /**\n     * Terminates the chain and returns array of filtered documents\n     * @param {object} options\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values 'parse-stringify', 'deep', and 'shallow' and\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} Array of documents in the ResultSet\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * Used to run an update operation on all documents currently in the ResultSet.\n     * @param {function} updateFunction - User supplied updateFunction(obj) will be executed for each document object.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    update(updateFunction: (obj: Doc<T>) => Doc<T>): this;\n    /**\n     * Removes all document objects which are currently in ResultSet from collection (as well as ResultSet)\n     * @returns {ResultSet} this (empty) ResultSet for further chain ops.\n     */\n    remove(): this;\n    /**\n     * data transformation via user supplied functions\n     *\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns {value} The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Left joining two sets of data. Join keys can be defined or calculated properties\n     * eqJoin expects the right join key values to be unique.  Otherwise left data will be joined on the last joinData object with that key\n     * @param {Array|ResultSet|Collection} joinData - Data array to join to.\n     * @param {(string|function)} leftJoinKey - Property name in this result set to join on or a function to produce a value to join on\n     * @param {(string|function)} rightJoinKey - Property name in the joinData to join on or a function to produce a value to join on\n     * @param {function} [mapFun=] - a function that receives each matching pair and maps them into output objects - function(left,right){return joinedObject}\n     * @param {object} [dataOptions=] - optional options to apply to data() calls for left and right sides\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} A ResultSet with data in the format [{left: leftObj, right: rightObj}]\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinKey: string | ((obj: any) => string), rightJoinKey: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * Applies a map function into a new collection for further chaining.\n     * @param {function} mapFun - javascript map function\n     * @param {object} [dataOptions=] - options to data() before input to your map function\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - Allows overriding the default or collection specified cloning method\n     * @return {ResultSet}\n     */\n    map<U extends object>(mapFun: (obj: Doc<T>, index: number, array: Doc<T>[]) => U, dataOptions?: ResultSet.DataOptions): ResultSet<U>;\n}\nexport declare namespace ResultSet {\n    interface DataOptions {\n        forceClones?: boolean;\n        forceCloneMethod?: CloneMethod;\n        removeMeta?: boolean;\n    }\n    interface SimpleSortOptions {\n        desc?: boolean;\n        sortComparator?: string;\n    }\n    type ContainsHelperType<R> = R extends string ? string | string[] : R extends any[] ? R[number] | R[number][] : R extends object ? keyof R | (keyof R)[] : never;\n    type LokiOps<R> = {\n        $eq?: R;\n    } | {\n        $ne?: R;\n    } | {\n        $gt?: R;\n    } | {\n        $gte?: R;\n    } | {\n        $lt?: R;\n    } | {\n        $lte?: R;\n    } | {\n        $between?: [R, R];\n    } | {\n        $in?: R[];\n    } | {\n        $nin?: R[];\n    } | {\n        $keyin?: object;\n    } | {\n        $nkeyin?: object;\n    } | {\n        $definedin?: object;\n    } | {\n        $undefinedin?: object;\n    } | {\n        $regex?: RegExp | string | [string, string];\n    } | {\n        $containsNone?: ContainsHelperType<R>;\n    } | {\n        $containsAny?: ContainsHelperType<R>;\n    } | {\n        $contains?: ContainsHelperType<R>;\n    } | {\n        $type?: string;\n    } | {\n        $finite?: boolean;\n    } | {\n        $size?: number;\n    } | {\n        $len?: number;\n    } | {\n        $where?: (val?: R) => boolean;\n    };\n    type Query<T> = {\n        [P in keyof T]?: LokiOps<T[P]> | T[P];\n    } & {\n        $and?: Query<T>[];\n    } & {\n        $or?: Query<T>[];\n    } & {\n        $fts?: FullTextSearchQuery;\n    };\n}\n"
  },
  {
    "path": "dist/packages/loki/types/loki/src/unique_index.d.ts",
    "content": "export declare class UniqueIndex {\n    private _field;\n    private _lokiMap;\n    private _valMap;\n    /**\n     * Constructs an unique index object.\n     * @param {string} propertyField - the property field to index\n     */\n    constructor(propertyField: string);\n    /**\n     * Sets a document's unique index.\n     * @param {number} id loki id to associate with value\n     * @param {*} value  value to associate with id\n     */\n    set(id: number, value: any): void;\n    /**\n     * Returns the $loki id of an unique value.\n     * @param {*} value the value to retrieve a loki id match for\n     */\n    get(value: any): number;\n    /**\n     * Updates a document's unique index.\n     * @param {number} id (loki) id of document to update the value to\n     * @param {*} value value to associate with loki id\n     */\n    update(id: number, value: any): void;\n    /**\n     * Removes an unique index.\n     * @param {number} id (loki) id to remove from index\n     */\n    remove(id: number): void;\n    /**\n     * Clears the unique index.\n     */\n    clear(): void;\n}\n"
  },
  {
    "path": "dist/packages/loki/types/memory-storage/src/index.d.ts",
    "content": "import { MemoryStorage } from \"./memory_storage\";\nexport { MemoryStorage };\nexport default MemoryStorage;\n"
  },
  {
    "path": "dist/packages/loki/types/memory-storage/src/memory_storage.d.ts",
    "content": "import { Dict, StorageAdapter } from \"../../common/types\";\n/**\n * An in-memory persistence adapter for an in-memory database.\n * This simple 'key/value' adapter is intended for unit testing and diagnostics.\n */\nexport declare class MemoryStorage implements StorageAdapter {\n    hashStore: Dict<{\n        savecount: number;\n        lastsave: Date;\n        value: string;\n    }>;\n    options: MemoryStorage.Options;\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} options - memory storage options\n     * @param {boolean} [options.asyncResponses=false] - whether callbacks are invoked asynchronously (default: false)\n     * @param {int} [options.asyncTimeout=50] - timeout in ms to queue callbacks (default: 50)\n     */\n    constructor(options?: MemoryStorage.Options);\n    /**\n     * Loads a serialized database from its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * Saves a serialized database to its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {string} dbstring - the database content\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a database from its in-memory store.\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport declare namespace MemoryStorage {\n    interface Options {\n        asyncResponses?: boolean;\n        asyncTimeout?: number;\n    }\n}\n"
  },
  {
    "path": "dist/packages/loki/types/partitioning-adapter/src/index.d.ts",
    "content": "import { PartitioningAdapter } from \"./partitioning_adapter\";\nexport { PartitioningAdapter };\nexport default PartitioningAdapter;\n"
  },
  {
    "path": "dist/packages/loki/types/partitioning-adapter/src/partitioning_adapter.d.ts",
    "content": "import { Loki } from \"../../loki/src/loki\";\nimport { StorageAdapter } from \"../../common/types\";\n/**\n * An adapter for adapters. Converts a non reference mode adapter into a reference mode adapter\n * which can perform destructuring and partitioning. Each collection will be stored in its own key/save and\n * only dirty collections will be saved. If you  turn on paging with default page size of 25megs and save\n * a 75 meg collection it should use up roughly 3 save slots (key/value pairs sent to inner adapter).\n * A dirty collection that spans three pages will save all three pages again\n * Paging mode was added mainly because Chrome has issues saving 'too large' of a string within a\n * single IndexedDB row. If a single document update causes the collection to be flagged as dirty, all\n * of that collection's pages will be written on next save.\n */\nexport declare class PartitioningAdapter implements StorageAdapter {\n    mode: string;\n    private _adapter;\n    private _dbref;\n    private _dbname;\n    private _pageIterator;\n    private _paging;\n    private _pageSize;\n    private _delimiter;\n    private _dirtyPartitions;\n    /**\n     * Registers the partitioning adapter as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the partitioning storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} adapter - reference to a 'non-reference' mode loki adapter instance.\n     * @param {boolean} paging - (default: false) set to true to enable paging collection data.\n     * @param {number} pageSize - (default : 25MB) you can use this to limit size of strings passed to inner adapter.\n     * @param {string} delimiter - allows you to override the default delimiter\n     */\n    constructor(adapter: StorageAdapter, {paging, pageSize, delimiter}?: {\n        paging?: boolean;\n        pageSize?: number;\n        delimiter?: string;\n    });\n    /**\n     * Loads a database which was partitioned into several key/value saves.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Used to sequentially load each collection partition, one at a time.\n     *\n     * @param {int} partition - ordinal collection position to load next\n     * @returns {Promise} a Promise that resolves after the next partition is loaded\n     */\n    private _loadNextPartition(partition);\n    /**\n     * Used to sequentially load the next page of collection partition, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next page is loaded\n     */\n    private _loadNextPage();\n    /**\n     * Saves a database by partioning into separate key/value saves.\n     * (Loki 'reference mode' persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {object} dbref - reference to database which we will partition and save.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     *\n     */\n    exportDatabase(dbname: string, dbref: Loki): Promise<void>;\n    /**\n     * Helper method used internally to save each dirty collection, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPartition();\n    /**\n     * Helper method used internally to generate and save the next page of the current (dirty) partition.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPage();\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/lokidb.memory-storage.js",
    "content": "(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"@lokidb/memory-storage\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"@lokidb/memory-storage\"] = factory();\n\telse\n\t\t{ root[\"@lokidb/memory-storage\"] = factory(); root[\"LokiMemoryStorage\"] = root[\"@lokidb/memory-storage\"].default; }\n})(typeof self !== 'undefined' ? self : this, function() {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// define __esModule on exports\n/******/ \t__webpack_require__.r = function(exports) {\n/******/ \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n/******/ \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n/******/ \t\t}\n/******/ \t\tObject.defineProperty(exports, '__esModule', { value: true });\n/******/ \t};\n/******/\n/******/ \t// create a fake namespace object\n/******/ \t// mode & 1: value is a module id, require it\n/******/ \t// mode & 2: merge all properties of value into the ns\n/******/ \t// mode & 4: return value when already ns object\n/******/ \t// mode & 8|1: behave like require\n/******/ \t__webpack_require__.t = function(value, mode) {\n/******/ \t\tif(mode & 1) value = __webpack_require__(value);\n/******/ \t\tif(mode & 8) return value;\n/******/ \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n/******/ \t\tvar ns = Object.create(null);\n/******/ \t\t__webpack_require__.r(ns);\n/******/ \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n/******/ \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n/******/ \t\treturn ns;\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 1);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return PLUGINS; });\nfunction getGlobal() {\n    let glob;\n    (function (global) {\n        glob = global;\n    })(global !== undefined && global || this);\n    return glob;\n}\nfunction create() {\n    const global = getGlobal();\n    const sym = Symbol.for(\"LOKI\");\n    if (global[sym] === undefined) {\n        global[sym] = {};\n    }\n    return global[sym];\n}\n/**\n * @hidden\n */\nconst PLUGINS = create();\n\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(2)))\n\n/***/ }),\n/* 1 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n\n// EXTERNAL MODULE: ./packages/common/plugin.ts\nvar common_plugin = __webpack_require__(0);\n\n// CONCATENATED MODULE: ./packages/memory-storage/src/memory_storage.ts\n\n/**\n * An in-memory persistence adapter for an in-memory database.\n * This simple 'key/value' adapter is intended for unit testing and diagnostics.\n */\nclass memory_storage_MemoryStorage {\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register() {\n        common_plugin[\"a\" /* PLUGINS */][\"MemoryStorage\"] = memory_storage_MemoryStorage;\n    }\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister() {\n        delete common_plugin[\"a\" /* PLUGINS */][\"MemoryStorage\"];\n    }\n    /**\n     * @param {object} options - memory storage options\n     * @param {boolean} [options.asyncResponses=false] - whether callbacks are invoked asynchronously (default: false)\n     * @param {int} [options.asyncTimeout=50] - timeout in ms to queue callbacks (default: 50)\n     */\n    constructor(options) {\n        this.hashStore = {};\n        this.options = options || {};\n        if (this.options.asyncResponses === undefined) {\n            this.options.asyncResponses = false;\n        }\n        if (this.options.asyncTimeout === undefined) {\n            this.options.asyncTimeout = 50; // 50 ms default\n        }\n    }\n    /**\n     * Loads a serialized database from its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname) {\n        if (this.options.asyncResponses) {\n            return new Promise((resolve, reject) => {\n                setTimeout(() => {\n                    if (this.hashStore[dbname] !== undefined) {\n                        resolve(this.hashStore[dbname].value);\n                    }\n                    else {\n                        reject(null);\n                    }\n                }, this.options.asyncTimeout);\n            });\n        }\n        else {\n            if (this.hashStore[dbname] !== undefined) {\n                return Promise.resolve(this.hashStore[dbname].value);\n            }\n            else {\n                return Promise.reject(null);\n            }\n        }\n    }\n    /**\n     * Saves a serialized database to its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {string} dbstring - the database content\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname, dbstring) {\n        if (this.options.asyncResponses) {\n            return new Promise((resolve) => {\n                setTimeout(() => {\n                    const saveCount = (this.hashStore[dbname] !== undefined ? this.hashStore[dbname].savecount : 0);\n                    this.hashStore[dbname] = {\n                        savecount: saveCount + 1,\n                        lastsave: new Date(),\n                        value: dbstring\n                    };\n                    resolve();\n                }, this.options.asyncTimeout);\n                return Promise.resolve();\n            });\n        }\n        else {\n            const saveCount = (this.hashStore[dbname] !== undefined ? this.hashStore[dbname].savecount : 0);\n            this.hashStore[dbname] = {\n                savecount: saveCount + 1,\n                lastsave: new Date(),\n                value: dbstring\n            };\n            return Promise.resolve();\n        }\n    }\n    /**\n     * Deletes a database from its in-memory store.\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname) {\n        delete this.hashStore[dbname];\n        return Promise.resolve();\n    }\n}\n\n// CONCATENATED MODULE: ./packages/memory-storage/src/index.ts\n/* concated harmony reexport */__webpack_require__.d(__webpack_exports__, \"MemoryStorage\", function() { return memory_storage_MemoryStorage; });\n\n\n/* harmony default export */ var src = __webpack_exports__[\"default\"] = (memory_storage_MemoryStorage);\n\n\n/***/ }),\n/* 2 */\n/***/ (function(module, exports) {\n\nvar g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || Function(\"return this\")() || (1, eval)(\"this\");\n} catch (e) {\n\t// This works if the window reference is available\n\tif (typeof window === \"object\") g = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n\n\n/***/ })\n/******/ ]);\n});\n//# sourceMappingURL=lokidb.memory-storage.js.map"
  },
  {
    "path": "dist/packages/memory-storage/types/common/plugin.d.ts",
    "content": "/**\n * @hidden\n */\nexport declare const PLUGINS: void;\n"
  },
  {
    "path": "dist/packages/memory-storage/types/common/types.d.ts",
    "content": "/**\n * @hidden\n */\nimport { Loki } from \"../loki/src/loki\";\nexport interface StorageAdapter {\n    loadDatabase(dbname: string): Promise<any>;\n    saveDatabase?(dbname: string, serialization: string): Promise<void>;\n    deleteDatabase?(dbname: string): Promise<void>;\n    mode?: string;\n    exportDatabase?(dbname: string, dbref: Loki): Promise<void>;\n}\nexport declare type Doc<T extends object = object> = T & {\n    $loki: number;\n    meta?: {\n        created: number;\n        revision: number;\n        version: number;\n        updated?: number;\n    };\n};\nexport interface Dict<T> {\n    [index: string]: T;\n    [index: number]: T;\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/fs-storage/src/fs_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists using node fs module.\n */\nexport declare class FSStorage implements StorageAdapter {\n    /**\n     * Registers the fs storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the fs storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * Load data from file, will throw an error if the file does not exist\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Save data to file, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Delete the database file, will throw an error if the\n     * file can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/fs-storage/src/index.d.ts",
    "content": "import { FSStorage } from \"./fs_storage\";\nexport { FSStorage };\nexport default FSStorage;\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search/src/analyzer/analyzer.d.ts",
    "content": "import { CharacterFilter } from \"./character_filter\";\nimport { Tokenizer, whitespaceTokenizer } from \"./tokenizer\";\nimport { lowercaseTokenFilter, TokenFilter } from \"./token_filter\";\n/**\n * A analyzer converts a string into tokens which are added to the inverted index for searching.\n */\nexport interface Analyzer {\n    /**\n     * The character filters of the analyzer.\n     */\n    char_filter?: CharacterFilter[];\n    /**\n     * The tokenizer of the analyzer.\n     */\n    tokenizer: Tokenizer;\n    /**\n     * The token filters of the analyzer.\n     */\n    token_filter?: TokenFilter[];\n}\n/**\n * Analyzes a given string.\n * @param {Analyzer} analyzer - the analyzer\n * @param {string} str - the string\n * @returns {string[]} - the tokens\n */\nexport declare function analyze(analyzer: Analyzer, str: string): string[];\n/**\n * An analyzer with the whitespace tokenizer and the lowercase token filter.\n */\nexport declare class StandardAnalyzer implements Analyzer {\n    tokenizer: typeof whitespaceTokenizer;\n    token_filter: (typeof lowercaseTokenFilter)[];\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search/src/analyzer/character_filter.d.ts",
    "content": "/**\n * A character filter is used to preprocess a string before it is passed to a tokenizer.\n */\nexport declare type CharacterFilter = (value: string) => string;\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search/src/analyzer/token_filter.d.ts",
    "content": "/**\n * A token filter takes tokens from a tokenizer and modify, delete or add tokens.\n */\nexport declare type TokenFilter = (value: string, index: number, array: string[]) => string;\n/**\n * Converts a token to lowercase.\n * @param {string} token - the token\n * @returns {string} - the lowercased token\n */\nexport declare function lowercaseTokenFilter(token: string): string;\n/**\n * Converts a token to uppercase.\n * @param {string} token - the token\n * @returns {string} - the uppercased token\n */\nexport declare function uppercaseTokenFilter(token: string): string;\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search/src/analyzer/tokenizer.d.ts",
    "content": "/**\n * A tokenizer splits a string into individual tokens.\n */\nexport declare type Tokenizer = (value: string) => string[];\n/**\n * Splits a string at whitespace characters into tokens.\n * @param {string} value - the string\n * @returns {string[]} - the tokens\n */\nexport declare function whitespaceTokenizer(value: string): string[];\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search/src/full_text_search.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\nimport { Scorer } from \"./scorer\";\nimport { Analyzer } from \"./analyzer/analyzer\";\nexport declare class FullTextSearch {\n    private _id;\n    private _docs;\n    private _idxSearcher;\n    private _invIdxs;\n    /**\n     * Registers the full-text search as plugin.\n     */\n    static register(): void;\n    /**\n     * Initialize the full-text search for the given fields.\n     * @param {object[]} fieldOptions - the field options\n     * @param {string} fieldOptions.field - the name of the property field\n     * @param {boolean=true} fieldOptions.store - flag to indicate if the full-text search should be stored on serialization or\n     *  rebuild on deserialization\n     * @param {boolean=true} fieldOptions.optimizeChanges - flag to optimize updating and deleting of documents\n     *    (requires more memory but performs faster)\n     * @param {Analyzer} fieldOptions.analyzer - an analyzer for the field\n     * @param {string} [id] - the property name of the document index\n     */\n    constructor(fieldOptions?: FullTextSearch.FieldOptions[], id?: string);\n    addDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    removeDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    updateDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    clear(): void;\n    search(query: Query): Scorer.ScoreResults;\n    toJSON(): FullTextSearch.Serialization;\n    static fromJSONObject(serialized: FullTextSearch.Serialization, analyzers?: Dict<Analyzer>): FullTextSearch;\n}\nexport declare namespace FullTextSearch {\n    interface FieldOptions extends InvertedIndex.FieldOptions {\n        field: string;\n    }\n    interface Serialization {\n        id: string;\n        ii: Dict<InvertedIndex.Serialization>;\n    }\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search/src/fuzzy/automaton.d.ts",
    "content": "/**\n * Transition with dest, min and max.\n * @hidden\n */\nexport declare type Transition = [number, number, number];\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MIN_CODE_POINT = 0;\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MAX_CODE_POINT = 1114111;\n/**\n * From org/apache/lucene/util/automaton/Automaton.java\n * @hidden\n */\nexport declare class Automaton {\n    private _stateTransitions;\n    private _accept;\n    private _nextState;\n    private _currState;\n    private _transitions;\n    constructor();\n    isAccept(n: number): boolean;\n    createState(): number;\n    setAccept(state: number, accept: boolean): void;\n    finishState(): void;\n    private _finishCurrentState();\n    getStartPoints(): number[];\n    step(state: number, label: number): number;\n    getNumStates(): number;\n    addTransition(source: number, dest: number, min: number, max: number): void;\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search/src/fuzzy/lev1t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev1TParametricDescription.java\n * @hidden\n */\nexport declare class Lev1TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search/src/fuzzy/lev2t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev2TParametricDescription.java\n * @hidden\n */\nexport declare class Lev2TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search/src/fuzzy/levenshtein_automata.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java\n * @hidden\n */\nexport declare class LevenshteinAutomata {\n    private _word;\n    private _numRanges;\n    private _rangeLower;\n    private _rangeUpper;\n    private _description;\n    private _alphabet;\n    private _editDistance;\n    constructor(input: number[], editDistance: number);\n    /**\n     * Transforms the NDFA to a DFA.\n     * @returns {Automaton}\n     */\n    toAutomaton(): Automaton;\n    private _getVector(x, pos, end);\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search/src/fuzzy/long.d.ts",
    "content": "/**\n * Class supports 64Bit integer operations.\n * A cut-down version of dcodeIO/long.js.\n * @hidden\n */\nexport declare class Long {\n    private _low;\n    private _high;\n    constructor(low?: number, high?: number);\n    /**\n     * Returns this long with bits arithmetically shifted to the right by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftRight(numBits: number): Long;\n    /**\n     * Returns this long with bits arithmetically shifted to the left by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftLeft(numBits: number): Long;\n    /**\n     * Returns the bitwise AND of this Long and the specified.\n     * @param {Long} other - the other Long\n     * @returns {Long} the long\n     */\n    and(other: Long): Long;\n    /**\n     * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.\n     * @returns {number}\n     */\n    toInt(): number;\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search/src/fuzzy/parametric_description.d.ts",
    "content": "import { Long } from \"./long\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java#ParametricDescription\n * @hidden\n */\nexport declare class ParametricDescription {\n    protected _w: number;\n    private _n;\n    private _minErrors;\n    constructor(w: number, n: number, minErrors: number[]);\n    /**\n     * Return the number of states needed to compute a Levenshtein DFA\n     */\n    size(): number;\n    /**\n     * Returns true if the <code>state</code> in any Levenshtein DFA is an accept state (final state).\n     */\n    isAccept(absState: number): boolean;\n    /**\n     * Returns the position in the input word for a given <code>state</code>.\n     * This is the minimal boundary for the state.\n     */\n    getPosition(absState: number): number;\n    static unpack(data: Long[], index: number, bitsPerValue: number): number;\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search/src/fuzzy/run_automaton.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/RunAutomaton.java\n * @hidden\n */\nexport declare class RunAutomaton {\n    private _points;\n    private _accept;\n    private _transitions;\n    private _classmap;\n    constructor(automaton: Automaton);\n    getCharClass(c: number): number;\n    step(state: number, c: number): number;\n    isAccept(state: number): boolean;\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search/src/index.d.ts",
    "content": "import { FullTextSearch } from \"./full_text_search\";\nimport { analyze, StandardAnalyzer } from \"./analyzer/analyzer\";\nimport { whitespaceTokenizer } from \"./analyzer/tokenizer\";\nimport { lowercaseTokenFilter, uppercaseTokenFilter } from \"./analyzer/token_filter\";\nexport { FullTextSearch, analyze, StandardAnalyzer, whitespaceTokenizer, lowercaseTokenFilter, uppercaseTokenFilter };\nexport default FullTextSearch;\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search/src/index_searcher.d.ts",
    "content": "import { Scorer } from \"./scorer\";\nimport { InvertedIndex } from \"./inverted_index\";\nimport { Query } from \"./query_types\";\nimport { Dict } from \"../../common/types\";\n/**\n * @hidden\n */\nexport declare class IndexSearcher {\n    private _invIdxs;\n    private _docs;\n    private _scorer;\n    /**\n     * Constructs an index searcher.\n     * @param {Dict<InvertedIndex>} invIdxs - the inverted indexes\n     * @param {Set<number>} docs - the ids of the documents\n     */\n    constructor(invIdxs: Dict<InvertedIndex>, docs: Set<InvertedIndex.DocumentIndex>);\n    search(query: Query): Scorer.ScoreResults;\n    setDirty(): void;\n    private _recursive(query, doScoring);\n    private _getUnique(queries, doScoring, queryResults);\n    private _getAll(queries, doScoring, queryResults?);\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search/src/inverted_index.d.ts",
    "content": "import { Analyzer } from \"./analyzer/analyzer\";\n/**\n * Converts a string into an array of code points.\n * @param str - the string\n * @returns {number[]} to code points\n * @hidden\n */\nexport declare function toCodePoints(str: string): number[];\n/**\n * Inverted index class handles featured text search for specific document fields.\n * @hidden\n */\nexport declare class InvertedIndex {\n    analyzer: Analyzer;\n    docCount: number;\n    docStore: Map<InvertedIndex.DocumentIndex, InvertedIndex.DocStore>;\n    totalFieldLength: number;\n    root: InvertedIndex.Index;\n    private _store;\n    private _optimizeChanges;\n    /**\n     * @param {boolean} [options.store=true] - inverted index will be stored at serialization rather than rebuilt on load\n     * @param {boolean} [options.optimizeChanges=true] - flag to store additional metadata inside the index for better\n     *  performance if an existing field is updated or removed\n     * @param {Analyzer} [options.analyzer=] - the analyzer of this inverted index\n     */\n    constructor(options?: InvertedIndex.FieldOptions);\n    /**\n     * Adds defined fields of a document to the inverted index.\n     * @param {string} field - the field to add\n     * @param {number} docId - the doc id of the field\n     */\n    insert(field: string, docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Removes all relevant terms of a document from the inverted index.\n     * @param {number} docId - the document.\n     */\n    remove(docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Gets the term index of a term.\n     * @param {string} term - the term\n     * @param {object} root - the term index to start from\n     * @param {number} start - the position of the term string to start from\n     * @return {object} - The term index or null if the term is not in the term tree.\n     */\n    static getTermIndex(term: number[], root: InvertedIndex.Index, start?: number): InvertedIndex.Index;\n    /**\n     * Extends a term index to all available term leafs.\n     * @param {object} idx - the term index to start from\n     * @param {number[]} [term=[]] - the current term\n     * @param {Array} termIndices - all extended indices with their term\n     * @returns {Array} - Array with term indices and extension\n     */\n    static extendTermIndex(idx: InvertedIndex.Index, term?: number[], termIndices?: InvertedIndex.IndexTerm[]): InvertedIndex.IndexTerm[];\n    /**\n     * Serialize the inverted index.\n     * @returns {{docStore: *, _fields: *, index: *}}\n     */\n    toJSON(): InvertedIndex.Serialization;\n    /**\n     * Deserialize the inverted index.\n     * @param {{docStore: *, _fields: *, index: *}} serialized - The serialized inverted index.\n     * @param {Analyzer} analyzer[undefined] - an analyzer\n     */\n    static fromJSONObject(serialized: InvertedIndex.Serialization, analyzer?: Analyzer): InvertedIndex;\n    private static _serializeIndex(idx);\n    private static _deserializeIndex(serialized);\n    /**\n     * Set parent of to each index and regenerate the indexRef.\n     * @param {Index} index - the index\n     * @param {Index} parent - the parent\n     */\n    private _regenerate(index, parent);\n    /**\n     * Iterate over the whole inverted index and remove the document.\n     * Delete branch if not needed anymore.\n     * Function is needed if index is used without optimization.\n     * @param {Index} idx - the index\n     * @param {number} docId - the doc id\n     * @returns {boolean} true if index is empty\n     */\n    private _remove(idx, docId);\n}\nexport declare namespace InvertedIndex {\n    interface FieldOptions {\n        store?: boolean;\n        optimizeChanges?: boolean;\n        analyzer?: Analyzer;\n    }\n    type Index = Map<number, any> & {\n        dc?: Map<DocumentIndex, number>;\n        df?: number;\n        pa?: Index;\n    };\n    type IndexTerm = {\n        index: Index;\n        term: number[];\n    };\n    interface SerializedIndex {\n        d?: {\n            df: number;\n            dc: [DocumentIndex, number][];\n        };\n        k?: number[];\n        v?: SerializedIndex[];\n    }\n    type Serialization = SpareSerialization | FullSerialization;\n    type SpareSerialization = {\n        _store: false;\n        _optimizeChanges: boolean;\n    };\n    type FullSerialization = {\n        _store: true;\n        _optimizeChanges: boolean;\n        docCount: number;\n        docStore: [DocumentIndex, DocStore][];\n        totalFieldLength: number;\n        root: SerializedIndex;\n    };\n    interface DocStore {\n        fieldLength?: number;\n        indexRef?: Index[];\n    }\n    type DocumentIndex = number | string;\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search/src/query_types.d.ts",
    "content": "/**\n * Base query to enable boost to a query type.\n */\nexport interface BaseQuery<Type> {\n    type: Type;\n    boost?: number;\n}\n/**\n * A query which finds documents where a document field contains a term.\n */\nexport interface TermQuery extends BaseQuery<\"term\"> {\n    field: string;\n    value: string;\n}\n/**\n * A query which finds documents where a document field contains any of the terms.\n */\nexport interface TermsQuery extends BaseQuery<\"terms\"> {\n    field: string;\n    value: string[];\n}\n/**\n * A query which finds documents where the wildcard term can be applied at an existing document field term.\n */\nexport interface WildcardQuery extends BaseQuery<\"wildcard\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which finds documents where the fuzzy term can be transformed into an existing document field term within a\n * given edit distance.\n */\nexport interface FuzzyQuery extends BaseQuery<\"fuzzy\"> {\n    field: string;\n    value: string;\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query which matches documents containing the prefix of a term inside a field.\n */\nexport interface PrefixQuery extends BaseQuery<\"prefix\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which matches all documents with a given field.\n */\nexport interface ExistsQuery extends BaseQuery<\"exists\"> {\n    field: string;\n}\n/**\n * A query which tokenizes the given text into tokens and performs a sub query for each token. The results are combined\n * using a boolean operator.\n */\nexport interface MatchQuery extends BaseQuery<\"match\"> {\n    field: string;\n    value: string;\n    minimum_should_match?: number | string;\n    operator?: \"and\" | \"or\";\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query that matches all documents and giving them a constant score equal to the query boost.\n*/\nexport interface MatchQueryAll extends BaseQuery<\"match_all\"> {\n}\n/**\n * A query that wraps sub queries and returns a constant score equal to the query boost for every document in the filter.\n */\nexport interface ConstantScoreQuery extends BaseQuery<\"constant_score\"> {\n    filter: QueryTypes[];\n}\n/**\n * A query that matches documents matching boolean combinations of sub queries.\n */\nexport interface BoolQuery extends BaseQuery<\"bool\"> {\n    must?: QueryTypes[];\n    filter?: QueryTypes[];\n    should?: QueryTypes[];\n    not?: QueryTypes[];\n    minimum_should_match?: number | string;\n}\n/**\n * Union type of possible query types.\n */\nexport declare type QueryTypes = BoolQuery | ConstantScoreQuery | TermQuery | TermsQuery | WildcardQuery | FuzzyQuery | MatchQuery | MatchQueryAll | PrefixQuery | ExistsQuery;\n/**\n * The main query with the actually full-text search query and the scoring parameters.\n */\nexport interface Query {\n    query: QueryTypes;\n    calculate_scoring?: boolean;\n    explain?: boolean;\n    bm25?: {\n        k1: number;\n        b: number;\n    };\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search/src/scorer.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\n/**\n * @hidden\n */\nexport declare class Scorer {\n    private _invIdxs;\n    private _cache;\n    constructor(invIdxs: Dict<InvertedIndex>);\n    setDirty(): void;\n    score(fieldName: string, boost: number, termIdx: InvertedIndex.Index, doScoring: boolean | null, queryResults: Scorer.QueryResults, term: number[], df?: number): void;\n    scoreConstant(boost: number, docId: InvertedIndex.DocumentIndex, queryResults: Scorer.QueryResults): Scorer.QueryResults;\n    finalScore(query: Query, queryResults: Scorer.QueryResults): Scorer.ScoreResults;\n    private static _calculateFieldLength(fieldLength);\n    private _getCache(fieldName);\n    /**\n     * Returns the idf by either calculate it or use a cached one.\n     * @param {string} fieldName - the name of the field\n     * @param {number} docFreq - the doc frequency of the term\n     * @returns {number} the idf\n     * @private\n     */\n    private _idf(fieldName, docFreq);\n    private _avgFieldLength(fieldName);\n}\nexport declare namespace Scorer {\n    interface IDFCache {\n        idfs: Dict<number>;\n        avgFieldLength: number;\n    }\n    interface QueryResult {\n        tf?: number;\n        idf?: number;\n        boost: number;\n        fieldName?: string;\n        term?: number[];\n    }\n    type QueryResults = Map<InvertedIndex.DocumentIndex, QueryResult[]>;\n    interface BM25Explanation {\n        boost: number;\n        score: number;\n        docID: number;\n        fieldName: string;\n        index: string;\n        idf: number;\n        tfNorm: number;\n        tf: number;\n        fieldLength: number;\n        avgFieldLength: number;\n    }\n    interface ConstantExplanation {\n        boost: number;\n        score: number;\n    }\n    type ScoreExplanation = BM25Explanation | ConstantExplanation;\n    type ScoreResult = {\n        score: number;\n        explanation?: ScoreExplanation[];\n    };\n    type ScoreResults = Dict<ScoreResult>;\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search-language/src/index.d.ts",
    "content": "export { generateStopWordFilter, generateTrimmer, Among, SnowballProgram } from \"./language\";\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search-language/src/language.d.ts",
    "content": "export declare function generateTrimmer(wordCharacters: string): (token: string) => string;\nexport declare function generateStopWordFilter(stopWords: string[]): (token: string) => string;\nexport declare class Among {\n    s_size: number;\n    s: number[];\n    substring_i: number;\n    result: number;\n    method: any;\n    constructor(s: string, substring_i: number, result: number, method?: any);\n}\nexport declare class SnowballProgram {\n    current: string;\n    bra: number;\n    ket: number;\n    limit: number;\n    cursor: number;\n    limit_backward: number;\n    constructor();\n    setCurrent(word: string): void;\n    getCurrent(): string;\n    in_grouping(s: number[], min: number, max: number): boolean;\n    in_grouping_b(s: number[], min: number, max: number): boolean;\n    out_grouping(s: number[], min: number, max: number): boolean;\n    out_grouping_b(s: number[], min: number, max: number): boolean;\n    eq_s(s_size: number, s: string): boolean;\n    eq_s_b(s_size: number, s: string): boolean;\n    find_among(v: Among[], v_size: number): number;\n    find_among_b(v: Among[], v_size: number): number;\n    replace_s(c_bra: number, c_ket: number, s: string): number;\n    slice_check(): void;\n    slice_from(s: string): void;\n    slice_del(): void;\n    insert(c_bra: number, c_ket: number, s: string): void;\n    slice_to(): string;\n    eq_v_b(s: string): boolean;\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search-language-de/src/german_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class GermanAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search-language-de/src/index.d.ts",
    "content": "import { GermanAnalyzer } from \"./german_analyzer\";\nexport { GermanAnalyzer };\nexport default GermanAnalyzer;\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search-language-en/src/english_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class EnglishAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/full-text-search-language-en/src/index.d.ts",
    "content": "import { EnglishAnalyzer } from \"./english_analyzer\";\nexport { EnglishAnalyzer };\nexport default EnglishAnalyzer;\n"
  },
  {
    "path": "dist/packages/memory-storage/types/indexed-storage/src/index.d.ts",
    "content": "import { IndexedStorage } from \"./indexed_storage\";\nexport { IndexedStorage };\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/memory-storage/types/indexed-storage/src/indexed_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * Loki persistence adapter class for indexedDb.\n *     This class fulfills abstract adapter interface which can be applied to other storage methods.\n *     Utilizes the included LokiCatalog app/key/value database for actual database persistence.\n *     IndexedDb storage is provided per-domain, so we implement app/key/value database to\n *     allow separate contexts for separate apps within a domain.\n */\nexport declare class IndexedStorage implements StorageAdapter {\n    private _appname;\n    private catalog;\n    /**\n     * Registers the indexed storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the indexed storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {string} [appname=loki] - Application name context can be used to distinguish subdomains, \"loki\" by default\n     */\n    constructor(appname?: string);\n    /**\n     * Retrieves a serialized db string from the catalog.\n     *\n     * @example\n     * // LOAD\n     * var idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * var db = new loki(\"test\", { adapter: idbAdapter });\n     *   db.base(function(result) {\n       *   console.log(\"done\");\n       * });\n     *\n     * @param {string} dbname - the name of the database to retrieve.\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<{}>;\n    /**\n     * Saves a serialized db to the catalog.\n     *\n     * @example\n     * // SAVE : will save App/Key/Val as \"finance\"/\"test\"/{serializedDb}\n     * let idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * let db = new loki(\"test\", { adapter: idbAdapter });\n     * let coll = db.addCollection(\"testColl\");\n     * coll.insert({test: \"val\"});\n     * db.saveDatabase();  // could pass callback if needed for async complete\n     *\n     * @param {string} dbname - the name to give the serialized database within the catalog.\n     * @param {string} dbstring - the serialized db string to save.\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a serialized db from the catalog.\n     *\n     * @example\n     * // DELETE DATABASE\n     * // delete \"finance\"/\"test\" value from catalog\n     * idbAdapter.deleteDatabase(\"test\", function {\n       *   // database deleted\n       * });\n     *\n     * @param {string} dbname - the name of the database to delete from the catalog.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n    /**\n     * Removes all database partitions and pages with the base filename passed in.\n     * This utility method does not (yet) guarantee async deletions will be completed before returning\n     *\n     * @param {string} dbname - the base filename which container, partitions, or pages are derived\n     */\n    deleteDatabasePartitions(dbname: string): void;\n    /**\n     * Retrieves object array of catalog entries for current app.\n     *\n     * @example\n     * idbAdapter.getDatabaseList(function(result) {\n       *   // result is array of string names for that appcontext (\"finance\")\n       *   result.forEach(function(str) {\n       *     console.log(str);\n       *   });\n       * });\n     *\n     * @param {function} callback - should accept array of database names in the catalog for current app.\n     */\n    getDatabaseList(callback: (names: string[]) => void): void;\n    /**\n     * Allows retrieval of list of all keys in catalog along with size\n     * @param {function} callback - (Optional) callback to accept result array.\n     */\n    getCatalogSummary(callback: (entry: Entry[]) => void): void;\n}\nexport interface Entry {\n    app: string;\n    key: string;\n    size: number;\n}\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/memory-storage/types/local-storage/src/index.d.ts",
    "content": "import { LocalStorage } from \"./local_storage\";\nexport { LocalStorage };\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/memory-storage/types/local-storage/src/local_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists to web browser's local storage object\n * @constructor LocalStorageAdapter\n */\nexport declare class LocalStorage implements StorageAdapter {\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * loadDatabase() - Load data from localstorage\n     * @param {string} dbname - the name of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * saveDatabase() - save data to localstorage, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was saved\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * deleteDatabase() - delete the database from localstorage, will throw an error if it\n     * can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/memory-storage/types/loki/src/avl_index.d.ts",
    "content": "import { IRangedIndex, IRangedIndexRequest } from \"./ranged_indexes\";\nimport { ILokiComparer } from \"./comparators\";\n/**\n * Treenode type for binary search tree (BST) implementation.\n *\n * To support duplicates, we may need to either repurpose parent to\n * point to 'elder' sibling or add a siblingId to point to owner of\n * node represented in tree.\n */\nexport declare type TreeNode<T> = {\n    id: number;\n    value: T;\n    parent: number | null;\n    balance: number;\n    height: number;\n    left: number | null;\n    right: number | null;\n    siblings: number[];\n};\nexport interface ITreeNodeHash<T> {\n    [id: number]: TreeNode<T>;\n}\n/**\n * LokiDB AVL Balanced Binary Tree Index implementation.\n * To support duplicates, we use siblings (array) in tree nodes.\n * Basic AVL components guided by William Fiset tutorials at :\n * https://github.com/williamfiset/data-structures/blob/master/com/williamfiset/datastructures/balancedtree/AVLTreeRecursive.java\n * https://www.youtube.com/watch?v=g4y2h70D6Nk&list=PLDV1Zeh2NRsD06x59fxczdWLhDDszUHKt\n */\nexport declare class AvlTreeIndex<T> implements IRangedIndex<T> {\n    name: string;\n    comparator: ILokiComparer<T>;\n    nodes: ITreeNodeHash<T>;\n    apex: number | null;\n    /**\n     * Initializes index with property name and a comparer function.\n     */\n    constructor(name: string, comparator: ILokiComparer<T>);\n    backup(): AvlTreeIndex<T>;\n    restore(tree: AvlTreeIndex<T>): void;\n    /**\n     * Used for inserting a new value into the BinaryTreeIndex\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val Value to be indexed and inserted into binary tree\n     */\n    insert(id: number, val: T): void;\n    /**\n     * Recursively inserts a treenode and re-balances if needed.\n     * @param current\n     * @param node\n     */\n    insertNode(current: TreeNode<T>, node: TreeNode<T>): number;\n    /**\n     * Updates height and balance (calculation) for tree node\n     * @param node\n     */\n    private updateBalance(node);\n    /**\n     * Balance the 'double left-heavy' condition\n     * @param node\n     */\n    private leftLeftCase(node);\n    /**\n     * Balance the '(parent) left heavy, (child) right heavy' condition\n     * @param node\n     */\n    private leftRightCase(node);\n    /**\n     * Balance the 'double right-heavy' condition\n     * @param node\n     */\n    private rightRightCase(node);\n    /**\n     * Balance the '(parent) right heavy, (child) left heavy' condition\n     * @param node\n     */\n    private rightLeftCase(node);\n    /**\n     * Left rotation of node. Swaps right child into current location.\n     * @param node\n     */\n    private rotateLeft(node);\n    /**\n     * Right rotation of node. Swaps left child into current location.\n     * @param node\n     */\n    private rotateRight(node);\n    /**\n     * Diagnostic method for examining tree contents and structure\n     * @param node\n     */\n    getValuesAsTree(node?: TreeNode<T>): any;\n    /**\n     * Updates a value, possibly relocating it, within binary tree\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val New value to be indexed within binary tree\n     */\n    update(id: number, val: T): void;\n    /**\n     * Removes a value from the binary tree index\n     * @param id\n     */\n    remove(id: number): void;\n    /**\n     * Recursive node removal and rebalancer\n     * @param node\n     * @param val\n     */\n    private removeNode(node, id);\n    /**\n     * Utility method for updating a parent's child link when it changes\n     * @param parentId\n     * @param oldChildId\n     * @param newChildId\n     */\n    private updateChildLink(parentId, oldChildId, newChildId);\n    /**\n     * When removing a parent with only child, this does simple remap of child to grandParent.\n     * @param grandParent New parent of 'child'.\n     * @param parent Node being removed.\n     * @param child Node to reparent to grandParent.\n     */\n    private promoteChild(parent, child);\n    /**\n     * Finds a successor to a node and replaces that node with it.\n     * @param node\n     */\n    private promoteSuccessor(node);\n    /**\n     * Utility method for finding In-Order predecessor to the provided node\n     * @param node Parent node to find leaf node of greatest 'value'\n    */\n    private findGreaterLeaf(node);\n    /**\n     * Utility method for finding In-Order successor to the provided node\n     * @param node Parent Node to find leaf node of least 'value'\n     */\n    private findLesserLeaf(node);\n    /**\n     *  Interface method to support ranged queries.  Results sorted by index property.\n     * @param range Options for ranged request.\n     */\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    /**\n     * Implements ranged request operations.\n     * @param node\n     * @param range\n     */\n    private collateRequest(node, range);\n    /**\n     * Used on a branch node to return an array of id within that branch, sorted by their value\n     * @param node\n     */\n    private collateIds(node);\n    /**\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    /**\n     * Inline/Non-recusive 'single value' ($eq) lookup.\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    private locate(node, val);\n    /**\n     * Index integrity check (IRangedIndex interface function)\n     */\n    validateIndex(): boolean;\n    /**\n     * Recursive Node validation routine\n     * @param node\n     */\n    private validateNode(node);\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/loki/src/clone.d.ts",
    "content": "export declare type CloneMethod = \"parse-stringify\" | \"deep\" | \"shallow\" | \"shallow-recurse\";\n/**\n * @hidden\n */\nexport declare function clone<T>(data: T, method?: CloneMethod): T;\n"
  },
  {
    "path": "dist/packages/memory-storage/types/loki/src/collection.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { UniqueIndex } from \"./unique_index\";\nimport { ResultSet } from \"./result_set\";\nimport { DynamicView } from \"./dynamic_view\";\nimport { IRangedIndex } from \"./ranged_indexes\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc, Dict } from \"../../common/types\";\nimport { FullTextSearch } from \"../../full-text-search/src/full_text_search\";\nimport { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\n/**\n * Collection class that handles documents of same type\n * @extends LokiEventEmitter\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class Collection<TData extends object = object, TNested extends object = object, T extends TData & TNested = TData & TNested> extends LokiEventEmitter {\n    name: string;\n    _data: Doc<T>[];\n    private _idIndex;\n    _rangedIndexes: {\n        [P in keyof T]?: Collection.RangedIndexMeta;\n    };\n    _lokimap: {\n        [$loki: number]: Doc<T>;\n    };\n    _unindexedSortComparator: string;\n    _defaultLokiOperatorPackage: string;\n    /**\n     * Unique constraints contain duplicate object references, so they are not persisted.\n     * We will keep track of properties which have unique constraints applied here, and regenerate on load.\n     */\n    _constraints: {\n        unique: {\n            [P in keyof T]?: UniqueIndex;\n        };\n    };\n    /**\n     * Transforms will be used to store frequently used query chains as a series of steps which itself can be stored along\n     * with the database.\n     */\n    _transforms: Dict<Collection.Transform<T>[]>;\n    /**\n     * In autosave scenarios we will use collection level dirty flags to determine whether save is needed.\n     * currently, if any collection is dirty we will autosave the whole database if autosave is configured.\n     * Defaulting to true since this is called from addCollection and adding a collection should trigger save.\n     */\n    _dirty: boolean;\n    private _cached;\n    /**\n     * Is collection transactional.\n     */\n    private _transactional;\n    /**\n     * Options to clone objects when inserting them.\n     */\n    _cloneObjects: boolean;\n    /**\n     * Default clone method (if enabled) is parse-stringify.\n     */\n    _cloneMethod: CloneMethod;\n    /**\n     * If set to true we will not maintain a meta property for a document.\n     */\n    private _disableMeta;\n    /**\n     * Disable track changes.\n     */\n    private _disableChangesApi;\n    /**\n     * Disable delta update object style on changes.\n     */\n    _disableDeltaChangesApi: boolean;\n    /**\n     * By default, if you insert a document with a Date value for an indexed property, we will convert that value to number.\n     */\n    private _serializableIndexes;\n    /**\n     * Name of path of used nested properties.\n     */\n    private _nestedProperties;\n    /**\n     * Option to activate a cleaner daemon - clears \"aged\" documents at set intervals.\n     */\n    _ttl: Collection.TTL;\n    private _maxId;\n    private _dynamicViews;\n    /**\n     * Changes are tracked by collection and aggregated by the db.\n     */\n    private _changes;\n    /**\n     * stages: a map of uniquely identified 'stages', which hold copies of objects to be\n     * manipulated without affecting the data in the original collection\n     */\n    private _stages;\n    private _commitLog;\n    _fullTextSearch: FullTextSearch;\n    /**\n     * @param {string} name - collection name\n     * @param {(object)} [options={}] - a configuration object\n     * @param {string[]} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {string[]} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {RangedIndexOptions} [options.rangedIndexes] - configuration object for ranged indexes\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are invoked asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes API\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {boolean} [options.serializableIndexes=true] - converts date values on binary indexed property values are serializable\n     * @param {string} [options.cloneMethod=\"deep\"] - the clone method\n     * @param {number} [options.transactional=false] - ?\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale.\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @param {string} [options.unindexedSortComparator=\"js\"] \"js\", \"abstract\", \"abstract-date\", \"loki\" or other registered comparator name\n     * @param {string} [options.defaultLokiOperatorPackage=\"js\"] \"js\", \"loki\", \"comparator\" (or user defined) query ops package\n     * @param {FullTextSearch.FieldOptions} [options.fullTextSearch=] - the full-text search options\n     * @see {@link Loki#addCollection} for normal creation of collections\n     */\n    constructor(name: string, options?: Collection.Options<TData, TNested>);\n    toJSON(): Collection.Serialized;\n    static fromJSONObject(obj: Collection.Serialized, options?: Collection.DeserializeOptions): Collection<any, object, any>;\n    /**\n     * Adds a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {array} transform - an array of transformation 'step' objects to save into the collection\n     */\n    addTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Retrieves a named transform from the collection.\n     * @param {string} name - name of the transform to lookup.\n     */\n    getTransform(name: string): Collection.Transform<T>[];\n    /**\n     * Updates a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {object} transform - a transformation object to save into collection\n     */\n    setTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Removes a named collection transform from the collection\n     * @param {string} name - name of collection transform to remove\n     */\n    removeTransform(name: string): void;\n    private setTTL(age, interval);\n    /**\n     * Create a row filter that covers all documents in the collection.\n     */\n    _prepareFullDocIndex(): number[];\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field\n     * @param indexTypeName\n     * @param comparatorName\n     */\n    ensureIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field Property to create an index on (need to look into contraining on keyof T)\n     * @param indexTypeName Name of IndexType factory within (global?) hashmap to create IRangedIndex from\n     * @param comparatorName Name of Comparator within (global?) hashmap\n     */\n    ensureRangedIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    ensureUniqueIndex(field: keyof T): UniqueIndex;\n    /**\n     * Quickly determine number of documents in collection (or query)\n     * @param {object} query - (optional) query object to count results of\n     * @returns {number} number of documents in the collection\n     */\n    count(query?: ResultSet.Query<Doc<T>>): number;\n    /**\n     * Rebuild idIndex\n     */\n    private _ensureId();\n    /**\n     * Add a dynamic view to the collection\n     * @param {string} name - name of dynamic view to add\n     * @param {object} options - (optional) options to configure dynamic view with\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=SortPriority.PASSIVE] - the sort priority\n     * @param {number} options.minRebuildInterval - minimum rebuild interval (need clarification to docs here)\n     * @returns {DynamicView} reference to the dynamic view added\n     **/\n    addDynamicView(name: string, options?: DynamicView.Options): DynamicView<T>;\n    /**\n     * Remove a dynamic view from the collection\n     * @param {string} name - name of dynamic view to remove\n     **/\n    removeDynamicView(name: string): void;\n    /**\n     * Look up dynamic view reference from within the collection\n     * @param {string} name - name of dynamic view to retrieve reference of\n     * @returns {DynamicView} A reference to the dynamic view with that name\n     **/\n    getDynamicView(name: string): DynamicView<T>;\n    /**\n     * Applies a 'mongo-like' find query object and passes all results to an update function.\n     * @param {object} filterObject - the 'mongo-like' query object\n     * @param {function} updateFunction - the update function\n     */\n    findAndUpdate(filterObject: ResultSet.Query<Doc<T>>, updateFunction: (obj: Doc<T>) => any): void;\n    /**\n     * Applies a 'mongo-like' find query object removes all documents which match that filter.\n     * @param {object} filterObject - 'mongo-like' query object\n     */\n    findAndRemove(filterObject: ResultSet.Query<Doc<T>>): void;\n    /**\n     * Adds object(s) to collection, ensure object(s) have meta properties, clone it if necessary, etc.\n     * @param {(object|array)} doc - the document (or array of documents) to be inserted\n     * @returns {(object|array)} document or documents inserted\n     */\n    insert(doc: TData): Doc<T>;\n    insert(doc: TData[]): Doc<T>[];\n    /**\n     * Adds a single object, ensures it has meta properties, clone it if necessary, etc.\n     * @param {object} doc - the document to be inserted\n     * @param {boolean} bulkInsert - quiet pre-insert and insert event emits\n     * @returns {object} document or 'undefined' if there was a problem inserting it\n     */\n    insertOne(doc: TData, bulkInsert?: boolean): Doc<T>;\n    /**\n     * Refers nested properties of an object to the root of it.\n     * @param {T} data - the object\n     * @returns {T & TNested} the object with nested properties\n     * @hidden\n     */\n    _defineNestedProperties<U extends TData>(data: U): U & TNested;\n    /**\n     * Empties the collection.\n     * @param {boolean} [removeIndices=false] - remove indices\n     */\n    clear({removeIndices: removeIndices}?: {\n        removeIndices?: boolean;\n    }): void;\n    /**\n     * Updates an object and notifies collection that the document has changed.\n     * @param {object} doc - document to update within the collection\n     */\n    update(doc: Doc<T> | Doc<T>[]): void;\n    /**\n     * Add object to collection\n     */\n    private _add(obj);\n    /**\n     * Applies a filter function and passes all results to an update function.\n     * @param {function} filterFunction - the filter function\n     * @param {function} updateFunction - the update function\n     */\n    updateWhere(filterFunction: (obj: Doc<T>) => boolean, updateFunction: (obj: Doc<T>) => Doc<T>): void;\n    /**\n     * Remove all documents matching supplied filter function.\n     * @param {function} filterFunction - the filter function\n     */\n    removeWhere(filterFunction: (obj: Doc<T>) => boolean): void;\n    removeDataOnly(): void;\n    /**\n     * Remove a document from the collection\n     * @param {number|object} doc - document to remove from collection\n     */\n    remove(doc: number | Doc<T> | Doc<T>[]): void;\n    /**\n     * Returns all changes.\n     * @returns {Collection.Change[]}\n     */\n    getChanges(): Collection.Change[];\n    /**\n     * Enables/disables changes api.\n     * @param {boolean} disableChangesApi\n     * @param {boolean} disableDeltaChangesApi\n     */\n    setChangesApi(disableChangesApi: boolean, disableDeltaChangesApi?: boolean): void;\n    /**\n     * Clears all the changes.\n     */\n    flushChanges(): void;\n    private _getObjectDelta(oldObject, newObject);\n    /**\n     * Compare changed object (which is a forced clone) with existing object and return the delta\n     */\n    private _getChangeDelta(obj, old);\n    /**\n     * Creates a clone of the current status of an object and associates operation and collection name,\n     * so the parent db can aggregate and generate a changes object for the entire db\n     */\n    private _createChange(name, op, obj, old?);\n    private _createInsertChange(obj);\n    private _createUpdateChange(obj, old);\n    private _insertMetaWithChange(obj);\n    private _updateMetaWithChange(obj, old);\n    private _insertMeta(obj);\n    private _updateMeta(obj);\n    /**\n     * Get by Id - faster than other methods because of the searching algorithm\n     * @param {int} id - $loki id of document you want to retrieve\n     * @param {boolean} returnPosition - if 'true' we will return [object, position]\n     * @returns {(object|array|null)} Object reference if document was found, null if not,\n     *     or an array if 'returnPosition' was passed.\n     */\n    get(id: number): Doc<T>;\n    get(id: number, returnPosition: boolean): Doc<T> | [Doc<T>, number];\n    /**\n     * Retrieve doc by Unique index\n     * @param {string} field - name of uniquely indexed property to use when doing lookup\n     * @param {any} value - unique value to search for\n     * @returns {object} document matching the value passed\n     */\n    by(field: keyof T, value: any): Doc<T>;\n    /**\n     * Find one object by index property, by property equal to value\n     * @param {object} query - query object used to perform search with\n     * @returns {(object|null)} First matching document, or null if none\n     */\n    findOne(query: ResultSet.Query<Doc<T>>): Doc<T>;\n    /**\n     * Chain method, used for beginning a series of chained find() and/or view() operations\n     * on a collection.\n     *\n     * @param {array} transform - Ordered array of transform step objects similar to chain\n     * @param {object} parameters - Object containing properties representing parameters to substitute\n     * @returns {ResultSet} (this) ResultSet, or data array if any map or join functions where called\n     */\n    chain(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Find method, api is similar to mongodb.\n     * for more complex queries use [chain()]{@link Collection#chain} or [where()]{@link Collection#where}.\n     * @example {@tutorial Query Examples}\n     * @param {object} query - 'mongo-like' query object\n     * @returns {array} Array of matching documents\n     */\n    find(query?: ResultSet.Query<Doc<T>>): Doc<T>[];\n    /**\n     * Find object by unindexed field by property equal to value,\n     * simply iterates and returns the first element matching the query\n     */\n    findOneUnindexed(prop: string, value: any): Doc<T>;\n    /**\n     * Transaction methods\n     */\n    /**\n     * start the transation\n     */\n    startTransaction(): void;\n    /**\n     * Commit the transaction.\n     */\n    commit(): void;\n    /**\n     * Rollback the transaction.\n     */\n    rollback(): void;\n    /**\n     * Query the collection by supplying a javascript filter function.\n     * @example\n     * let results = coll.where(function(obj) {\n       *   return obj.legs === 8;\n       * });\n     * @param {function} fun - filter function to run against all collection docs\n     * @returns {array} all documents which pass your filter function\n     */\n    where(fun: (obj: Doc<T>) => boolean): Doc<T>[];\n    /**\n     * Map Reduce operation\n     * @param {function} mapFunction - function to use as map function\n     * @param {function} reduceFunction - function to use as reduce function\n     * @returns {data} The result of your mapReduce operation\n     */\n    mapReduce<U1, U2>(mapFunction: (value: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Join two collections on specified properties\n     * @param {array} joinData - array of documents to 'join' to this collection\n     * @param {string} leftJoinProp - property name in collection\n     * @param {string} rightJoinProp - property name in joinData\n     * @param {function} mapFun - (Optional) map function to use\n     * @param dataOptions - options to data() before input to your map function\n     * @param [dataOptions.removeMeta] - allows removing meta before calling mapFun\n     * @param [dataOptions.forceClones] - forcing the return of cloned objects to your map object\n     * @param [dataOptions.forceCloneMethod] - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} Result of the mapping operation\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinProp: string | ((obj: any) => string), rightJoinProp: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * (Staging API) create a stage and/or retrieve it\n     */\n    getStage(name: string): any;\n    /**\n     * a collection of objects recording the changes applied through a commmitStage\n     */\n    /**\n     * (Staging API) create a copy of an object and insert it into a stage\n     */\n    stage<F extends TData>(stageName: string, obj: Doc<F>): F;\n    /**\n     * (Staging API) re-attach all objects to the original collection, so indexes and views can be rebuilt\n     * then create a message to be inserted in the commitlog\n     * @param {string} stageName - name of stage\n     * @param {string} message\n     */\n    commitStage(stageName: string, message: string): void;\n    /**\n     * Returns all values of a field.\n     * @param {string} field - the field name\n     * @return {any}: the array of values\n     */\n    extract(field: keyof T): any[];\n    /**\n     * Finds the minimum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the minimum value\n     */\n    min(field: keyof T): number;\n    /**\n     * Finds the maximum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the maximum value\n     */\n    max(field: keyof T): number;\n    /**\n     * Finds the minimum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    minRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Finds the maximum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    maxRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Returns all values of a field as numbers (if possible).\n     * @param {string} field - the field name\n     * @return {number[]} - the number array\n     */\n    extractNumerical(field: keyof T): number[];\n    /**\n     * Calculates the average numerical value of a field\n     * @param {string} field - the field name\n     * @returns {number} average of property in all docs in the collection\n     */\n    avg(field: keyof T): number;\n    /**\n     * Calculate the standard deviation of a field.\n     * @param {string} field - the field name\n     * @return {number} the standard deviation\n     */\n    stdDev(field: keyof T): number;\n    /**\n     * Calculates the mode of a field.\n     * @param {string} field - the field name\n     * @return {number} the mode\n     */\n    mode(field: keyof T): number;\n    /**\n     * Calculates the median of a field.\n     * @param {string} field - the field name\n     * @return {number} the median\n     */\n    median(field: keyof T): number;\n}\nexport declare namespace Collection {\n    interface Options<TData extends object, TNested extends object = {}, T extends object = TData & TNested> {\n        unique?: (keyof T)[];\n        unindexedSortComparator?: string;\n        defaultLokiOperatorPackage?: string;\n        rangedIndexes?: RangedIndexOptions;\n        serializableIndexes?: boolean;\n        asyncListeners?: boolean;\n        disableMeta?: boolean;\n        disableChangesApi?: boolean;\n        disableDeltaChangesApi?: boolean;\n        clone?: boolean;\n        serializableIndices?: boolean;\n        cloneMethod?: CloneMethod;\n        transactional?: boolean;\n        ttl?: number;\n        ttlInterval?: number;\n        nestedProperties?: (keyof TNested | {\n            name: keyof TNested;\n            path: string[];\n        })[];\n        fullTextSearch?: FullTextSearch.FieldOptions[];\n    }\n    interface RangedIndexOptions {\n        [prop: string]: RangedIndexMeta;\n    }\n    interface DeserializeOptions {\n        retainDirtyFlags?: boolean;\n        fullTextSearch?: Dict<Analyzer>;\n        [collName: string]: any | {\n            proto?: any;\n            inflate?: (src: object, dest?: object) => void;\n        };\n    }\n    interface BinaryIndex {\n        dirty: boolean;\n        values: any;\n    }\n    interface RangedIndexMeta {\n        index?: IRangedIndex<any>;\n        indexTypeName?: string;\n        comparatorName?: string;\n    }\n    interface Change {\n        name: string;\n        operation: string;\n        obj: any;\n    }\n    interface Serialized {\n        name: string;\n        unindexedSortComparator: string;\n        defaultLokiOperatorPackage: string;\n        _dynamicViews: DynamicView[];\n        _nestedProperties: {\n            name: string;\n            path: string[];\n        }[];\n        uniqueNames: string[];\n        transforms: Dict<Transform[]>;\n        rangedIndexes: RangedIndexOptions;\n        _data: Doc<any>[];\n        idIndex: number[];\n        maxId: number;\n        _dirty: boolean;\n        transactional: boolean;\n        asyncListeners: boolean;\n        disableMeta: boolean;\n        disableChangesApi: boolean;\n        disableDeltaChangesApi: boolean;\n        cloneObjects: boolean;\n        cloneMethod: CloneMethod;\n        changes: any;\n        _fullTextSearch: FullTextSearch;\n    }\n    interface CheckIndexOptions {\n        randomSampling?: boolean;\n        randomSamplingFactor?: number;\n        repair?: boolean;\n    }\n    type Transform<T extends object = object> = {\n        type: \"find\";\n        value: ResultSet.Query<Doc<T>> | string;\n    } | {\n        type: \"where\";\n        value: ((obj: Doc<T>) => boolean) | string;\n    } | {\n        type: \"simplesort\";\n        property: keyof T;\n        options?: boolean | ResultSet.SimpleSortOptions;\n    } | {\n        type: \"compoundsort\";\n        value: (keyof T | [keyof T, boolean])[];\n    } | {\n        type: \"sort\";\n        value: (a: Doc<T>, b: Doc<T>) => number;\n    } | {\n        type: \"sortByScoring\";\n        desc?: boolean;\n    } | {\n        type: \"limit\";\n        value: number;\n    } | {\n        type: \"offset\";\n        value: number;\n    } | {\n        type: \"map\";\n        value: (obj: Doc<T>, index: number, array: Doc<T>[]) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"eqJoin\";\n        joinData: Collection<any> | ResultSet<any>;\n        leftJoinKey: string | ((obj: any) => string);\n        rightJoinKey: string | ((obj: any) => string);\n        mapFun?: (left: any, right: any) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"mapReduce\";\n        mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => any;\n        reduceFunction: (array: any[]) => any;\n    } | {\n        type: \"update\";\n        value: (obj: Doc<T>) => any;\n    } | {\n        type: \"remove\";\n    };\n    interface TTL {\n        age: number;\n        ttlInterval: number;\n        daemon: any;\n    }\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/loki/src/comparators.d.ts",
    "content": "export interface ILokiComparer<T> {\n    (a: T, b: T): -1 | 0 | 1;\n}\nexport interface IComparatorMap {\n    [name: string]: ILokiComparer<any>;\n}\n/** Map/Register of named ILokiComparer functions returning -1, 0, 1 for lt/eq/gt assertions for two passed parameters */\nexport declare let ComparatorMap: IComparatorMap;\n/** Typescript-friendly factory for strongly typed 'js' comparators */\nexport declare function CreateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'abstract js' comparators */\nexport declare function CreateAbstractJavascriptComparator<T>(): ILokiComparer<T>;\n/**\n * Comparator which attempts to deal with deal with dates at comparator level.\n * Should work for dates in any of the object, string, and number formats\n */\nexport declare function CreateAbstractDateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'loki' comparators */\nexport declare function CreateLokiComparator(): ILokiComparer<any>;\n"
  },
  {
    "path": "dist/packages/memory-storage/types/loki/src/dynamic_view.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { ResultSet } from \"./result_set\";\nimport { Collection } from \"./collection\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\n/**\n * DynamicView class is a versatile 'live' view class which can have filters and sorts applied.\n *    Collection.addDynamicView(name) instantiates this DynamicView object and notifies it\n *    whenever documents are add/updated/removed so it can remain up-to-date. (chainable)\n *\n * @example\n * let mydv = mycollection.addDynamicView('test');  // default is non-persistent\n * mydv.applyFind({ 'doors' : 4 });\n * mydv.applyWhere(function(obj) { return obj.name === 'Toyota'; });\n * let results = mydv.data();\n *\n * @extends LokiEventEmitter\n\n * @see {@link Collection#addDynamicView} to construct instances of DynamicView\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class DynamicView<T extends object = object> extends LokiEventEmitter {\n    readonly name: string;\n    private _collection;\n    private _persistent;\n    private _sortPriority;\n    private _minRebuildInterval;\n    private _rebuildPending;\n    private _resultSet;\n    private _resultData;\n    private _resultDirty;\n    private _cachedResultSet;\n    private _filterPipeline;\n    private _sortFunction;\n    private _sortCriteria;\n    private _sortCriteriaSimple;\n    private _sortByScoring;\n    private _sortDirty;\n    /**\n     * Constructor.\n     * @param {Collection} collection - a reference to the collection to work agains\n     * @param {string} name - the name of this dynamic view\n     * @param {object} options - the options\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=\"passive\"] - the sort priority\n     * @param {number} [options.minRebuildInterval=1] - minimum rebuild interval (need clarification to docs here)\n     */\n    constructor(collection: Collection<T>, name: string, options?: DynamicView.Options);\n    /**\n     * Internally used immediately after deserialization (loading)\n     *    This will clear out and reapply filterPipeline ops, recreating the view.\n     *    Since where filters do not persist correctly, this method allows\n     *    restoring the view to state where user can re-apply those where filters.\n     *\n     * @param removeWhereFilters\n     * @returns {DynamicView} This dynamic view for further chained ops.\n     * @fires DynamicView.rebuild\n     */\n    private _rematerialize({removeWhereFilters});\n    /**\n     * Makes a copy of the internal ResultSet for branched queries.\n     * Unlike this dynamic view, the branched ResultSet will not be 'live' updated,\n     * so your branched query should be immediately resolved and not held for future evaluation.\n     * @param {(string|array=)} transform - Optional name of collection transform, or an array of transform steps\n     * @param {object} parameters - optional parameters (if optional transform requires them)\n     * @returns {ResultSet} A copy of the internal ResultSet for branched queries.\n     */\n    branchResultSet(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Override of toJSON to avoid circular references.\n     */\n    toJSON(): DynamicView.Serialized;\n    static fromJSONObject(collection: Collection, obj: DynamicView.Serialized): DynamicView;\n    /**\n     * Used to clear pipeline and reset dynamic view to initial state.\n     * Existing options should be retained.\n     * @param {boolean} queueSortPhase - (default: false) if true we will async rebuild view (maybe set default to true in future?)\n     */\n    removeFilters({queueSortPhase}?: {\n        queueSortPhase?: boolean;\n    }): void;\n    /**\n     * Used to apply a sort to the dynamic view\n     * @example\n     * dv.applySort(function(obj1, obj2) {\n       *   if (obj1.name === obj2.name) return 0;\n       *   if (obj1.name > obj2.name) return 1;\n       *   if (obj1.name < obj2.name) return -1;\n       * });\n     * @param {function} comparefun - a javascript compare function used for sorting\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applySort(comparefun: (lhs: Doc<T>, rhs: Doc<T>) => number): this;\n    /**\n     * Used to specify a property used for view translation.\n     * @param {string} field - the field name\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether we should sort descending.\n     * @param {boolean} [options.disableIndexIntersect=false] - whether we should explicity not use array intersection.\n     * @param {boolean} [options.forceIndexIntersect=false] - force array intersection (if binary index exists).\n     * @param {boolean} [options.useJavascriptSorting=false] - whether results are sorted via basic javascript sort.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     * @example\n     * dv.applySimpleSort(\"name\");\n     */\n    applySimpleSort(field: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @param {Array} criteria - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {DynamicView} Reference to this DynamicView, sorted, for future chain operations.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * dv.applySortCriteria(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * dv.applySortCriteria(['age', ['name', true]]);\n     * // to sort by age (descending) and then by name (descending)\n     * dv.applySortCriteria([['age', true], ['name', true]]);\n     */\n    applySortCriteria(criteria: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Used to apply a sort by the latest full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     */\n    applySortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Marks the beginning of a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    startTransaction(): this;\n    /**\n     * Commits a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    commit(): this;\n    /**\n     * Rolls back a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    rollback(): this;\n    /**\n     * Find the index of a filter in the pipeline, by that filter's ID.\n     * @param {(string|number)} uid - The unique ID of the filter.\n     * @returns {number}: index of the referenced filter in the pipeline; -1 if not found.\n     */\n    private _indexOfFilterWithId(uid);\n    /**\n     * Add the filter object to the end of view's filter pipeline and apply the filter to the ResultSet.\n     * @param {object} filter - The filter object. Refer to applyFilter() for extra details.\n     */\n    private _addFilter(filter);\n    /**\n     * Reapply all the filters in the current pipeline.\n     *\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    reapplyFilters(): this;\n    /**\n     * Adds or updates a filter in the DynamicView filter pipeline\n     * @param {object} filter - A filter object to add to the pipeline.\n     *    The object is in the format { 'type': filter_type, 'val', filter_param, 'uid', optional_filter_id }\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFilter(filter: DynamicView.Filter<T>): this;\n    /**\n     * applyFind() - Adds or updates a mongo-style query option in the DynamicView filter pipeline\n     *\n     * @param {object} query - A mongo-style query object to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFind(query: object, uid?: string | number): this;\n    /**\n     * Adds or updates a javascript filter function in the DynamicView filter pipeline\n     * @param {function} fun - A javascript filter function to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyWhere(fun: (obj: Doc<T>) => boolean, uid?: string | number): this;\n    /**\n     * Remove the specified filter from the DynamicView filter pipeline\n     * @param {(string|number)} uid - The unique ID of the filter to be removed.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    removeFilter(uid: string | number): this;\n    /**\n     * Returns the number of documents representing the current DynamicView contents.\n     * @returns {number} The number of documents representing the current DynamicView contents.\n     */\n    count(): number;\n    /**\n     * Resolves and pending filtering and sorting, then returns document array as result.\n     * @param {object} options - optional parameters to pass to ResultSet.data() if non-persistent\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values include 'parse-stringify', 'jquery-extend-deep', 'shallow', 'shallow-assign'\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} An array of documents representing the current DynamicView contents.\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * When the view is not sorted we may still wish to be notified of rebuild events.\n     * This event will throttle and queue a single rebuild event when batches of updates affect the view.\n     */\n    private _queueRebuildEvent();\n    /**\n     * If the view is sorted we will throttle sorting to either :\n     * (1) passive - when the user calls data(), or\n     * (2) active - once they stop updating and yield js thread control\n     */\n    private _queueSortPhase();\n    /**\n     * Invoked synchronously or asynchronously to perform final sort phase (if needed)\n     */\n    private _performSortPhase(options?);\n    /**\n     * (Re)evaluating document inclusion.\n     * Called by : collection.insert() and collection.update().\n     * @param {int} objIndex - index of document to (re)run through filter pipeline.\n     * @param {boolean} isNew - true if the document was just added to the collection.\n     * @hidden\n     */\n    _evaluateDocument(objIndex: number, isNew: boolean): void;\n    /**\n     * Internal function called on collection.delete().\n     * @hidden\n     */\n    _removeDocument(objIndex: number): void;\n    /**\n     * Data transformation via user supplied functions\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: T, index: number, array: T[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n}\nexport declare namespace DynamicView {\n    interface Options {\n        persistent?: boolean;\n        sortPriority?: SortPriority;\n        minRebuildInterval?: number;\n    }\n    type SortPriority = \"passive\" | \"active\";\n    interface Serialized {\n        name: string;\n        _persistent: boolean;\n        _sortPriority: SortPriority;\n        _minRebuildInterval: number;\n        _resultSet: ResultSet<any>;\n        _filterPipeline: Filter<any>[];\n        _sortCriteria: (string | [string, boolean])[];\n        _sortCriteriaSimple: {\n            field: string;\n            options: boolean | ResultSet.SimpleSortOptions;\n        };\n        _sortByScoring: boolean;\n        _sortDirty: boolean;\n    }\n    type Filter<T extends object = object> = {\n        type: \"find\";\n        val: ResultSet.Query<Doc<T>>;\n        uid: number | string;\n    } | {\n        type: \"where\";\n        val: (obj: Doc<T>) => boolean;\n        uid: number | string;\n    };\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/loki/src/event_emitter.d.ts",
    "content": "/**\n * LokiEventEmitter is a minimalist version of EventEmitter. It enables any\n * constructor that inherits EventEmitter to emit events and trigger\n * listeners that have been added to the event through the on(event, callback) method\n *\n * @constructor LokiEventEmitter\n */\nexport declare class LokiEventEmitter {\n    /**\n     * A map, with each property being an array of callbacks.\n     */\n    protected _events: object;\n    /**\n     * Determines whether or not the callbacks associated with each event should happen in an async fashion or not.\n     * Default is false, which means events are synchronous\n     */\n    protected _asyncListeners: boolean;\n    /**\n     * Adds a listener to the queue of callbacks associated to an event\n     * @param {string|string[]} eventName - the name(s) of the event(s) to listen to\n     * @param {function} listener - callback function of listener to attach\n     * @returns {int} the index of the callback in the array of listeners for a particular event\n     */\n    on(eventName: string | string[], listener: Function): Function;\n    /**\n     * Emits a particular event\n     * with the option of passing optional parameters which are going to be processed by the callback\n     * provided signatures match (i.e. if passing emit(event, arg0, arg1) the listener should take two parameters)\n     * @param {string} eventName - the name of the event\n     * @param {object} data - optional object passed with the event\n     */\n    protected emit(eventName: string, ...data: any[]): void;\n    /**\n     * Alias of EventEmitter.on().\n     */\n    addListener(eventName: string | string[], listener: Function): Function;\n    /**\n     * Removes the listener at position 'index' from the event 'eventName'\n     * @param {string|string[]} eventName - the name(s) of the event(s) which the listener is attached to\n     * @param {function} listener - the listener callback function to remove from emitter\n     */\n    removeListener(eventName: string | string[], listener: Function): void;\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/loki/src/index.d.ts",
    "content": "import { Loki } from \"./loki\";\nimport { Collection } from \"./collection\";\nexport { Loki, Collection };\nexport default Loki;\n"
  },
  {
    "path": "dist/packages/memory-storage/types/loki/src/loki.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { Collection } from \"./collection\";\nimport { Doc, StorageAdapter } from \"../../common/types\";\nimport { IComparatorMap } from \"./comparators\";\nimport { IRangedIndexFactoryMap } from \"./ranged_indexes\";\nimport { ILokiOperatorPackageMap } from \"./operator_packages\";\nexport declare class Loki extends LokiEventEmitter {\n    filename: string;\n    private databaseVersion;\n    private engineVersion;\n    _collections: Collection[];\n    private _env;\n    private _serializationMethod;\n    private _destructureDelimiter;\n    private _persistenceMethod;\n    private _persistenceAdapter;\n    private _throttledSaves;\n    private _throttledSaveRunning;\n    private _throttledSavePending;\n    private _autosave;\n    private _autosaveInterval;\n    private _autosaveRunning;\n    private _autosaveHandler;\n    /**\n     * Constructs the main database class.\n     * @param {string} filename - name of the file to be saved to\n     * @param {object} [options={}] - options\n     * @param {Loki.Environment} [options.env] - the javascript environment\n     * @param {Loki.SerializationMethod} [options.serializationMethod=NORMAL] - the serialization method\n     * @param {string} [options.destructureDelimiter=\"$<\\n\"] - string delimiter used for destructured serialization\n     * @param {IComparatorMap} [options.comparatorMap] allows injecting or overriding registered comparators\n     * @param {IRangedIndexFactoryMap} [options.rangedIndexFactoryMap] allows injecting or overriding registered ranged index factories\n     * @param {ILokiOperatorPackageMap} [options.lokiOperatorPackageMap] allows injecting or overriding registered loki operator packages\n     */\n    constructor(filename?: string, options?: Loki.Options);\n    /**\n     * configures options related to database persistence.\n     *\n     * @param {Loki.PersistenceOptions} [options={}] - options\n     * @param {adapter} [options.adapter=auto] - an instance of a loki persistence adapter\n     * @param {boolean} [options.autosave=false] - enables autosave\n     * @param {int} [options.autosaveInterval=5000] - time interval (in milliseconds) between saves (if dirty)\n     * @param {boolean} [options.autoload=false] - enables autoload on loki instantiation\n     * @param {object} options.inflate - options that are passed to loadDatabase if autoload enabled\n     * @param {boolean} [options.throttledSaves=true] - if true, it batches multiple calls to to saveDatabase reducing number of\n     *   disk I/O operations and guaranteeing proper serialization of the calls. Default value is true.\n     * @param {Loki.PersistenceMethod} options.persistenceMethod - a persistence method which should be used (FS_STORAGE, LOCAL_STORAGE...)\n     * @returns {Promise} a Promise that resolves after initialization and (if enabled) autoloading the database\n     */\n    initializePersistence(options?: Loki.PersistenceOptions): Promise<void>;\n    /**\n     * Copies 'this' database into a new Loki instance. Object references are shared to make lightweight.\n     * @param {object} options - options\n     * @param {boolean} options.removeNonSerializable - nulls properties not safe for serialization.\n     */\n    copy(options?: Loki.CopyOptions): Loki;\n    /**\n     * Adds a collection to the database.\n     * @param {string} name - name of collection to add\n     * @param {object} [options={}] - options to configure collection with.\n     * @param {array} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {array} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {array} [options.indices=[]] - array property names to define binary indexes for\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are called asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes Api\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {string} [options.cloneMethod=CloneMethod.DEEP] - the clone method\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @returns {Collection} a reference to the collection which was just added\n     */\n    addCollection<TData extends object = object, TNested extends object = object>(name: string, options?: Collection.Options<TData, TNested>): Collection<TData, TNested>;\n    loadCollection(collection: Collection): void;\n    /**\n     * Retrieves reference to a collection by name.\n     * @param {string} name - name of collection to look up\n     * @returns {Collection} Reference to collection in database by that name, or null if not found\n     */\n    getCollection<TData extends object = object, TNested extends object = object>(name: string): Collection<TData, TNested>;\n    /**\n     * Renames an existing loki collection\n     * @param {string} oldName - name of collection to rename\n     * @param {string} newName - new name of collection\n     * @returns {Collection} reference to the newly renamed collection\n     */\n    renameCollection<TData extends object = object, TNested extends object = object>(oldName: string, newName: string): Collection<TData, TNested>;\n    listCollections(): {\n        name: string;\n        count: number;\n    }[];\n    /**\n     * Removes a collection from the database.\n     * @param {string} collectionName - name of collection to remove\n     */\n    removeCollection(collectionName: string): void;\n    /**\n     * Serialize database to a string which can be loaded via {@link Loki#loadJSON}\n     *\n     * @returns {string} Stringified representation of the loki database.\n     */\n    serialize(options?: Loki.SerializeOptions): string | string[];\n    toJSON(): Loki.Serialized;\n    /**\n     * Database level destructured JSON serialization routine to allow alternate serialization methods.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {object} options - output format options for use externally to loki\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to only output an individual collection or db (-1)\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {string|Array} A custom, restructured aggregation of independent serializations.\n     */\n    serializeDestructured(options?: Loki.SerializeDestructuredOptions): string | string[];\n    /**\n     * Collection level utility method to serialize a collection in a 'destructured' format\n     *\n     * @param {object} options - used to determine output of method\n     * @param {int} options.delimited - whether to return single delimited string or an array\n     * @param {string} options.delimiter - (optional) if delimited, this is delimiter to use\n     * @param {int} options.collectionIndex -  specify which collection to serialize data for\n     *\n     * @returns {string|array} A custom, restructured aggregation of independent serializations for a single collection.\n     */\n    serializeCollection(options?: {\n        delimited?: boolean;\n        collectionIndex?: number;\n        delimiter?: string;\n    }): string | string[];\n    /**\n     * Database level destructured JSON deserialization routine to minimize memory overhead.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {string|array} destructuredSource - destructured json or array to deserialize from\n     * @param {object} options - source format options\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to deserialize only a single partition\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {object|array} An object representation of the deserialized database, not yet applied to 'this' db or document array\n     */\n    deserializeDestructured(destructuredSource: string | string[], options?: Loki.SerializeDestructuredOptions): any;\n    /**\n     * Collection level utility function to deserializes a destructured collection.\n     *\n     * @param {string|string[]} destructuredSource - destructured representation of collection to inflate\n     * @param {object} options - used to describe format of destructuredSource input\n     * @param {int} [options.delimited=false] - whether source is delimited string or an array\n     * @param {string} options.delimiter - if delimited, this is delimiter to use (if other than default)\n     *\n     * @returns {Array} an array of documents to attach to collection.data.\n     */\n    deserializeCollection<T extends object = object>(destructuredSource: string | string[], options?: Loki.DeserializeCollectionOptions): Doc<T>[];\n    /**\n     * Inflates a loki database from a serialized JSON string\n     *\n     * @param {string} serializedDb - a serialized loki database string\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSON(serializedDb: string | string[], options?: Collection.DeserializeOptions): void;\n    /**\n     * Inflates a loki database from a JS object\n     *\n     * @param {object} dbObject - a serialized loki database object\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSONObject(dbObject: Loki, options?: Collection.DeserializeOptions): void;\n    loadJSONObject(dbObject: Loki.Serialized, options?: Collection.DeserializeOptions): void;\n    /**\n     * Emits the close event. In autosave scenarios, if the database is dirty, this will save and disable timer.\n     * Does not actually destroy the db.\n     *\n     * @returns {Promise} a Promise that resolves after closing the database succeeded\n     */\n    close(): Promise<void>;\n    /**-------------------------+\n     | Changes API               |\n     +--------------------------*/\n    /**\n     * The Changes API enables the tracking the changes occurred in the collections since the beginning of the session,\n     * so it's possible to create a differential dataset for synchronization purposes (possibly to a remote db)\n     */\n    /**\n     * (Changes API) : takes all the changes stored in each\n     * collection and creates a single array for the entire database. If an array of names\n     * of collections is passed then only the included collections will be tracked.\n     *\n     * @param {Array} [arrayOfCollectionNames=] - array of collection names. No arg means all collections are processed.\n     * @returns {Array} array of changes\n     * @see private method _createChange() in Collection\n     */\n    generateChangesNotification(arrayOfCollectionNames?: string[]): Collection.Change[];\n    /**\n     * (Changes API) - stringify changes for network transmission\n     * @returns {string} string representation of the changes\n     */\n    serializeChanges(collectionNamesArray?: string[]): string;\n    /**\n     * (Changes API) : clears all the changes in all collections.\n     */\n    clearChanges(): void;\n    /**\n     * Wait for throttledSaves to complete and invoke your callback when drained or duration is met.\n     *\n     * @param {object} options - configuration options\n     * @param {boolean} [options.recursiveWait=true] - if after queue is drained, another save was kicked off, wait for it\n     * @param {boolean} [options.recursiveWaitLimit=false] - limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDuration=2000] - cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves when save queue is drained, it is passed a sucess parameter value\n     */\n    throttledSaveDrain(options?: Loki.ThrottledDrainOptions): Promise<void>;\n    /**\n     * Internal load logic, decoupled from throttling/contention logic\n     *\n     * @param {object} options - an object containing inflation options for each collection\n     * @param {boolean} ignore_not_found - does not raise an error if database is not found\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    private _loadDatabase(options?, ignore_not_found?);\n    /**\n     * Handles manually loading from an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *    To avoid contention with any throttledSaves, we will drain the save queue first.\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @param {object} [options={}] - if throttling saves and loads, this controls how we drain save queue before loading\n     * @param {boolean} [options.recursiveWait=true] wait recursively until no saves are queued\n     * @param {boolean} [options.recursiveWaitLimit=false] limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDelay=2000] cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    loadDatabase(options?: Loki.LoadDatabaseOptions): Promise<void>;\n    private _saveDatabase();\n    /**\n     * Handles manually saving to an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @returns {Promise} a Promise that resolves after the database is persisted\n     */\n    saveDatabase(): Promise<void>;\n    /**\n     * Handles deleting a database from the underlying storage adapter\n     *\n     * @returns {Promise} a Promise that resolves after the database is deleted\n     */\n    deleteDatabase(): Promise<void>;\n    /****************\n     * Autosave API\n     ****************/\n    /**\n     * Check whether any collections are \"dirty\" meaning we need to save the (entire) database\n     * @returns {boolean} - true if database has changed since last autosave, otherwise false\n     */\n    private _autosaveDirty();\n    /**\n     * Resets dirty flags on all collections.\n     */\n    private _autosaveClearFlags();\n    /**\n     * Starts periodically saves to the underlying storage adapter.\n     */\n    private _autosaveEnable();\n    /**\n     * Stops the autosave interval timer.\n     */\n    private _autosaveDisable();\n}\nexport declare namespace Loki {\n    interface Options {\n        env?: Environment;\n        serializationMethod?: SerializationMethod;\n        destructureDelimiter?: string;\n        comparatorMap?: IComparatorMap;\n        rangedIndexFactoryMap?: IRangedIndexFactoryMap;\n        lokiOperatorPackageMap?: ILokiOperatorPackageMap;\n    }\n    interface PersistenceOptions {\n        adapter?: StorageAdapter;\n        autosave?: boolean;\n        autosaveInterval?: number;\n        autoload?: boolean;\n        throttledSaves?: boolean;\n        persistenceMethod?: Loki.PersistenceMethod;\n        inflate?: any;\n    }\n    interface CopyOptions {\n        removeNonSerializable?: boolean;\n    }\n    interface SerializeOptions {\n        serializationMethod?: SerializationMethod;\n    }\n    interface SerializeDestructuredOptions {\n        partitioned?: boolean;\n        partition?: number;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface DeserializeCollectionOptions {\n        partitioned?: boolean;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface ThrottledDrainOptions {\n        recursiveWait?: boolean;\n        recursiveWaitLimit?: boolean;\n        recursiveWaitLimitDuration?: number;\n        started?: Date;\n    }\n    interface Serialized {\n        _env: Environment;\n        _serializationMethod: SerializationMethod;\n        _autosave: boolean;\n        _autosaveInterval: number;\n        _collections: Collection[];\n        databaseVersion: number;\n        engineVersion: number;\n        filename: string;\n        _persistenceAdapter: StorageAdapter;\n        _persistenceMethod: PersistenceMethod;\n        _throttledSaves: boolean;\n    }\n    type LoadDatabaseOptions = Collection.DeserializeOptions & ThrottledDrainOptions;\n    type SerializationMethod = \"normal\" | \"pretty\" | \"destructured\";\n    type PersistenceMethod = \"fs-storage\" | \"local-storage\" | \"indexed-storage\" | \"memory-storage\" | \"adapter\";\n    type Environment = \"NATIVESCRIPT\" | \"NODEJS\" | \"CORDOVA\" | \"BROWSER\" | \"MEMORY\";\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/loki/src/operator_packages.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\n/** Hash interface for named LokiOperatorPackage registration */\nexport interface ILokiOperatorPackageMap {\n    [name: string]: LokiOperatorPackage;\n}\n/**\n * Helper function for determining 'loki' abstract equality which is a little more abstract than ==\n *     aeqHelper(5, '5') === true\n *     aeqHelper(5.0, '5') === true\n *     aeqHelper(new Date(\"1/1/2011\"), new Date(\"1/1/2011\")) === true\n *     aeqHelper({a:1}, {z:4}) === true (all objects sorted equally)\n *     aeqHelper([1, 2, 3], [1, 3]) === false\n *     aeqHelper([1, 2, 3], [1, 2, 3]) === true\n *     aeqHelper(undefined, null) === true\n * @param {any} prop1\n * @param {any} prop2\n * @returns {boolean}\n * @hidden\n */\nexport declare function aeqHelper(prop1: any, prop2: any): boolean;\n/**\n * Helper function for determining 'less-than' conditions for ops, sorting, and binary indices.\n *     In the future we might want $lt and $gt ops to use their own functionality/helper.\n *     Since binary indices on a property might need to index [12, NaN, new Date(), Infinity], we\n *     need this function (as well as gtHelper) to always ensure one value is LT, GT, or EQ to another.\n * @hidden\n */\nexport declare function ltHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @hidden\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} equal\n * @returns {boolean}\n */\nexport declare function gtHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} descending\n * @returns {number}\n * @hidden\n */\nexport declare function sortHelper(prop1: any, prop2: any, descending: boolean): number;\n/**\n * Default implementation of LokiOperatorPackage, using fastest javascript comparison operators.\n */\nexport declare class LokiOperatorPackage {\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n    $in(a: any, b: any): boolean;\n    $nin(a: any, b: any): boolean;\n    $keyin(a: string, b: object): boolean;\n    $nkeyin(a: string, b: object): boolean;\n    $definedin(a: string, b: object): boolean;\n    $undefinedin(a: string, b: object): boolean;\n    $regex(a: string, b: RegExp): boolean;\n    $containsNone(a: any, b: any): boolean;\n    $containsAny(a: any, b: any): boolean;\n    $contains(a: any, b: any): boolean;\n    $type(a: any, b: any): boolean;\n    $finite(a: number, b: boolean): boolean;\n    $size(a: any, b: any): boolean;\n    $len(a: any, b: any): boolean;\n    $where(a: any, b: any): boolean;\n    $not(a: any, b: any): boolean;\n    $and(a: any, b: any): boolean;\n    $or(a: any, b: any): boolean;\n    private doQueryOp(val, op);\n    private containsCheckFn(a);\n}\n/**\n * LokiOperatorPackage which utilizes abstract 'loki' comparisons for basic relational equality op implementations.\n */\nexport declare class LokiAbstractOperatorPackage extends LokiOperatorPackage {\n    constructor();\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * LokiOperatorPackage which utilizes provided comparator for basic relational equality op implementations.\n */\nexport declare class ComparatorOperatorPackage<T> extends LokiOperatorPackage {\n    comparator: ILokiComparer<T>;\n    constructor(comparator: ILokiComparer<T>);\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * Map/Register of named LokiOperatorPackages which implement all unindexed query ops within 'find' query objects\n */\nexport declare let LokiOperatorPackageMap: ILokiOperatorPackageMap;\n"
  },
  {
    "path": "dist/packages/memory-storage/types/loki/src/ranged_indexes.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\nexport declare type RangedValueOperator = \"$gt\" | \"$gte\" | \"$lt\" | \"$lte\" | \"$eq\" | \"$neq\" | \"$between\";\nexport interface IRangedIndexRequest<T> {\n    op: RangedValueOperator;\n    val: T;\n    high?: T;\n}\n/** Defines interface which all loki ranged indexes need to implement */\nexport interface IRangedIndex<T> {\n    insert(id: number, val: T): void;\n    update(id: number, val: T): void;\n    remove(id: number): void;\n    restore(tree: any): void;\n    backup(): IRangedIndex<T>;\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    validateIndex(): boolean;\n}\n/** Hash Interface for global ranged index factory map*/\nexport interface IRangedIndexFactoryMap {\n    [name: string]: (name: string, comparator: ILokiComparer<any>) => IRangedIndex<any>;\n}\n/** Map/Register of named factory functions returning IRangedIndex instances */\nexport declare let RangedIndexFactoryMap: IRangedIndexFactoryMap;\n"
  },
  {
    "path": "dist/packages/memory-storage/types/loki/src/result_set.d.ts",
    "content": "import { Collection } from \"./collection\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\nimport { Query as FullTextSearchQuery } from \"../../full-text-search/src/query_types\";\n/**\n * ResultSet class allowing chainable queries.  Intended to be instanced internally.\n *    Collection.find(), Collection.where(), and Collection.chain() instantiate this.\n *\n * @example\n *    mycollection.chain()\n *      .find({ 'doors' : 4 })\n *      .where(function(obj) { return obj.name === 'Toyota' })\n *      .data();\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class ResultSet<T extends object = object> {\n    _collection: Collection<T>;\n    _filteredRows: number[];\n    _filterInitialized: boolean;\n    private _scoring;\n    /**\n     * Constructor.\n     * @param {Collection} collection - the collection which this ResultSet will query against\n     */\n    constructor(collection: Collection<T>);\n    /**\n     * Reset the ResultSet to its initial state.\n     * @returns {ResultSet} Reference to this ResultSet, for future chain operations.\n     */\n    reset(): this;\n    /**\n     * Override of toJSON to avoid circular references\n     */\n    toJSON(): ResultSet<T>;\n    /**\n     * Allows you to limit the number of documents passed to next chain operation.\n     * A ResultSet copy() is made to avoid altering original ResultSet.\n     * @param {int} qty - The number of documents to return.\n     * @returns {ResultSet} Returns a copy of the ResultSet, limited by qty, for subsequent chain ops.\n     */\n    limit(qty: number): this;\n    /**\n     * Used for skipping 'pos' number of documents in the ResultSet.\n     * @param {int} pos - Number of documents to skip; all preceding documents are filtered out.\n     * @returns {ResultSet} Returns a copy of the ResultSet, containing docs starting at 'pos' for subsequent chain ops.\n     */\n    offset(pos: number): this;\n    /**\n     * To support reuse of ResultSet in branched query situations.\n     * @returns {ResultSet} Returns a copy of the ResultSet (set) but the underlying document references will be the same.\n     */\n    copy(): ResultSet<T>;\n    /**\n     * Executes a named collection transform or raw array of transform steps against the ResultSet.\n     * @param {(string|array)} transform - name of collection transform or raw transform array\n     * @param {object} [parameters=] - object property hash of parameters, if the transform requires them.\n     * @returns {ResultSet} either (this) ResultSet or a clone of of this ResultSet (depending on steps)\n     */\n    transform(transform: string | Collection.Transform<T>[], parameters?: object): this;\n    /**\n     * User supplied compare function is provided two documents to compare. (chainable)\n     * @example\n     *    rslt.sort(function(obj1, obj2) {\n       *      if (obj1.name === obj2.name) return 0;\n       *      if (obj1.name > obj2.name) return 1;\n       *      if (obj1.name < obj2.name) return -1;\n       *    });\n     * @param {function} comparefun - A javascript compare function used for sorting.\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    sort(comparefun: (a: Doc<T>, b: Doc<T>) => number): this;\n    /**\n     * Simpler, loose evaluation for user to sort based on a property name. (chainable).\n     * Sorting based on the same lt/gt helper functions used for binary indices.\n     * @param {string} propname - name of property to sort by.\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether to sort descending\n     * @param {string} [options.sortComparator] override default with name of comparator registered in ComparatorMap\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    simplesort(propname: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * rs.compoundsort(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * rs.compoundsort(['age', ['name', true]);\n     * @param {array} properties - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    compoundsort(properties: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Helper function for compoundsort(), performing individual object comparisons\n     * @param {Array} properties - array of property names, in order, by which to evaluate sort order\n     * @param {object} obj1 - first object to compare\n     * @param {object} obj2 - second object to compare\n     * @returns {number} 0, -1, or 1 to designate if identical (sortwise) or which should be first\n     */\n    private _compoundeval(properties, obj1, obj2);\n    /**\n     * Sorts the ResultSet based on the last full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     * @returns {ResultSet}\n     */\n    sortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Oversee the operation of OR'ed query expressions.\n     * OR'ed expression evaluation runs each expression individually against the full collection,\n     * and finally does a set OR on each expression's results.\n     * Each evaluation can utilize a binary index to prevent multiple linear array scans.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findOr(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $or(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Oversee the operation of AND'ed query expressions.\n     * AND'ed expression evaluation runs each expression progressively against the full collection,\n     * internally utilizing existing chained ResultSet functionality.\n     * Only the first filter can utilize a binary index.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findAnd(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $and(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Used for querying via a mongo-style query object.\n     *\n     * @param {object} query - A mongo-style query object used for filtering current results.\n     * @param {boolean} firstOnly - (Optional) Used by collection.findOne() - flag if this was invoked via findOne()\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    find(query?: ResultSet.Query<Doc<T>>, firstOnly?: boolean): this;\n    /**\n     * Used for filtering via a javascript filter function.\n     * @param {function} fun - A javascript function used for filtering current results by.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    where(fun: (obj: Doc<T>) => boolean): this;\n    /**\n     * Returns the number of documents in the ResultSet.\n     * @returns {number} The number of documents in the ResultSet.\n     */\n    count(): number;\n    /**\n     * Terminates the chain and returns array of filtered documents\n     * @param {object} options\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values 'parse-stringify', 'deep', and 'shallow' and\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} Array of documents in the ResultSet\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * Used to run an update operation on all documents currently in the ResultSet.\n     * @param {function} updateFunction - User supplied updateFunction(obj) will be executed for each document object.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    update(updateFunction: (obj: Doc<T>) => Doc<T>): this;\n    /**\n     * Removes all document objects which are currently in ResultSet from collection (as well as ResultSet)\n     * @returns {ResultSet} this (empty) ResultSet for further chain ops.\n     */\n    remove(): this;\n    /**\n     * data transformation via user supplied functions\n     *\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns {value} The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Left joining two sets of data. Join keys can be defined or calculated properties\n     * eqJoin expects the right join key values to be unique.  Otherwise left data will be joined on the last joinData object with that key\n     * @param {Array|ResultSet|Collection} joinData - Data array to join to.\n     * @param {(string|function)} leftJoinKey - Property name in this result set to join on or a function to produce a value to join on\n     * @param {(string|function)} rightJoinKey - Property name in the joinData to join on or a function to produce a value to join on\n     * @param {function} [mapFun=] - a function that receives each matching pair and maps them into output objects - function(left,right){return joinedObject}\n     * @param {object} [dataOptions=] - optional options to apply to data() calls for left and right sides\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} A ResultSet with data in the format [{left: leftObj, right: rightObj}]\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinKey: string | ((obj: any) => string), rightJoinKey: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * Applies a map function into a new collection for further chaining.\n     * @param {function} mapFun - javascript map function\n     * @param {object} [dataOptions=] - options to data() before input to your map function\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - Allows overriding the default or collection specified cloning method\n     * @return {ResultSet}\n     */\n    map<U extends object>(mapFun: (obj: Doc<T>, index: number, array: Doc<T>[]) => U, dataOptions?: ResultSet.DataOptions): ResultSet<U>;\n}\nexport declare namespace ResultSet {\n    interface DataOptions {\n        forceClones?: boolean;\n        forceCloneMethod?: CloneMethod;\n        removeMeta?: boolean;\n    }\n    interface SimpleSortOptions {\n        desc?: boolean;\n        sortComparator?: string;\n    }\n    type ContainsHelperType<R> = R extends string ? string | string[] : R extends any[] ? R[number] | R[number][] : R extends object ? keyof R | (keyof R)[] : never;\n    type LokiOps<R> = {\n        $eq?: R;\n    } | {\n        $ne?: R;\n    } | {\n        $gt?: R;\n    } | {\n        $gte?: R;\n    } | {\n        $lt?: R;\n    } | {\n        $lte?: R;\n    } | {\n        $between?: [R, R];\n    } | {\n        $in?: R[];\n    } | {\n        $nin?: R[];\n    } | {\n        $keyin?: object;\n    } | {\n        $nkeyin?: object;\n    } | {\n        $definedin?: object;\n    } | {\n        $undefinedin?: object;\n    } | {\n        $regex?: RegExp | string | [string, string];\n    } | {\n        $containsNone?: ContainsHelperType<R>;\n    } | {\n        $containsAny?: ContainsHelperType<R>;\n    } | {\n        $contains?: ContainsHelperType<R>;\n    } | {\n        $type?: string;\n    } | {\n        $finite?: boolean;\n    } | {\n        $size?: number;\n    } | {\n        $len?: number;\n    } | {\n        $where?: (val?: R) => boolean;\n    };\n    type Query<T> = {\n        [P in keyof T]?: LokiOps<T[P]> | T[P];\n    } & {\n        $and?: Query<T>[];\n    } & {\n        $or?: Query<T>[];\n    } & {\n        $fts?: FullTextSearchQuery;\n    };\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/loki/src/unique_index.d.ts",
    "content": "export declare class UniqueIndex {\n    private _field;\n    private _lokiMap;\n    private _valMap;\n    /**\n     * Constructs an unique index object.\n     * @param {string} propertyField - the property field to index\n     */\n    constructor(propertyField: string);\n    /**\n     * Sets a document's unique index.\n     * @param {number} id loki id to associate with value\n     * @param {*} value  value to associate with id\n     */\n    set(id: number, value: any): void;\n    /**\n     * Returns the $loki id of an unique value.\n     * @param {*} value the value to retrieve a loki id match for\n     */\n    get(value: any): number;\n    /**\n     * Updates a document's unique index.\n     * @param {number} id (loki) id of document to update the value to\n     * @param {*} value value to associate with loki id\n     */\n    update(id: number, value: any): void;\n    /**\n     * Removes an unique index.\n     * @param {number} id (loki) id to remove from index\n     */\n    remove(id: number): void;\n    /**\n     * Clears the unique index.\n     */\n    clear(): void;\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/memory-storage/src/index.d.ts",
    "content": "import { MemoryStorage } from \"./memory_storage\";\nexport { MemoryStorage };\nexport default MemoryStorage;\n"
  },
  {
    "path": "dist/packages/memory-storage/types/memory-storage/src/memory_storage.d.ts",
    "content": "import { Dict, StorageAdapter } from \"../../common/types\";\n/**\n * An in-memory persistence adapter for an in-memory database.\n * This simple 'key/value' adapter is intended for unit testing and diagnostics.\n */\nexport declare class MemoryStorage implements StorageAdapter {\n    hashStore: Dict<{\n        savecount: number;\n        lastsave: Date;\n        value: string;\n    }>;\n    options: MemoryStorage.Options;\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} options - memory storage options\n     * @param {boolean} [options.asyncResponses=false] - whether callbacks are invoked asynchronously (default: false)\n     * @param {int} [options.asyncTimeout=50] - timeout in ms to queue callbacks (default: 50)\n     */\n    constructor(options?: MemoryStorage.Options);\n    /**\n     * Loads a serialized database from its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * Saves a serialized database to its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {string} dbstring - the database content\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a database from its in-memory store.\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport declare namespace MemoryStorage {\n    interface Options {\n        asyncResponses?: boolean;\n        asyncTimeout?: number;\n    }\n}\n"
  },
  {
    "path": "dist/packages/memory-storage/types/partitioning-adapter/src/index.d.ts",
    "content": "import { PartitioningAdapter } from \"./partitioning_adapter\";\nexport { PartitioningAdapter };\nexport default PartitioningAdapter;\n"
  },
  {
    "path": "dist/packages/memory-storage/types/partitioning-adapter/src/partitioning_adapter.d.ts",
    "content": "import { Loki } from \"../../loki/src/loki\";\nimport { StorageAdapter } from \"../../common/types\";\n/**\n * An adapter for adapters. Converts a non reference mode adapter into a reference mode adapter\n * which can perform destructuring and partitioning. Each collection will be stored in its own key/save and\n * only dirty collections will be saved. If you  turn on paging with default page size of 25megs and save\n * a 75 meg collection it should use up roughly 3 save slots (key/value pairs sent to inner adapter).\n * A dirty collection that spans three pages will save all three pages again\n * Paging mode was added mainly because Chrome has issues saving 'too large' of a string within a\n * single IndexedDB row. If a single document update causes the collection to be flagged as dirty, all\n * of that collection's pages will be written on next save.\n */\nexport declare class PartitioningAdapter implements StorageAdapter {\n    mode: string;\n    private _adapter;\n    private _dbref;\n    private _dbname;\n    private _pageIterator;\n    private _paging;\n    private _pageSize;\n    private _delimiter;\n    private _dirtyPartitions;\n    /**\n     * Registers the partitioning adapter as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the partitioning storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} adapter - reference to a 'non-reference' mode loki adapter instance.\n     * @param {boolean} paging - (default: false) set to true to enable paging collection data.\n     * @param {number} pageSize - (default : 25MB) you can use this to limit size of strings passed to inner adapter.\n     * @param {string} delimiter - allows you to override the default delimiter\n     */\n    constructor(adapter: StorageAdapter, {paging, pageSize, delimiter}?: {\n        paging?: boolean;\n        pageSize?: number;\n        delimiter?: string;\n    });\n    /**\n     * Loads a database which was partitioned into several key/value saves.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Used to sequentially load each collection partition, one at a time.\n     *\n     * @param {int} partition - ordinal collection position to load next\n     * @returns {Promise} a Promise that resolves after the next partition is loaded\n     */\n    private _loadNextPartition(partition);\n    /**\n     * Used to sequentially load the next page of collection partition, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next page is loaded\n     */\n    private _loadNextPage();\n    /**\n     * Saves a database by partioning into separate key/value saves.\n     * (Loki 'reference mode' persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {object} dbref - reference to database which we will partition and save.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     *\n     */\n    exportDatabase(dbname: string, dbref: Loki): Promise<void>;\n    /**\n     * Helper method used internally to save each dirty collection, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPartition();\n    /**\n     * Helper method used internally to generate and save the next page of the current (dirty) partition.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPage();\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/lokidb.partitioning-adapter.js",
    "content": "(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"@lokidb/loki\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"@lokidb/partitioning-adapter\", [\"@lokidb/loki\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"@lokidb/partitioning-adapter\"] = factory(require(\"@lokidb/loki\"));\n\telse\n\t\t{ root[\"@lokidb/partitioning-adapter\"] = factory(root[\"@lokidb/loki\"]); root[\"LokiPartitioningAdapter\"] = root[\"@lokidb/partitioning-adapter\"].default; }\n})(typeof self !== 'undefined' ? self : this, function(__WEBPACK_EXTERNAL_MODULE__1__) {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// define __esModule on exports\n/******/ \t__webpack_require__.r = function(exports) {\n/******/ \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n/******/ \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n/******/ \t\t}\n/******/ \t\tObject.defineProperty(exports, '__esModule', { value: true });\n/******/ \t};\n/******/\n/******/ \t// create a fake namespace object\n/******/ \t// mode & 1: value is a module id, require it\n/******/ \t// mode & 2: merge all properties of value into the ns\n/******/ \t// mode & 4: return value when already ns object\n/******/ \t// mode & 8|1: behave like require\n/******/ \t__webpack_require__.t = function(value, mode) {\n/******/ \t\tif(mode & 1) value = __webpack_require__(value);\n/******/ \t\tif(mode & 8) return value;\n/******/ \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n/******/ \t\tvar ns = Object.create(null);\n/******/ \t\t__webpack_require__.r(ns);\n/******/ \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n/******/ \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n/******/ \t\treturn ns;\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 2);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return PLUGINS; });\nfunction getGlobal() {\n    let glob;\n    (function (global) {\n        glob = global;\n    })(global !== undefined && global || this);\n    return glob;\n}\nfunction create() {\n    const global = getGlobal();\n    const sym = Symbol.for(\"LOKI\");\n    if (global[sym] === undefined) {\n        global[sym] = {};\n    }\n    return global[sym];\n}\n/**\n * @hidden\n */\nconst PLUGINS = create();\n\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(3)))\n\n/***/ }),\n/* 1 */\n/***/ (function(module, exports) {\n\nmodule.exports = __WEBPACK_EXTERNAL_MODULE__1__;\n\n/***/ }),\n/* 2 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n\n// EXTERNAL MODULE: external \"@lokidb/loki\"\nvar loki_ = __webpack_require__(1);\n\n// EXTERNAL MODULE: ./packages/common/plugin.ts\nvar common_plugin = __webpack_require__(0);\n\n// CONCATENATED MODULE: ./packages/partitioning-adapter/src/partitioning_adapter.ts\n\n\n/**\n * An adapter for adapters. Converts a non reference mode adapter into a reference mode adapter\n * which can perform destructuring and partitioning. Each collection will be stored in its own key/save and\n * only dirty collections will be saved. If you  turn on paging with default page size of 25megs and save\n * a 75 meg collection it should use up roughly 3 save slots (key/value pairs sent to inner adapter).\n * A dirty collection that spans three pages will save all three pages again\n * Paging mode was added mainly because Chrome has issues saving 'too large' of a string within a\n * single IndexedDB row. If a single document update causes the collection to be flagged as dirty, all\n * of that collection's pages will be written on next save.\n */\nclass partitioning_adapter_PartitioningAdapter {\n    /**\n     * Registers the partitioning adapter as plugin.\n     */\n    static register() {\n        common_plugin[\"a\" /* PLUGINS */][\"PartitioningAdapter\"] = partitioning_adapter_PartitioningAdapter;\n    }\n    /**\n     * Deregisters the partitioning storage as plugin.\n     */\n    static deregister() {\n        delete common_plugin[\"a\" /* PLUGINS */][\"PartitioningAdapter\"];\n    }\n    /**\n     * @param {object} adapter - reference to a 'non-reference' mode loki adapter instance.\n     * @param {boolean} paging - (default: false) set to true to enable paging collection data.\n     * @param {number} pageSize - (default : 25MB) you can use this to limit size of strings passed to inner adapter.\n     * @param {string} delimiter - allows you to override the default delimiter\n     */\n    constructor(adapter, { paging = false, pageSize = 25 * 1024 * 1024, delimiter = \"$<\\n\" } = {}) {\n        this.mode = \"reference\";\n        this._adapter = null;\n        this._dbref = null;\n        this._dbname = \"\";\n        this._pageIterator = {};\n        // verify user passed an appropriate adapter\n        if (adapter) {\n            if (adapter.mode === \"reference\") {\n                throw new Error(\"LokiPartitioningAdapter cannot be instantiated with a reference mode adapter.\");\n            }\n            else {\n                this._adapter = adapter;\n            }\n        }\n        else {\n            throw new Error(\"LokiPartitioningAdapter requires a (non-reference mode) adapter on construction.\");\n        }\n        this._paging = paging;\n        this._pageSize = pageSize;\n        this._delimiter = delimiter;\n    }\n    /**\n     * Loads a database which was partitioned into several key/value saves.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname) {\n        this._dbname = dbname;\n        this._dbref = new loki_[\"Loki\"](dbname);\n        // load the db container (without data)\n        return this._adapter.loadDatabase(dbname).then((result) => {\n            if (typeof result !== \"string\") {\n                throw new Error(\"LokiPartitioningAdapter received an unexpected response from inner adapter loadDatabase()\");\n            }\n            // I will want to use loki destructuring helper methods so i will inflate into typed instance\n            let db = JSON.parse(result);\n            this._dbref.loadJSONObject(db);\n            db = null;\n            if (this._dbref._collections.length === 0) {\n                return this._dbref;\n            }\n            this._pageIterator = {\n                collection: 0,\n                pageIndex: 0\n            };\n            return this._loadNextPartition(0).then(() => this._dbref);\n        });\n    }\n    /**\n     * Used to sequentially load each collection partition, one at a time.\n     *\n     * @param {int} partition - ordinal collection position to load next\n     * @returns {Promise} a Promise that resolves after the next partition is loaded\n     */\n    _loadNextPartition(partition) {\n        if (this._paging === true) {\n            this._pageIterator.pageIndex = 0;\n            return this._loadNextPage();\n        }\n        const keyname = this._dbname + \".\" + partition;\n        return this._adapter.loadDatabase(keyname).then((result) => {\n            this._dbref._collections[partition]._data = this._dbref.deserializeCollection(result, {\n                delimited: true\n            });\n            if (++partition < this._dbref._collections.length) {\n                return this._loadNextPartition(partition);\n            }\n            return Promise.resolve();\n        });\n    }\n    /**\n     * Used to sequentially load the next page of collection partition, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next page is loaded\n     */\n    _loadNextPage() {\n        // calculate name for next saved page in sequence\n        const keyname = this._dbname + \".\" + this._pageIterator.collection + \".\" + this._pageIterator.pageIndex;\n        // load whatever page is next in sequence\n        return this._adapter.loadDatabase(keyname).then((result) => {\n            let data = result.split(this._delimiter);\n            result = \"\"; // free up memory now that we have split it into array\n            let dlen = data.length;\n            // detect if last page by presence of final empty string element and remove it if so\n            const isLastPage = (data[dlen - 1] === \"\");\n            if (isLastPage) {\n                data.pop();\n                dlen = data.length;\n                // empty collections are just a delimiter meaning two blank items\n                if (data[dlen - 1] === \"\" && dlen === 1) {\n                    data.pop();\n                    dlen = data.length;\n                }\n            }\n            // convert stringified array elements to object instances and push to collection data\n            for (let idx = 0; idx < dlen; idx++) {\n                this._dbref._collections[this._pageIterator.collection]._data.push(JSON.parse(data[idx]));\n                data[idx] = null;\n            }\n            data = [];\n            // if last page, we are done with this partition\n            if (isLastPage) {\n                // if there are more partitions, kick off next partition load\n                if (++this._pageIterator.collection < this._dbref._collections.length) {\n                    return this._loadNextPartition(this._pageIterator.collection);\n                }\n            }\n            else {\n                this._pageIterator.pageIndex++;\n                return this._loadNextPage();\n            }\n            return Promise.resolve();\n        });\n    }\n    /**\n     * Saves a database by partioning into separate key/value saves.\n     * (Loki 'reference mode' persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {object} dbref - reference to database which we will partition and save.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     *\n     */\n    exportDatabase(dbname, dbref) {\n        this._dbref = dbref;\n        this._dbname = dbname;\n        // queue up dirty partitions to be saved\n        this._dirtyPartitions = [-1];\n        for (let idx = 0; idx < dbref._collections.length; idx++) {\n            if (dbref._collections[idx]._dirty) {\n                this._dirtyPartitions.push(idx);\n            }\n        }\n        return this._saveNextPartition();\n    }\n    /**\n     * Helper method used internally to save each dirty collection, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    _saveNextPartition() {\n        const partition = this._dirtyPartitions.shift();\n        const keyname = this._dbname + ((partition === -1) ? \"\" : (\".\" + partition));\n        // if we are doing paging and this is collection partition\n        if (this._paging && partition !== -1) {\n            this._pageIterator = {\n                collection: partition,\n                docIndex: 0,\n                pageIndex: 0\n            };\n            // since saveNextPage recursively calls itself until done, our callback means this whole paged partition is finished\n            return this._saveNextPage().then(() => {\n                if (this._dirtyPartitions.length !== 0) {\n                    return this._saveNextPartition();\n                }\n                return Promise.resolve();\n            });\n        }\n        // otherwise this is 'non-paged' partioning...\n        const result = this._dbref.serializeDestructured({\n            partitioned: true,\n            delimited: true,\n            partition\n        });\n        return this._adapter.saveDatabase(keyname, result).then(() => {\n            if (this._dirtyPartitions.length !== 0) {\n                return this._saveNextPartition();\n            }\n            return Promise.resolve();\n        });\n    }\n    /**\n     * Helper method used internally to generate and save the next page of the current (dirty) partition.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    _saveNextPage() {\n        const coll = this._dbref._collections[this._pageIterator.collection];\n        const keyname = this._dbname + \".\" + this._pageIterator.collection + \".\" + this._pageIterator.pageIndex;\n        let pageLen = 0;\n        const cdlen = coll._data.length;\n        const delimlen = this._delimiter.length;\n        let serializedObject = \"\";\n        let pageBuilder = \"\";\n        let doneWithPartition = false;\n        let doneWithPage = false;\n        const pageSaveCallback = () => {\n            pageBuilder = \"\";\n            // update meta properties then continue process by invoking callback\n            if (!doneWithPartition) {\n                this._pageIterator.pageIndex++;\n                return this._saveNextPage();\n            }\n            return Promise.resolve();\n        };\n        if (coll._data.length === 0) {\n            doneWithPartition = true;\n        }\n        while (!doneWithPartition && !doneWithPage) {\n            if (!doneWithPartition) {\n                // serialize object\n                serializedObject = JSON.stringify(coll._data[this._pageIterator.docIndex]);\n                pageBuilder += serializedObject;\n                pageLen += serializedObject.length;\n                // if no more documents in collection to add, we are done with partition\n                if (++this._pageIterator.docIndex >= cdlen)\n                    doneWithPartition = true;\n            }\n            // if our current page is bigger than defined pageSize, we are done with page\n            if (pageLen >= this._pageSize)\n                doneWithPage = true;\n            // if not done with current page, need delimiter before next item\n            // if done with partition we also want a delmiter to indicate 'end of pages' final empty row\n            if (!doneWithPage || doneWithPartition) {\n                pageBuilder += this._delimiter;\n                pageLen += delimlen;\n            }\n        }\n        // if we are done with page save it and pass off to next recursive call or callback\n        return this._adapter.saveDatabase(keyname, pageBuilder).then(pageSaveCallback);\n    }\n}\n\n// CONCATENATED MODULE: ./packages/partitioning-adapter/src/index.ts\n/* concated harmony reexport */__webpack_require__.d(__webpack_exports__, \"PartitioningAdapter\", function() { return partitioning_adapter_PartitioningAdapter; });\n\n\n/* harmony default export */ var src = __webpack_exports__[\"default\"] = (partitioning_adapter_PartitioningAdapter);\n\n\n/***/ }),\n/* 3 */\n/***/ (function(module, exports) {\n\nvar g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || Function(\"return this\")() || (1, eval)(\"this\");\n} catch (e) {\n\t// This works if the window reference is available\n\tif (typeof window === \"object\") g = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n\n\n/***/ })\n/******/ ]);\n});\n//# sourceMappingURL=lokidb.partitioning-adapter.js.map"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/common/plugin.d.ts",
    "content": "/**\n * @hidden\n */\nexport declare const PLUGINS: void;\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/common/types.d.ts",
    "content": "/**\n * @hidden\n */\nimport { Loki } from \"../loki/src/loki\";\nexport interface StorageAdapter {\n    loadDatabase(dbname: string): Promise<any>;\n    saveDatabase?(dbname: string, serialization: string): Promise<void>;\n    deleteDatabase?(dbname: string): Promise<void>;\n    mode?: string;\n    exportDatabase?(dbname: string, dbref: Loki): Promise<void>;\n}\nexport declare type Doc<T extends object = object> = T & {\n    $loki: number;\n    meta?: {\n        created: number;\n        revision: number;\n        version: number;\n        updated?: number;\n    };\n};\nexport interface Dict<T> {\n    [index: string]: T;\n    [index: number]: T;\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/fs-storage/src/fs_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists using node fs module.\n */\nexport declare class FSStorage implements StorageAdapter {\n    /**\n     * Registers the fs storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the fs storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * Load data from file, will throw an error if the file does not exist\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Save data to file, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Delete the database file, will throw an error if the\n     * file can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/fs-storage/src/index.d.ts",
    "content": "import { FSStorage } from \"./fs_storage\";\nexport { FSStorage };\nexport default FSStorage;\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search/src/analyzer/analyzer.d.ts",
    "content": "import { CharacterFilter } from \"./character_filter\";\nimport { Tokenizer, whitespaceTokenizer } from \"./tokenizer\";\nimport { lowercaseTokenFilter, TokenFilter } from \"./token_filter\";\n/**\n * A analyzer converts a string into tokens which are added to the inverted index for searching.\n */\nexport interface Analyzer {\n    /**\n     * The character filters of the analyzer.\n     */\n    char_filter?: CharacterFilter[];\n    /**\n     * The tokenizer of the analyzer.\n     */\n    tokenizer: Tokenizer;\n    /**\n     * The token filters of the analyzer.\n     */\n    token_filter?: TokenFilter[];\n}\n/**\n * Analyzes a given string.\n * @param {Analyzer} analyzer - the analyzer\n * @param {string} str - the string\n * @returns {string[]} - the tokens\n */\nexport declare function analyze(analyzer: Analyzer, str: string): string[];\n/**\n * An analyzer with the whitespace tokenizer and the lowercase token filter.\n */\nexport declare class StandardAnalyzer implements Analyzer {\n    tokenizer: typeof whitespaceTokenizer;\n    token_filter: (typeof lowercaseTokenFilter)[];\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search/src/analyzer/character_filter.d.ts",
    "content": "/**\n * A character filter is used to preprocess a string before it is passed to a tokenizer.\n */\nexport declare type CharacterFilter = (value: string) => string;\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search/src/analyzer/token_filter.d.ts",
    "content": "/**\n * A token filter takes tokens from a tokenizer and modify, delete or add tokens.\n */\nexport declare type TokenFilter = (value: string, index: number, array: string[]) => string;\n/**\n * Converts a token to lowercase.\n * @param {string} token - the token\n * @returns {string} - the lowercased token\n */\nexport declare function lowercaseTokenFilter(token: string): string;\n/**\n * Converts a token to uppercase.\n * @param {string} token - the token\n * @returns {string} - the uppercased token\n */\nexport declare function uppercaseTokenFilter(token: string): string;\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search/src/analyzer/tokenizer.d.ts",
    "content": "/**\n * A tokenizer splits a string into individual tokens.\n */\nexport declare type Tokenizer = (value: string) => string[];\n/**\n * Splits a string at whitespace characters into tokens.\n * @param {string} value - the string\n * @returns {string[]} - the tokens\n */\nexport declare function whitespaceTokenizer(value: string): string[];\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search/src/full_text_search.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\nimport { Scorer } from \"./scorer\";\nimport { Analyzer } from \"./analyzer/analyzer\";\nexport declare class FullTextSearch {\n    private _id;\n    private _docs;\n    private _idxSearcher;\n    private _invIdxs;\n    /**\n     * Registers the full-text search as plugin.\n     */\n    static register(): void;\n    /**\n     * Initialize the full-text search for the given fields.\n     * @param {object[]} fieldOptions - the field options\n     * @param {string} fieldOptions.field - the name of the property field\n     * @param {boolean=true} fieldOptions.store - flag to indicate if the full-text search should be stored on serialization or\n     *  rebuild on deserialization\n     * @param {boolean=true} fieldOptions.optimizeChanges - flag to optimize updating and deleting of documents\n     *    (requires more memory but performs faster)\n     * @param {Analyzer} fieldOptions.analyzer - an analyzer for the field\n     * @param {string} [id] - the property name of the document index\n     */\n    constructor(fieldOptions?: FullTextSearch.FieldOptions[], id?: string);\n    addDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    removeDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    updateDocument(doc: object, id?: InvertedIndex.DocumentIndex): void;\n    clear(): void;\n    search(query: Query): Scorer.ScoreResults;\n    toJSON(): FullTextSearch.Serialization;\n    static fromJSONObject(serialized: FullTextSearch.Serialization, analyzers?: Dict<Analyzer>): FullTextSearch;\n}\nexport declare namespace FullTextSearch {\n    interface FieldOptions extends InvertedIndex.FieldOptions {\n        field: string;\n    }\n    interface Serialization {\n        id: string;\n        ii: Dict<InvertedIndex.Serialization>;\n    }\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search/src/fuzzy/automaton.d.ts",
    "content": "/**\n * Transition with dest, min and max.\n * @hidden\n */\nexport declare type Transition = [number, number, number];\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MIN_CODE_POINT = 0;\n/**\n * @type {number}\n * @hidden\n */\nexport declare const MAX_CODE_POINT = 1114111;\n/**\n * From org/apache/lucene/util/automaton/Automaton.java\n * @hidden\n */\nexport declare class Automaton {\n    private _stateTransitions;\n    private _accept;\n    private _nextState;\n    private _currState;\n    private _transitions;\n    constructor();\n    isAccept(n: number): boolean;\n    createState(): number;\n    setAccept(state: number, accept: boolean): void;\n    finishState(): void;\n    private _finishCurrentState();\n    getStartPoints(): number[];\n    step(state: number, label: number): number;\n    getNumStates(): number;\n    addTransition(source: number, dest: number, min: number, max: number): void;\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search/src/fuzzy/lev1t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev1TParametricDescription.java\n * @hidden\n */\nexport declare class Lev1TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search/src/fuzzy/lev2t_parametric_description.d.ts",
    "content": "import { ParametricDescription } from \"./parametric_description\";\n/**\n * From org/apache/lucene/util/automaton/Lev2TParametricDescription.java\n * @hidden\n */\nexport declare class Lev2TParametricDescription extends ParametricDescription {\n    constructor(w: number);\n    transition(absState: number, position: number, vector: number): number;\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search/src/fuzzy/levenshtein_automata.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java\n * @hidden\n */\nexport declare class LevenshteinAutomata {\n    private _word;\n    private _numRanges;\n    private _rangeLower;\n    private _rangeUpper;\n    private _description;\n    private _alphabet;\n    private _editDistance;\n    constructor(input: number[], editDistance: number);\n    /**\n     * Transforms the NDFA to a DFA.\n     * @returns {Automaton}\n     */\n    toAutomaton(): Automaton;\n    private _getVector(x, pos, end);\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search/src/fuzzy/long.d.ts",
    "content": "/**\n * Class supports 64Bit integer operations.\n * A cut-down version of dcodeIO/long.js.\n * @hidden\n */\nexport declare class Long {\n    private _low;\n    private _high;\n    constructor(low?: number, high?: number);\n    /**\n     * Returns this long with bits arithmetically shifted to the right by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftRight(numBits: number): Long;\n    /**\n     * Returns this long with bits arithmetically shifted to the left by the given amount.\n     * @param {number} numBits - number of bits\n     * @returns {Long} the long\n     */\n    shiftLeft(numBits: number): Long;\n    /**\n     * Returns the bitwise AND of this Long and the specified.\n     * @param {Long} other - the other Long\n     * @returns {Long} the long\n     */\n    and(other: Long): Long;\n    /**\n     * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.\n     * @returns {number}\n     */\n    toInt(): number;\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search/src/fuzzy/parametric_description.d.ts",
    "content": "import { Long } from \"./long\";\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java#ParametricDescription\n * @hidden\n */\nexport declare class ParametricDescription {\n    protected _w: number;\n    private _n;\n    private _minErrors;\n    constructor(w: number, n: number, minErrors: number[]);\n    /**\n     * Return the number of states needed to compute a Levenshtein DFA\n     */\n    size(): number;\n    /**\n     * Returns true if the <code>state</code> in any Levenshtein DFA is an accept state (final state).\n     */\n    isAccept(absState: number): boolean;\n    /**\n     * Returns the position in the input word for a given <code>state</code>.\n     * This is the minimal boundary for the state.\n     */\n    getPosition(absState: number): number;\n    static unpack(data: Long[], index: number, bitsPerValue: number): number;\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search/src/fuzzy/run_automaton.d.ts",
    "content": "import { Automaton } from \"./automaton\";\n/**\n * From org/apache/lucene/util/automaton/RunAutomaton.java\n * @hidden\n */\nexport declare class RunAutomaton {\n    private _points;\n    private _accept;\n    private _transitions;\n    private _classmap;\n    constructor(automaton: Automaton);\n    getCharClass(c: number): number;\n    step(state: number, c: number): number;\n    isAccept(state: number): boolean;\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search/src/index.d.ts",
    "content": "import { FullTextSearch } from \"./full_text_search\";\nimport { analyze, StandardAnalyzer } from \"./analyzer/analyzer\";\nimport { whitespaceTokenizer } from \"./analyzer/tokenizer\";\nimport { lowercaseTokenFilter, uppercaseTokenFilter } from \"./analyzer/token_filter\";\nexport { FullTextSearch, analyze, StandardAnalyzer, whitespaceTokenizer, lowercaseTokenFilter, uppercaseTokenFilter };\nexport default FullTextSearch;\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search/src/index_searcher.d.ts",
    "content": "import { Scorer } from \"./scorer\";\nimport { InvertedIndex } from \"./inverted_index\";\nimport { Query } from \"./query_types\";\nimport { Dict } from \"../../common/types\";\n/**\n * @hidden\n */\nexport declare class IndexSearcher {\n    private _invIdxs;\n    private _docs;\n    private _scorer;\n    /**\n     * Constructs an index searcher.\n     * @param {Dict<InvertedIndex>} invIdxs - the inverted indexes\n     * @param {Set<number>} docs - the ids of the documents\n     */\n    constructor(invIdxs: Dict<InvertedIndex>, docs: Set<InvertedIndex.DocumentIndex>);\n    search(query: Query): Scorer.ScoreResults;\n    setDirty(): void;\n    private _recursive(query, doScoring);\n    private _getUnique(queries, doScoring, queryResults);\n    private _getAll(queries, doScoring, queryResults?);\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search/src/inverted_index.d.ts",
    "content": "import { Analyzer } from \"./analyzer/analyzer\";\n/**\n * Converts a string into an array of code points.\n * @param str - the string\n * @returns {number[]} to code points\n * @hidden\n */\nexport declare function toCodePoints(str: string): number[];\n/**\n * Inverted index class handles featured text search for specific document fields.\n * @hidden\n */\nexport declare class InvertedIndex {\n    analyzer: Analyzer;\n    docCount: number;\n    docStore: Map<InvertedIndex.DocumentIndex, InvertedIndex.DocStore>;\n    totalFieldLength: number;\n    root: InvertedIndex.Index;\n    private _store;\n    private _optimizeChanges;\n    /**\n     * @param {boolean} [options.store=true] - inverted index will be stored at serialization rather than rebuilt on load\n     * @param {boolean} [options.optimizeChanges=true] - flag to store additional metadata inside the index for better\n     *  performance if an existing field is updated or removed\n     * @param {Analyzer} [options.analyzer=] - the analyzer of this inverted index\n     */\n    constructor(options?: InvertedIndex.FieldOptions);\n    /**\n     * Adds defined fields of a document to the inverted index.\n     * @param {string} field - the field to add\n     * @param {number} docId - the doc id of the field\n     */\n    insert(field: string, docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Removes all relevant terms of a document from the inverted index.\n     * @param {number} docId - the document.\n     */\n    remove(docId: InvertedIndex.DocumentIndex): void;\n    /**\n     * Gets the term index of a term.\n     * @param {string} term - the term\n     * @param {object} root - the term index to start from\n     * @param {number} start - the position of the term string to start from\n     * @return {object} - The term index or null if the term is not in the term tree.\n     */\n    static getTermIndex(term: number[], root: InvertedIndex.Index, start?: number): InvertedIndex.Index;\n    /**\n     * Extends a term index to all available term leafs.\n     * @param {object} idx - the term index to start from\n     * @param {number[]} [term=[]] - the current term\n     * @param {Array} termIndices - all extended indices with their term\n     * @returns {Array} - Array with term indices and extension\n     */\n    static extendTermIndex(idx: InvertedIndex.Index, term?: number[], termIndices?: InvertedIndex.IndexTerm[]): InvertedIndex.IndexTerm[];\n    /**\n     * Serialize the inverted index.\n     * @returns {{docStore: *, _fields: *, index: *}}\n     */\n    toJSON(): InvertedIndex.Serialization;\n    /**\n     * Deserialize the inverted index.\n     * @param {{docStore: *, _fields: *, index: *}} serialized - The serialized inverted index.\n     * @param {Analyzer} analyzer[undefined] - an analyzer\n     */\n    static fromJSONObject(serialized: InvertedIndex.Serialization, analyzer?: Analyzer): InvertedIndex;\n    private static _serializeIndex(idx);\n    private static _deserializeIndex(serialized);\n    /**\n     * Set parent of to each index and regenerate the indexRef.\n     * @param {Index} index - the index\n     * @param {Index} parent - the parent\n     */\n    private _regenerate(index, parent);\n    /**\n     * Iterate over the whole inverted index and remove the document.\n     * Delete branch if not needed anymore.\n     * Function is needed if index is used without optimization.\n     * @param {Index} idx - the index\n     * @param {number} docId - the doc id\n     * @returns {boolean} true if index is empty\n     */\n    private _remove(idx, docId);\n}\nexport declare namespace InvertedIndex {\n    interface FieldOptions {\n        store?: boolean;\n        optimizeChanges?: boolean;\n        analyzer?: Analyzer;\n    }\n    type Index = Map<number, any> & {\n        dc?: Map<DocumentIndex, number>;\n        df?: number;\n        pa?: Index;\n    };\n    type IndexTerm = {\n        index: Index;\n        term: number[];\n    };\n    interface SerializedIndex {\n        d?: {\n            df: number;\n            dc: [DocumentIndex, number][];\n        };\n        k?: number[];\n        v?: SerializedIndex[];\n    }\n    type Serialization = SpareSerialization | FullSerialization;\n    type SpareSerialization = {\n        _store: false;\n        _optimizeChanges: boolean;\n    };\n    type FullSerialization = {\n        _store: true;\n        _optimizeChanges: boolean;\n        docCount: number;\n        docStore: [DocumentIndex, DocStore][];\n        totalFieldLength: number;\n        root: SerializedIndex;\n    };\n    interface DocStore {\n        fieldLength?: number;\n        indexRef?: Index[];\n    }\n    type DocumentIndex = number | string;\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search/src/query_types.d.ts",
    "content": "/**\n * Base query to enable boost to a query type.\n */\nexport interface BaseQuery<Type> {\n    type: Type;\n    boost?: number;\n}\n/**\n * A query which finds documents where a document field contains a term.\n */\nexport interface TermQuery extends BaseQuery<\"term\"> {\n    field: string;\n    value: string;\n}\n/**\n * A query which finds documents where a document field contains any of the terms.\n */\nexport interface TermsQuery extends BaseQuery<\"terms\"> {\n    field: string;\n    value: string[];\n}\n/**\n * A query which finds documents where the wildcard term can be applied at an existing document field term.\n */\nexport interface WildcardQuery extends BaseQuery<\"wildcard\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which finds documents where the fuzzy term can be transformed into an existing document field term within a\n * given edit distance.\n */\nexport interface FuzzyQuery extends BaseQuery<\"fuzzy\"> {\n    field: string;\n    value: string;\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query which matches documents containing the prefix of a term inside a field.\n */\nexport interface PrefixQuery extends BaseQuery<\"prefix\"> {\n    field: string;\n    value: string;\n    enable_scoring?: boolean;\n}\n/**\n * A query which matches all documents with a given field.\n */\nexport interface ExistsQuery extends BaseQuery<\"exists\"> {\n    field: string;\n}\n/**\n * A query which tokenizes the given text into tokens and performs a sub query for each token. The results are combined\n * using a boolean operator.\n */\nexport interface MatchQuery extends BaseQuery<\"match\"> {\n    field: string;\n    value: string;\n    minimum_should_match?: number | string;\n    operator?: \"and\" | \"or\";\n    fuzziness?: 0 | 1 | 2 | \"AUTO\";\n    prefix_length?: number;\n    extended?: boolean;\n}\n/**\n * A query that matches all documents and giving them a constant score equal to the query boost.\n*/\nexport interface MatchQueryAll extends BaseQuery<\"match_all\"> {\n}\n/**\n * A query that wraps sub queries and returns a constant score equal to the query boost for every document in the filter.\n */\nexport interface ConstantScoreQuery extends BaseQuery<\"constant_score\"> {\n    filter: QueryTypes[];\n}\n/**\n * A query that matches documents matching boolean combinations of sub queries.\n */\nexport interface BoolQuery extends BaseQuery<\"bool\"> {\n    must?: QueryTypes[];\n    filter?: QueryTypes[];\n    should?: QueryTypes[];\n    not?: QueryTypes[];\n    minimum_should_match?: number | string;\n}\n/**\n * Union type of possible query types.\n */\nexport declare type QueryTypes = BoolQuery | ConstantScoreQuery | TermQuery | TermsQuery | WildcardQuery | FuzzyQuery | MatchQuery | MatchQueryAll | PrefixQuery | ExistsQuery;\n/**\n * The main query with the actually full-text search query and the scoring parameters.\n */\nexport interface Query {\n    query: QueryTypes;\n    calculate_scoring?: boolean;\n    explain?: boolean;\n    bm25?: {\n        k1: number;\n        b: number;\n    };\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search/src/scorer.d.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\n/**\n * @hidden\n */\nexport declare class Scorer {\n    private _invIdxs;\n    private _cache;\n    constructor(invIdxs: Dict<InvertedIndex>);\n    setDirty(): void;\n    score(fieldName: string, boost: number, termIdx: InvertedIndex.Index, doScoring: boolean | null, queryResults: Scorer.QueryResults, term: number[], df?: number): void;\n    scoreConstant(boost: number, docId: InvertedIndex.DocumentIndex, queryResults: Scorer.QueryResults): Scorer.QueryResults;\n    finalScore(query: Query, queryResults: Scorer.QueryResults): Scorer.ScoreResults;\n    private static _calculateFieldLength(fieldLength);\n    private _getCache(fieldName);\n    /**\n     * Returns the idf by either calculate it or use a cached one.\n     * @param {string} fieldName - the name of the field\n     * @param {number} docFreq - the doc frequency of the term\n     * @returns {number} the idf\n     * @private\n     */\n    private _idf(fieldName, docFreq);\n    private _avgFieldLength(fieldName);\n}\nexport declare namespace Scorer {\n    interface IDFCache {\n        idfs: Dict<number>;\n        avgFieldLength: number;\n    }\n    interface QueryResult {\n        tf?: number;\n        idf?: number;\n        boost: number;\n        fieldName?: string;\n        term?: number[];\n    }\n    type QueryResults = Map<InvertedIndex.DocumentIndex, QueryResult[]>;\n    interface BM25Explanation {\n        boost: number;\n        score: number;\n        docID: number;\n        fieldName: string;\n        index: string;\n        idf: number;\n        tfNorm: number;\n        tf: number;\n        fieldLength: number;\n        avgFieldLength: number;\n    }\n    interface ConstantExplanation {\n        boost: number;\n        score: number;\n    }\n    type ScoreExplanation = BM25Explanation | ConstantExplanation;\n    type ScoreResult = {\n        score: number;\n        explanation?: ScoreExplanation[];\n    };\n    type ScoreResults = Dict<ScoreResult>;\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search-language/src/index.d.ts",
    "content": "export { generateStopWordFilter, generateTrimmer, Among, SnowballProgram } from \"./language\";\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search-language/src/language.d.ts",
    "content": "export declare function generateTrimmer(wordCharacters: string): (token: string) => string;\nexport declare function generateStopWordFilter(stopWords: string[]): (token: string) => string;\nexport declare class Among {\n    s_size: number;\n    s: number[];\n    substring_i: number;\n    result: number;\n    method: any;\n    constructor(s: string, substring_i: number, result: number, method?: any);\n}\nexport declare class SnowballProgram {\n    current: string;\n    bra: number;\n    ket: number;\n    limit: number;\n    cursor: number;\n    limit_backward: number;\n    constructor();\n    setCurrent(word: string): void;\n    getCurrent(): string;\n    in_grouping(s: number[], min: number, max: number): boolean;\n    in_grouping_b(s: number[], min: number, max: number): boolean;\n    out_grouping(s: number[], min: number, max: number): boolean;\n    out_grouping_b(s: number[], min: number, max: number): boolean;\n    eq_s(s_size: number, s: string): boolean;\n    eq_s_b(s_size: number, s: string): boolean;\n    find_among(v: Among[], v_size: number): number;\n    find_among_b(v: Among[], v_size: number): number;\n    replace_s(c_bra: number, c_ket: number, s: string): number;\n    slice_check(): void;\n    slice_from(s: string): void;\n    slice_del(): void;\n    insert(c_bra: number, c_ket: number, s: string): void;\n    slice_to(): string;\n    eq_v_b(s: string): boolean;\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search-language-de/src/german_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class GermanAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search-language-de/src/index.d.ts",
    "content": "import { GermanAnalyzer } from \"./german_analyzer\";\nexport { GermanAnalyzer };\nexport default GermanAnalyzer;\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search-language-en/src/english_analyzer.d.ts",
    "content": "import { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nexport declare class EnglishAnalyzer implements Analyzer {\n    tokenizer: (str: string) => string[];\n    token_filter: ((token: string) => string)[];\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/full-text-search-language-en/src/index.d.ts",
    "content": "import { EnglishAnalyzer } from \"./english_analyzer\";\nexport { EnglishAnalyzer };\nexport default EnglishAnalyzer;\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/indexed-storage/src/index.d.ts",
    "content": "import { IndexedStorage } from \"./indexed_storage\";\nexport { IndexedStorage };\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/indexed-storage/src/indexed_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * Loki persistence adapter class for indexedDb.\n *     This class fulfills abstract adapter interface which can be applied to other storage methods.\n *     Utilizes the included LokiCatalog app/key/value database for actual database persistence.\n *     IndexedDb storage is provided per-domain, so we implement app/key/value database to\n *     allow separate contexts for separate apps within a domain.\n */\nexport declare class IndexedStorage implements StorageAdapter {\n    private _appname;\n    private catalog;\n    /**\n     * Registers the indexed storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the indexed storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {string} [appname=loki] - Application name context can be used to distinguish subdomains, \"loki\" by default\n     */\n    constructor(appname?: string);\n    /**\n     * Retrieves a serialized db string from the catalog.\n     *\n     * @example\n     * // LOAD\n     * var idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * var db = new loki(\"test\", { adapter: idbAdapter });\n     *   db.base(function(result) {\n       *   console.log(\"done\");\n       * });\n     *\n     * @param {string} dbname - the name of the database to retrieve.\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<{}>;\n    /**\n     * Saves a serialized db to the catalog.\n     *\n     * @example\n     * // SAVE : will save App/Key/Val as \"finance\"/\"test\"/{serializedDb}\n     * let idbAdapter = new LokiIndexedAdapter(\"finance\");\n     * let db = new loki(\"test\", { adapter: idbAdapter });\n     * let coll = db.addCollection(\"testColl\");\n     * coll.insert({test: \"val\"});\n     * db.saveDatabase();  // could pass callback if needed for async complete\n     *\n     * @param {string} dbname - the name to give the serialized database within the catalog.\n     * @param {string} dbstring - the serialized db string to save.\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a serialized db from the catalog.\n     *\n     * @example\n     * // DELETE DATABASE\n     * // delete \"finance\"/\"test\" value from catalog\n     * idbAdapter.deleteDatabase(\"test\", function {\n       *   // database deleted\n       * });\n     *\n     * @param {string} dbname - the name of the database to delete from the catalog.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n    /**\n     * Removes all database partitions and pages with the base filename passed in.\n     * This utility method does not (yet) guarantee async deletions will be completed before returning\n     *\n     * @param {string} dbname - the base filename which container, partitions, or pages are derived\n     */\n    deleteDatabasePartitions(dbname: string): void;\n    /**\n     * Retrieves object array of catalog entries for current app.\n     *\n     * @example\n     * idbAdapter.getDatabaseList(function(result) {\n       *   // result is array of string names for that appcontext (\"finance\")\n       *   result.forEach(function(str) {\n       *     console.log(str);\n       *   });\n       * });\n     *\n     * @param {function} callback - should accept array of database names in the catalog for current app.\n     */\n    getDatabaseList(callback: (names: string[]) => void): void;\n    /**\n     * Allows retrieval of list of all keys in catalog along with size\n     * @param {function} callback - (Optional) callback to accept result array.\n     */\n    getCatalogSummary(callback: (entry: Entry[]) => void): void;\n}\nexport interface Entry {\n    app: string;\n    key: string;\n    size: number;\n}\nexport default IndexedStorage;\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/local-storage/src/index.d.ts",
    "content": "import { LocalStorage } from \"./local_storage\";\nexport { LocalStorage };\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/local-storage/src/local_storage.d.ts",
    "content": "import { StorageAdapter } from \"../../common/types\";\n/**\n * A loki persistence adapter which persists to web browser's local storage object\n * @constructor LocalStorageAdapter\n */\nexport declare class LocalStorage implements StorageAdapter {\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * loadDatabase() - Load data from localstorage\n     * @param {string} dbname - the name of the database to load\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * saveDatabase() - save data to localstorage, will throw an error if the file can't be saved\n     * might want to expand this to avoid dataloss on partial save\n     * @param {string} dbname - the filename of the database to load\n     * @returns {Promise} a Promise that resolves after the database was saved\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * deleteDatabase() - delete the database from localstorage, will throw an error if it\n     * can't be deleted\n     * @param {string} dbname - the filename of the database to delete\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport default LocalStorage;\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/loki/src/avl_index.d.ts",
    "content": "import { IRangedIndex, IRangedIndexRequest } from \"./ranged_indexes\";\nimport { ILokiComparer } from \"./comparators\";\n/**\n * Treenode type for binary search tree (BST) implementation.\n *\n * To support duplicates, we may need to either repurpose parent to\n * point to 'elder' sibling or add a siblingId to point to owner of\n * node represented in tree.\n */\nexport declare type TreeNode<T> = {\n    id: number;\n    value: T;\n    parent: number | null;\n    balance: number;\n    height: number;\n    left: number | null;\n    right: number | null;\n    siblings: number[];\n};\nexport interface ITreeNodeHash<T> {\n    [id: number]: TreeNode<T>;\n}\n/**\n * LokiDB AVL Balanced Binary Tree Index implementation.\n * To support duplicates, we use siblings (array) in tree nodes.\n * Basic AVL components guided by William Fiset tutorials at :\n * https://github.com/williamfiset/data-structures/blob/master/com/williamfiset/datastructures/balancedtree/AVLTreeRecursive.java\n * https://www.youtube.com/watch?v=g4y2h70D6Nk&list=PLDV1Zeh2NRsD06x59fxczdWLhDDszUHKt\n */\nexport declare class AvlTreeIndex<T> implements IRangedIndex<T> {\n    name: string;\n    comparator: ILokiComparer<T>;\n    nodes: ITreeNodeHash<T>;\n    apex: number | null;\n    /**\n     * Initializes index with property name and a comparer function.\n     */\n    constructor(name: string, comparator: ILokiComparer<T>);\n    backup(): AvlTreeIndex<T>;\n    restore(tree: AvlTreeIndex<T>): void;\n    /**\n     * Used for inserting a new value into the BinaryTreeIndex\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val Value to be indexed and inserted into binary tree\n     */\n    insert(id: number, val: T): void;\n    /**\n     * Recursively inserts a treenode and re-balances if needed.\n     * @param current\n     * @param node\n     */\n    insertNode(current: TreeNode<T>, node: TreeNode<T>): number;\n    /**\n     * Updates height and balance (calculation) for tree node\n     * @param node\n     */\n    private updateBalance(node);\n    /**\n     * Balance the 'double left-heavy' condition\n     * @param node\n     */\n    private leftLeftCase(node);\n    /**\n     * Balance the '(parent) left heavy, (child) right heavy' condition\n     * @param node\n     */\n    private leftRightCase(node);\n    /**\n     * Balance the 'double right-heavy' condition\n     * @param node\n     */\n    private rightRightCase(node);\n    /**\n     * Balance the '(parent) right heavy, (child) left heavy' condition\n     * @param node\n     */\n    private rightLeftCase(node);\n    /**\n     * Left rotation of node. Swaps right child into current location.\n     * @param node\n     */\n    private rotateLeft(node);\n    /**\n     * Right rotation of node. Swaps left child into current location.\n     * @param node\n     */\n    private rotateRight(node);\n    /**\n     * Diagnostic method for examining tree contents and structure\n     * @param node\n     */\n    getValuesAsTree(node?: TreeNode<T>): any;\n    /**\n     * Updates a value, possibly relocating it, within binary tree\n     * @param id Unique Id (such as $loki) to associate with value\n     * @param val New value to be indexed within binary tree\n     */\n    update(id: number, val: T): void;\n    /**\n     * Removes a value from the binary tree index\n     * @param id\n     */\n    remove(id: number): void;\n    /**\n     * Recursive node removal and rebalancer\n     * @param node\n     * @param val\n     */\n    private removeNode(node, id);\n    /**\n     * Utility method for updating a parent's child link when it changes\n     * @param parentId\n     * @param oldChildId\n     * @param newChildId\n     */\n    private updateChildLink(parentId, oldChildId, newChildId);\n    /**\n     * When removing a parent with only child, this does simple remap of child to grandParent.\n     * @param grandParent New parent of 'child'.\n     * @param parent Node being removed.\n     * @param child Node to reparent to grandParent.\n     */\n    private promoteChild(parent, child);\n    /**\n     * Finds a successor to a node and replaces that node with it.\n     * @param node\n     */\n    private promoteSuccessor(node);\n    /**\n     * Utility method for finding In-Order predecessor to the provided node\n     * @param node Parent node to find leaf node of greatest 'value'\n    */\n    private findGreaterLeaf(node);\n    /**\n     * Utility method for finding In-Order successor to the provided node\n     * @param node Parent Node to find leaf node of least 'value'\n     */\n    private findLesserLeaf(node);\n    /**\n     *  Interface method to support ranged queries.  Results sorted by index property.\n     * @param range Options for ranged request.\n     */\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    /**\n     * Implements ranged request operations.\n     * @param node\n     * @param range\n     */\n    private collateRequest(node, range);\n    /**\n     * Used on a branch node to return an array of id within that branch, sorted by their value\n     * @param node\n     */\n    private collateIds(node);\n    /**\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    /**\n     * Inline/Non-recusive 'single value' ($eq) lookup.\n     * Traverses tree to a node matching the provided value.\n     * @param node\n     * @param val\n     */\n    private locate(node, val);\n    /**\n     * Index integrity check (IRangedIndex interface function)\n     */\n    validateIndex(): boolean;\n    /**\n     * Recursive Node validation routine\n     * @param node\n     */\n    private validateNode(node);\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/loki/src/clone.d.ts",
    "content": "export declare type CloneMethod = \"parse-stringify\" | \"deep\" | \"shallow\" | \"shallow-recurse\";\n/**\n * @hidden\n */\nexport declare function clone<T>(data: T, method?: CloneMethod): T;\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/loki/src/collection.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { UniqueIndex } from \"./unique_index\";\nimport { ResultSet } from \"./result_set\";\nimport { DynamicView } from \"./dynamic_view\";\nimport { IRangedIndex } from \"./ranged_indexes\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc, Dict } from \"../../common/types\";\nimport { FullTextSearch } from \"../../full-text-search/src/full_text_search\";\nimport { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\n/**\n * Collection class that handles documents of same type\n * @extends LokiEventEmitter\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class Collection<TData extends object = object, TNested extends object = object, T extends TData & TNested = TData & TNested> extends LokiEventEmitter {\n    name: string;\n    _data: Doc<T>[];\n    private _idIndex;\n    _rangedIndexes: {\n        [P in keyof T]?: Collection.RangedIndexMeta;\n    };\n    _lokimap: {\n        [$loki: number]: Doc<T>;\n    };\n    _unindexedSortComparator: string;\n    _defaultLokiOperatorPackage: string;\n    /**\n     * Unique constraints contain duplicate object references, so they are not persisted.\n     * We will keep track of properties which have unique constraints applied here, and regenerate on load.\n     */\n    _constraints: {\n        unique: {\n            [P in keyof T]?: UniqueIndex;\n        };\n    };\n    /**\n     * Transforms will be used to store frequently used query chains as a series of steps which itself can be stored along\n     * with the database.\n     */\n    _transforms: Dict<Collection.Transform<T>[]>;\n    /**\n     * In autosave scenarios we will use collection level dirty flags to determine whether save is needed.\n     * currently, if any collection is dirty we will autosave the whole database if autosave is configured.\n     * Defaulting to true since this is called from addCollection and adding a collection should trigger save.\n     */\n    _dirty: boolean;\n    private _cached;\n    /**\n     * Is collection transactional.\n     */\n    private _transactional;\n    /**\n     * Options to clone objects when inserting them.\n     */\n    _cloneObjects: boolean;\n    /**\n     * Default clone method (if enabled) is parse-stringify.\n     */\n    _cloneMethod: CloneMethod;\n    /**\n     * If set to true we will not maintain a meta property for a document.\n     */\n    private _disableMeta;\n    /**\n     * Disable track changes.\n     */\n    private _disableChangesApi;\n    /**\n     * Disable delta update object style on changes.\n     */\n    _disableDeltaChangesApi: boolean;\n    /**\n     * By default, if you insert a document with a Date value for an indexed property, we will convert that value to number.\n     */\n    private _serializableIndexes;\n    /**\n     * Name of path of used nested properties.\n     */\n    private _nestedProperties;\n    /**\n     * Option to activate a cleaner daemon - clears \"aged\" documents at set intervals.\n     */\n    _ttl: Collection.TTL;\n    private _maxId;\n    private _dynamicViews;\n    /**\n     * Changes are tracked by collection and aggregated by the db.\n     */\n    private _changes;\n    /**\n     * stages: a map of uniquely identified 'stages', which hold copies of objects to be\n     * manipulated without affecting the data in the original collection\n     */\n    private _stages;\n    private _commitLog;\n    _fullTextSearch: FullTextSearch;\n    /**\n     * @param {string} name - collection name\n     * @param {(object)} [options={}] - a configuration object\n     * @param {string[]} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {string[]} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {RangedIndexOptions} [options.rangedIndexes] - configuration object for ranged indexes\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are invoked asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes API\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {boolean} [options.serializableIndexes=true] - converts date values on binary indexed property values are serializable\n     * @param {string} [options.cloneMethod=\"deep\"] - the clone method\n     * @param {number} [options.transactional=false] - ?\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale.\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @param {string} [options.unindexedSortComparator=\"js\"] \"js\", \"abstract\", \"abstract-date\", \"loki\" or other registered comparator name\n     * @param {string} [options.defaultLokiOperatorPackage=\"js\"] \"js\", \"loki\", \"comparator\" (or user defined) query ops package\n     * @param {FullTextSearch.FieldOptions} [options.fullTextSearch=] - the full-text search options\n     * @see {@link Loki#addCollection} for normal creation of collections\n     */\n    constructor(name: string, options?: Collection.Options<TData, TNested>);\n    toJSON(): Collection.Serialized;\n    static fromJSONObject(obj: Collection.Serialized, options?: Collection.DeserializeOptions): Collection<any, object, any>;\n    /**\n     * Adds a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {array} transform - an array of transformation 'step' objects to save into the collection\n     */\n    addTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Retrieves a named transform from the collection.\n     * @param {string} name - name of the transform to lookup.\n     */\n    getTransform(name: string): Collection.Transform<T>[];\n    /**\n     * Updates a named collection transform to the collection\n     * @param {string} name - name to associate with transform\n     * @param {object} transform - a transformation object to save into collection\n     */\n    setTransform(name: string, transform: Collection.Transform<T>[]): void;\n    /**\n     * Removes a named collection transform from the collection\n     * @param {string} name - name of collection transform to remove\n     */\n    removeTransform(name: string): void;\n    private setTTL(age, interval);\n    /**\n     * Create a row filter that covers all documents in the collection.\n     */\n    _prepareFullDocIndex(): number[];\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field\n     * @param indexTypeName\n     * @param comparatorName\n     */\n    ensureIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    /**\n     * Ensure rangedIndex of a field.\n     * @param field Property to create an index on (need to look into contraining on keyof T)\n     * @param indexTypeName Name of IndexType factory within (global?) hashmap to create IRangedIndex from\n     * @param comparatorName Name of Comparator within (global?) hashmap\n     */\n    ensureRangedIndex(field: string, indexTypeName?: string, comparatorName?: string): void;\n    ensureUniqueIndex(field: keyof T): UniqueIndex;\n    /**\n     * Quickly determine number of documents in collection (or query)\n     * @param {object} query - (optional) query object to count results of\n     * @returns {number} number of documents in the collection\n     */\n    count(query?: ResultSet.Query<Doc<T>>): number;\n    /**\n     * Rebuild idIndex\n     */\n    private _ensureId();\n    /**\n     * Add a dynamic view to the collection\n     * @param {string} name - name of dynamic view to add\n     * @param {object} options - (optional) options to configure dynamic view with\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=SortPriority.PASSIVE] - the sort priority\n     * @param {number} options.minRebuildInterval - minimum rebuild interval (need clarification to docs here)\n     * @returns {DynamicView} reference to the dynamic view added\n     **/\n    addDynamicView(name: string, options?: DynamicView.Options): DynamicView<T>;\n    /**\n     * Remove a dynamic view from the collection\n     * @param {string} name - name of dynamic view to remove\n     **/\n    removeDynamicView(name: string): void;\n    /**\n     * Look up dynamic view reference from within the collection\n     * @param {string} name - name of dynamic view to retrieve reference of\n     * @returns {DynamicView} A reference to the dynamic view with that name\n     **/\n    getDynamicView(name: string): DynamicView<T>;\n    /**\n     * Applies a 'mongo-like' find query object and passes all results to an update function.\n     * @param {object} filterObject - the 'mongo-like' query object\n     * @param {function} updateFunction - the update function\n     */\n    findAndUpdate(filterObject: ResultSet.Query<Doc<T>>, updateFunction: (obj: Doc<T>) => any): void;\n    /**\n     * Applies a 'mongo-like' find query object removes all documents which match that filter.\n     * @param {object} filterObject - 'mongo-like' query object\n     */\n    findAndRemove(filterObject: ResultSet.Query<Doc<T>>): void;\n    /**\n     * Adds object(s) to collection, ensure object(s) have meta properties, clone it if necessary, etc.\n     * @param {(object|array)} doc - the document (or array of documents) to be inserted\n     * @returns {(object|array)} document or documents inserted\n     */\n    insert(doc: TData): Doc<T>;\n    insert(doc: TData[]): Doc<T>[];\n    /**\n     * Adds a single object, ensures it has meta properties, clone it if necessary, etc.\n     * @param {object} doc - the document to be inserted\n     * @param {boolean} bulkInsert - quiet pre-insert and insert event emits\n     * @returns {object} document or 'undefined' if there was a problem inserting it\n     */\n    insertOne(doc: TData, bulkInsert?: boolean): Doc<T>;\n    /**\n     * Refers nested properties of an object to the root of it.\n     * @param {T} data - the object\n     * @returns {T & TNested} the object with nested properties\n     * @hidden\n     */\n    _defineNestedProperties<U extends TData>(data: U): U & TNested;\n    /**\n     * Empties the collection.\n     * @param {boolean} [removeIndices=false] - remove indices\n     */\n    clear({removeIndices: removeIndices}?: {\n        removeIndices?: boolean;\n    }): void;\n    /**\n     * Updates an object and notifies collection that the document has changed.\n     * @param {object} doc - document to update within the collection\n     */\n    update(doc: Doc<T> | Doc<T>[]): void;\n    /**\n     * Add object to collection\n     */\n    private _add(obj);\n    /**\n     * Applies a filter function and passes all results to an update function.\n     * @param {function} filterFunction - the filter function\n     * @param {function} updateFunction - the update function\n     */\n    updateWhere(filterFunction: (obj: Doc<T>) => boolean, updateFunction: (obj: Doc<T>) => Doc<T>): void;\n    /**\n     * Remove all documents matching supplied filter function.\n     * @param {function} filterFunction - the filter function\n     */\n    removeWhere(filterFunction: (obj: Doc<T>) => boolean): void;\n    removeDataOnly(): void;\n    /**\n     * Remove a document from the collection\n     * @param {number|object} doc - document to remove from collection\n     */\n    remove(doc: number | Doc<T> | Doc<T>[]): void;\n    /**\n     * Returns all changes.\n     * @returns {Collection.Change[]}\n     */\n    getChanges(): Collection.Change[];\n    /**\n     * Enables/disables changes api.\n     * @param {boolean} disableChangesApi\n     * @param {boolean} disableDeltaChangesApi\n     */\n    setChangesApi(disableChangesApi: boolean, disableDeltaChangesApi?: boolean): void;\n    /**\n     * Clears all the changes.\n     */\n    flushChanges(): void;\n    private _getObjectDelta(oldObject, newObject);\n    /**\n     * Compare changed object (which is a forced clone) with existing object and return the delta\n     */\n    private _getChangeDelta(obj, old);\n    /**\n     * Creates a clone of the current status of an object and associates operation and collection name,\n     * so the parent db can aggregate and generate a changes object for the entire db\n     */\n    private _createChange(name, op, obj, old?);\n    private _createInsertChange(obj);\n    private _createUpdateChange(obj, old);\n    private _insertMetaWithChange(obj);\n    private _updateMetaWithChange(obj, old);\n    private _insertMeta(obj);\n    private _updateMeta(obj);\n    /**\n     * Get by Id - faster than other methods because of the searching algorithm\n     * @param {int} id - $loki id of document you want to retrieve\n     * @param {boolean} returnPosition - if 'true' we will return [object, position]\n     * @returns {(object|array|null)} Object reference if document was found, null if not,\n     *     or an array if 'returnPosition' was passed.\n     */\n    get(id: number): Doc<T>;\n    get(id: number, returnPosition: boolean): Doc<T> | [Doc<T>, number];\n    /**\n     * Retrieve doc by Unique index\n     * @param {string} field - name of uniquely indexed property to use when doing lookup\n     * @param {any} value - unique value to search for\n     * @returns {object} document matching the value passed\n     */\n    by(field: keyof T, value: any): Doc<T>;\n    /**\n     * Find one object by index property, by property equal to value\n     * @param {object} query - query object used to perform search with\n     * @returns {(object|null)} First matching document, or null if none\n     */\n    findOne(query: ResultSet.Query<Doc<T>>): Doc<T>;\n    /**\n     * Chain method, used for beginning a series of chained find() and/or view() operations\n     * on a collection.\n     *\n     * @param {array} transform - Ordered array of transform step objects similar to chain\n     * @param {object} parameters - Object containing properties representing parameters to substitute\n     * @returns {ResultSet} (this) ResultSet, or data array if any map or join functions where called\n     */\n    chain(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Find method, api is similar to mongodb.\n     * for more complex queries use [chain()]{@link Collection#chain} or [where()]{@link Collection#where}.\n     * @example {@tutorial Query Examples}\n     * @param {object} query - 'mongo-like' query object\n     * @returns {array} Array of matching documents\n     */\n    find(query?: ResultSet.Query<Doc<T>>): Doc<T>[];\n    /**\n     * Find object by unindexed field by property equal to value,\n     * simply iterates and returns the first element matching the query\n     */\n    findOneUnindexed(prop: string, value: any): Doc<T>;\n    /**\n     * Transaction methods\n     */\n    /**\n     * start the transation\n     */\n    startTransaction(): void;\n    /**\n     * Commit the transaction.\n     */\n    commit(): void;\n    /**\n     * Rollback the transaction.\n     */\n    rollback(): void;\n    /**\n     * Query the collection by supplying a javascript filter function.\n     * @example\n     * let results = coll.where(function(obj) {\n       *   return obj.legs === 8;\n       * });\n     * @param {function} fun - filter function to run against all collection docs\n     * @returns {array} all documents which pass your filter function\n     */\n    where(fun: (obj: Doc<T>) => boolean): Doc<T>[];\n    /**\n     * Map Reduce operation\n     * @param {function} mapFunction - function to use as map function\n     * @param {function} reduceFunction - function to use as reduce function\n     * @returns {data} The result of your mapReduce operation\n     */\n    mapReduce<U1, U2>(mapFunction: (value: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Join two collections on specified properties\n     * @param {array} joinData - array of documents to 'join' to this collection\n     * @param {string} leftJoinProp - property name in collection\n     * @param {string} rightJoinProp - property name in joinData\n     * @param {function} mapFun - (Optional) map function to use\n     * @param dataOptions - options to data() before input to your map function\n     * @param [dataOptions.removeMeta] - allows removing meta before calling mapFun\n     * @param [dataOptions.forceClones] - forcing the return of cloned objects to your map object\n     * @param [dataOptions.forceCloneMethod] - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} Result of the mapping operation\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinProp: string | ((obj: any) => string), rightJoinProp: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * (Staging API) create a stage and/or retrieve it\n     */\n    getStage(name: string): any;\n    /**\n     * a collection of objects recording the changes applied through a commmitStage\n     */\n    /**\n     * (Staging API) create a copy of an object and insert it into a stage\n     */\n    stage<F extends TData>(stageName: string, obj: Doc<F>): F;\n    /**\n     * (Staging API) re-attach all objects to the original collection, so indexes and views can be rebuilt\n     * then create a message to be inserted in the commitlog\n     * @param {string} stageName - name of stage\n     * @param {string} message\n     */\n    commitStage(stageName: string, message: string): void;\n    /**\n     * Returns all values of a field.\n     * @param {string} field - the field name\n     * @return {any}: the array of values\n     */\n    extract(field: keyof T): any[];\n    /**\n     * Finds the minimum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the minimum value\n     */\n    min(field: keyof T): number;\n    /**\n     * Finds the maximum value of a field.\n     * @param {string} field - the field name\n     * @return {number} the maximum value\n     */\n    max(field: keyof T): number;\n    /**\n     * Finds the minimum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    minRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Finds the maximum value and its index of a field.\n     * @param {string} field - the field name\n     * @return {object} - index and value\n     */\n    maxRecord(field: keyof T): {\n        index: number;\n        value: number;\n    };\n    /**\n     * Returns all values of a field as numbers (if possible).\n     * @param {string} field - the field name\n     * @return {number[]} - the number array\n     */\n    extractNumerical(field: keyof T): number[];\n    /**\n     * Calculates the average numerical value of a field\n     * @param {string} field - the field name\n     * @returns {number} average of property in all docs in the collection\n     */\n    avg(field: keyof T): number;\n    /**\n     * Calculate the standard deviation of a field.\n     * @param {string} field - the field name\n     * @return {number} the standard deviation\n     */\n    stdDev(field: keyof T): number;\n    /**\n     * Calculates the mode of a field.\n     * @param {string} field - the field name\n     * @return {number} the mode\n     */\n    mode(field: keyof T): number;\n    /**\n     * Calculates the median of a field.\n     * @param {string} field - the field name\n     * @return {number} the median\n     */\n    median(field: keyof T): number;\n}\nexport declare namespace Collection {\n    interface Options<TData extends object, TNested extends object = {}, T extends object = TData & TNested> {\n        unique?: (keyof T)[];\n        unindexedSortComparator?: string;\n        defaultLokiOperatorPackage?: string;\n        rangedIndexes?: RangedIndexOptions;\n        serializableIndexes?: boolean;\n        asyncListeners?: boolean;\n        disableMeta?: boolean;\n        disableChangesApi?: boolean;\n        disableDeltaChangesApi?: boolean;\n        clone?: boolean;\n        serializableIndices?: boolean;\n        cloneMethod?: CloneMethod;\n        transactional?: boolean;\n        ttl?: number;\n        ttlInterval?: number;\n        nestedProperties?: (keyof TNested | {\n            name: keyof TNested;\n            path: string[];\n        })[];\n        fullTextSearch?: FullTextSearch.FieldOptions[];\n    }\n    interface RangedIndexOptions {\n        [prop: string]: RangedIndexMeta;\n    }\n    interface DeserializeOptions {\n        retainDirtyFlags?: boolean;\n        fullTextSearch?: Dict<Analyzer>;\n        [collName: string]: any | {\n            proto?: any;\n            inflate?: (src: object, dest?: object) => void;\n        };\n    }\n    interface BinaryIndex {\n        dirty: boolean;\n        values: any;\n    }\n    interface RangedIndexMeta {\n        index?: IRangedIndex<any>;\n        indexTypeName?: string;\n        comparatorName?: string;\n    }\n    interface Change {\n        name: string;\n        operation: string;\n        obj: any;\n    }\n    interface Serialized {\n        name: string;\n        unindexedSortComparator: string;\n        defaultLokiOperatorPackage: string;\n        _dynamicViews: DynamicView[];\n        _nestedProperties: {\n            name: string;\n            path: string[];\n        }[];\n        uniqueNames: string[];\n        transforms: Dict<Transform[]>;\n        rangedIndexes: RangedIndexOptions;\n        _data: Doc<any>[];\n        idIndex: number[];\n        maxId: number;\n        _dirty: boolean;\n        transactional: boolean;\n        asyncListeners: boolean;\n        disableMeta: boolean;\n        disableChangesApi: boolean;\n        disableDeltaChangesApi: boolean;\n        cloneObjects: boolean;\n        cloneMethod: CloneMethod;\n        changes: any;\n        _fullTextSearch: FullTextSearch;\n    }\n    interface CheckIndexOptions {\n        randomSampling?: boolean;\n        randomSamplingFactor?: number;\n        repair?: boolean;\n    }\n    type Transform<T extends object = object> = {\n        type: \"find\";\n        value: ResultSet.Query<Doc<T>> | string;\n    } | {\n        type: \"where\";\n        value: ((obj: Doc<T>) => boolean) | string;\n    } | {\n        type: \"simplesort\";\n        property: keyof T;\n        options?: boolean | ResultSet.SimpleSortOptions;\n    } | {\n        type: \"compoundsort\";\n        value: (keyof T | [keyof T, boolean])[];\n    } | {\n        type: \"sort\";\n        value: (a: Doc<T>, b: Doc<T>) => number;\n    } | {\n        type: \"sortByScoring\";\n        desc?: boolean;\n    } | {\n        type: \"limit\";\n        value: number;\n    } | {\n        type: \"offset\";\n        value: number;\n    } | {\n        type: \"map\";\n        value: (obj: Doc<T>, index: number, array: Doc<T>[]) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"eqJoin\";\n        joinData: Collection<any> | ResultSet<any>;\n        leftJoinKey: string | ((obj: any) => string);\n        rightJoinKey: string | ((obj: any) => string);\n        mapFun?: (left: any, right: any) => any;\n        dataOptions?: ResultSet.DataOptions;\n    } | {\n        type: \"mapReduce\";\n        mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => any;\n        reduceFunction: (array: any[]) => any;\n    } | {\n        type: \"update\";\n        value: (obj: Doc<T>) => any;\n    } | {\n        type: \"remove\";\n    };\n    interface TTL {\n        age: number;\n        ttlInterval: number;\n        daemon: any;\n    }\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/loki/src/comparators.d.ts",
    "content": "export interface ILokiComparer<T> {\n    (a: T, b: T): -1 | 0 | 1;\n}\nexport interface IComparatorMap {\n    [name: string]: ILokiComparer<any>;\n}\n/** Map/Register of named ILokiComparer functions returning -1, 0, 1 for lt/eq/gt assertions for two passed parameters */\nexport declare let ComparatorMap: IComparatorMap;\n/** Typescript-friendly factory for strongly typed 'js' comparators */\nexport declare function CreateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'abstract js' comparators */\nexport declare function CreateAbstractJavascriptComparator<T>(): ILokiComparer<T>;\n/**\n * Comparator which attempts to deal with deal with dates at comparator level.\n * Should work for dates in any of the object, string, and number formats\n */\nexport declare function CreateAbstractDateJavascriptComparator<T>(): ILokiComparer<T>;\n/** Typescript-friendly factory for strongly typed 'loki' comparators */\nexport declare function CreateLokiComparator(): ILokiComparer<any>;\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/loki/src/dynamic_view.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { ResultSet } from \"./result_set\";\nimport { Collection } from \"./collection\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\n/**\n * DynamicView class is a versatile 'live' view class which can have filters and sorts applied.\n *    Collection.addDynamicView(name) instantiates this DynamicView object and notifies it\n *    whenever documents are add/updated/removed so it can remain up-to-date. (chainable)\n *\n * @example\n * let mydv = mycollection.addDynamicView('test');  // default is non-persistent\n * mydv.applyFind({ 'doors' : 4 });\n * mydv.applyWhere(function(obj) { return obj.name === 'Toyota'; });\n * let results = mydv.data();\n *\n * @extends LokiEventEmitter\n\n * @see {@link Collection#addDynamicView} to construct instances of DynamicView\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class DynamicView<T extends object = object> extends LokiEventEmitter {\n    readonly name: string;\n    private _collection;\n    private _persistent;\n    private _sortPriority;\n    private _minRebuildInterval;\n    private _rebuildPending;\n    private _resultSet;\n    private _resultData;\n    private _resultDirty;\n    private _cachedResultSet;\n    private _filterPipeline;\n    private _sortFunction;\n    private _sortCriteria;\n    private _sortCriteriaSimple;\n    private _sortByScoring;\n    private _sortDirty;\n    /**\n     * Constructor.\n     * @param {Collection} collection - a reference to the collection to work agains\n     * @param {string} name - the name of this dynamic view\n     * @param {object} options - the options\n     * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n     * @param {string} [options.sortPriority=\"passive\"] - the sort priority\n     * @param {number} [options.minRebuildInterval=1] - minimum rebuild interval (need clarification to docs here)\n     */\n    constructor(collection: Collection<T>, name: string, options?: DynamicView.Options);\n    /**\n     * Internally used immediately after deserialization (loading)\n     *    This will clear out and reapply filterPipeline ops, recreating the view.\n     *    Since where filters do not persist correctly, this method allows\n     *    restoring the view to state where user can re-apply those where filters.\n     *\n     * @param removeWhereFilters\n     * @returns {DynamicView} This dynamic view for further chained ops.\n     * @fires DynamicView.rebuild\n     */\n    private _rematerialize({removeWhereFilters});\n    /**\n     * Makes a copy of the internal ResultSet for branched queries.\n     * Unlike this dynamic view, the branched ResultSet will not be 'live' updated,\n     * so your branched query should be immediately resolved and not held for future evaluation.\n     * @param {(string|array=)} transform - Optional name of collection transform, or an array of transform steps\n     * @param {object} parameters - optional parameters (if optional transform requires them)\n     * @returns {ResultSet} A copy of the internal ResultSet for branched queries.\n     */\n    branchResultSet(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T>;\n    /**\n     * Override of toJSON to avoid circular references.\n     */\n    toJSON(): DynamicView.Serialized;\n    static fromJSONObject(collection: Collection, obj: DynamicView.Serialized): DynamicView;\n    /**\n     * Used to clear pipeline and reset dynamic view to initial state.\n     * Existing options should be retained.\n     * @param {boolean} queueSortPhase - (default: false) if true we will async rebuild view (maybe set default to true in future?)\n     */\n    removeFilters({queueSortPhase}?: {\n        queueSortPhase?: boolean;\n    }): void;\n    /**\n     * Used to apply a sort to the dynamic view\n     * @example\n     * dv.applySort(function(obj1, obj2) {\n       *   if (obj1.name === obj2.name) return 0;\n       *   if (obj1.name > obj2.name) return 1;\n       *   if (obj1.name < obj2.name) return -1;\n       * });\n     * @param {function} comparefun - a javascript compare function used for sorting\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applySort(comparefun: (lhs: Doc<T>, rhs: Doc<T>) => number): this;\n    /**\n     * Used to specify a property used for view translation.\n     * @param {string} field - the field name\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether we should sort descending.\n     * @param {boolean} [options.disableIndexIntersect=false] - whether we should explicity not use array intersection.\n     * @param {boolean} [options.forceIndexIntersect=false] - force array intersection (if binary index exists).\n     * @param {boolean} [options.useJavascriptSorting=false] - whether results are sorted via basic javascript sort.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     * @example\n     * dv.applySimpleSort(\"name\");\n     */\n    applySimpleSort(field: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @param {Array} criteria - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {DynamicView} Reference to this DynamicView, sorted, for future chain operations.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * dv.applySortCriteria(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * dv.applySortCriteria(['age', ['name', true]]);\n     * // to sort by age (descending) and then by name (descending)\n     * dv.applySortCriteria([['age', true], ['name', true]]);\n     */\n    applySortCriteria(criteria: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Used to apply a sort by the latest full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     */\n    applySortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Marks the beginning of a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    startTransaction(): this;\n    /**\n     * Commits a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    commit(): this;\n    /**\n     * Rolls back a transaction.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    rollback(): this;\n    /**\n     * Find the index of a filter in the pipeline, by that filter's ID.\n     * @param {(string|number)} uid - The unique ID of the filter.\n     * @returns {number}: index of the referenced filter in the pipeline; -1 if not found.\n     */\n    private _indexOfFilterWithId(uid);\n    /**\n     * Add the filter object to the end of view's filter pipeline and apply the filter to the ResultSet.\n     * @param {object} filter - The filter object. Refer to applyFilter() for extra details.\n     */\n    private _addFilter(filter);\n    /**\n     * Reapply all the filters in the current pipeline.\n     *\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    reapplyFilters(): this;\n    /**\n     * Adds or updates a filter in the DynamicView filter pipeline\n     * @param {object} filter - A filter object to add to the pipeline.\n     *    The object is in the format { 'type': filter_type, 'val', filter_param, 'uid', optional_filter_id }\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFilter(filter: DynamicView.Filter<T>): this;\n    /**\n     * applyFind() - Adds or updates a mongo-style query option in the DynamicView filter pipeline\n     *\n     * @param {object} query - A mongo-style query object to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyFind(query: object, uid?: string | number): this;\n    /**\n     * Adds or updates a javascript filter function in the DynamicView filter pipeline\n     * @param {function} fun - A javascript filter function to apply to pipeline\n     * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    applyWhere(fun: (obj: Doc<T>) => boolean, uid?: string | number): this;\n    /**\n     * Remove the specified filter from the DynamicView filter pipeline\n     * @param {(string|number)} uid - The unique ID of the filter to be removed.\n     * @returns {DynamicView} this DynamicView object, for further chain ops.\n     */\n    removeFilter(uid: string | number): this;\n    /**\n     * Returns the number of documents representing the current DynamicView contents.\n     * @returns {number} The number of documents representing the current DynamicView contents.\n     */\n    count(): number;\n    /**\n     * Resolves and pending filtering and sorting, then returns document array as result.\n     * @param {object} options - optional parameters to pass to ResultSet.data() if non-persistent\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values include 'parse-stringify', 'jquery-extend-deep', 'shallow', 'shallow-assign'\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} An array of documents representing the current DynamicView contents.\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * When the view is not sorted we may still wish to be notified of rebuild events.\n     * This event will throttle and queue a single rebuild event when batches of updates affect the view.\n     */\n    private _queueRebuildEvent();\n    /**\n     * If the view is sorted we will throttle sorting to either :\n     * (1) passive - when the user calls data(), or\n     * (2) active - once they stop updating and yield js thread control\n     */\n    private _queueSortPhase();\n    /**\n     * Invoked synchronously or asynchronously to perform final sort phase (if needed)\n     */\n    private _performSortPhase(options?);\n    /**\n     * (Re)evaluating document inclusion.\n     * Called by : collection.insert() and collection.update().\n     * @param {int} objIndex - index of document to (re)run through filter pipeline.\n     * @param {boolean} isNew - true if the document was just added to the collection.\n     * @hidden\n     */\n    _evaluateDocument(objIndex: number, isNew: boolean): void;\n    /**\n     * Internal function called on collection.delete().\n     * @hidden\n     */\n    _removeDocument(objIndex: number): void;\n    /**\n     * Data transformation via user supplied functions\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: T, index: number, array: T[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n}\nexport declare namespace DynamicView {\n    interface Options {\n        persistent?: boolean;\n        sortPriority?: SortPriority;\n        minRebuildInterval?: number;\n    }\n    type SortPriority = \"passive\" | \"active\";\n    interface Serialized {\n        name: string;\n        _persistent: boolean;\n        _sortPriority: SortPriority;\n        _minRebuildInterval: number;\n        _resultSet: ResultSet<any>;\n        _filterPipeline: Filter<any>[];\n        _sortCriteria: (string | [string, boolean])[];\n        _sortCriteriaSimple: {\n            field: string;\n            options: boolean | ResultSet.SimpleSortOptions;\n        };\n        _sortByScoring: boolean;\n        _sortDirty: boolean;\n    }\n    type Filter<T extends object = object> = {\n        type: \"find\";\n        val: ResultSet.Query<Doc<T>>;\n        uid: number | string;\n    } | {\n        type: \"where\";\n        val: (obj: Doc<T>) => boolean;\n        uid: number | string;\n    };\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/loki/src/event_emitter.d.ts",
    "content": "/**\n * LokiEventEmitter is a minimalist version of EventEmitter. It enables any\n * constructor that inherits EventEmitter to emit events and trigger\n * listeners that have been added to the event through the on(event, callback) method\n *\n * @constructor LokiEventEmitter\n */\nexport declare class LokiEventEmitter {\n    /**\n     * A map, with each property being an array of callbacks.\n     */\n    protected _events: object;\n    /**\n     * Determines whether or not the callbacks associated with each event should happen in an async fashion or not.\n     * Default is false, which means events are synchronous\n     */\n    protected _asyncListeners: boolean;\n    /**\n     * Adds a listener to the queue of callbacks associated to an event\n     * @param {string|string[]} eventName - the name(s) of the event(s) to listen to\n     * @param {function} listener - callback function of listener to attach\n     * @returns {int} the index of the callback in the array of listeners for a particular event\n     */\n    on(eventName: string | string[], listener: Function): Function;\n    /**\n     * Emits a particular event\n     * with the option of passing optional parameters which are going to be processed by the callback\n     * provided signatures match (i.e. if passing emit(event, arg0, arg1) the listener should take two parameters)\n     * @param {string} eventName - the name of the event\n     * @param {object} data - optional object passed with the event\n     */\n    protected emit(eventName: string, ...data: any[]): void;\n    /**\n     * Alias of EventEmitter.on().\n     */\n    addListener(eventName: string | string[], listener: Function): Function;\n    /**\n     * Removes the listener at position 'index' from the event 'eventName'\n     * @param {string|string[]} eventName - the name(s) of the event(s) which the listener is attached to\n     * @param {function} listener - the listener callback function to remove from emitter\n     */\n    removeListener(eventName: string | string[], listener: Function): void;\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/loki/src/index.d.ts",
    "content": "import { Loki } from \"./loki\";\nimport { Collection } from \"./collection\";\nexport { Loki, Collection };\nexport default Loki;\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/loki/src/loki.d.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { Collection } from \"./collection\";\nimport { Doc, StorageAdapter } from \"../../common/types\";\nimport { IComparatorMap } from \"./comparators\";\nimport { IRangedIndexFactoryMap } from \"./ranged_indexes\";\nimport { ILokiOperatorPackageMap } from \"./operator_packages\";\nexport declare class Loki extends LokiEventEmitter {\n    filename: string;\n    private databaseVersion;\n    private engineVersion;\n    _collections: Collection[];\n    private _env;\n    private _serializationMethod;\n    private _destructureDelimiter;\n    private _persistenceMethod;\n    private _persistenceAdapter;\n    private _throttledSaves;\n    private _throttledSaveRunning;\n    private _throttledSavePending;\n    private _autosave;\n    private _autosaveInterval;\n    private _autosaveRunning;\n    private _autosaveHandler;\n    /**\n     * Constructs the main database class.\n     * @param {string} filename - name of the file to be saved to\n     * @param {object} [options={}] - options\n     * @param {Loki.Environment} [options.env] - the javascript environment\n     * @param {Loki.SerializationMethod} [options.serializationMethod=NORMAL] - the serialization method\n     * @param {string} [options.destructureDelimiter=\"$<\\n\"] - string delimiter used for destructured serialization\n     * @param {IComparatorMap} [options.comparatorMap] allows injecting or overriding registered comparators\n     * @param {IRangedIndexFactoryMap} [options.rangedIndexFactoryMap] allows injecting or overriding registered ranged index factories\n     * @param {ILokiOperatorPackageMap} [options.lokiOperatorPackageMap] allows injecting or overriding registered loki operator packages\n     */\n    constructor(filename?: string, options?: Loki.Options);\n    /**\n     * configures options related to database persistence.\n     *\n     * @param {Loki.PersistenceOptions} [options={}] - options\n     * @param {adapter} [options.adapter=auto] - an instance of a loki persistence adapter\n     * @param {boolean} [options.autosave=false] - enables autosave\n     * @param {int} [options.autosaveInterval=5000] - time interval (in milliseconds) between saves (if dirty)\n     * @param {boolean} [options.autoload=false] - enables autoload on loki instantiation\n     * @param {object} options.inflate - options that are passed to loadDatabase if autoload enabled\n     * @param {boolean} [options.throttledSaves=true] - if true, it batches multiple calls to to saveDatabase reducing number of\n     *   disk I/O operations and guaranteeing proper serialization of the calls. Default value is true.\n     * @param {Loki.PersistenceMethod} options.persistenceMethod - a persistence method which should be used (FS_STORAGE, LOCAL_STORAGE...)\n     * @returns {Promise} a Promise that resolves after initialization and (if enabled) autoloading the database\n     */\n    initializePersistence(options?: Loki.PersistenceOptions): Promise<void>;\n    /**\n     * Copies 'this' database into a new Loki instance. Object references are shared to make lightweight.\n     * @param {object} options - options\n     * @param {boolean} options.removeNonSerializable - nulls properties not safe for serialization.\n     */\n    copy(options?: Loki.CopyOptions): Loki;\n    /**\n     * Adds a collection to the database.\n     * @param {string} name - name of collection to add\n     * @param {object} [options={}] - options to configure collection with.\n     * @param {array} [options.unique=[]] - array of property names to define unique constraints for\n     * @param {array} [options.exact=[]] - array of property names to define exact constraints for\n     * @param {array} [options.indices=[]] - array property names to define binary indexes for\n     * @param {boolean} [options.asyncListeners=false] - whether listeners are called asynchronously\n     * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n     * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes Api\n     * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n     * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n     * @param {string} [options.cloneMethod=CloneMethod.DEEP] - the clone method\n     * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale\n     * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n     * @returns {Collection} a reference to the collection which was just added\n     */\n    addCollection<TData extends object = object, TNested extends object = object>(name: string, options?: Collection.Options<TData, TNested>): Collection<TData, TNested>;\n    loadCollection(collection: Collection): void;\n    /**\n     * Retrieves reference to a collection by name.\n     * @param {string} name - name of collection to look up\n     * @returns {Collection} Reference to collection in database by that name, or null if not found\n     */\n    getCollection<TData extends object = object, TNested extends object = object>(name: string): Collection<TData, TNested>;\n    /**\n     * Renames an existing loki collection\n     * @param {string} oldName - name of collection to rename\n     * @param {string} newName - new name of collection\n     * @returns {Collection} reference to the newly renamed collection\n     */\n    renameCollection<TData extends object = object, TNested extends object = object>(oldName: string, newName: string): Collection<TData, TNested>;\n    listCollections(): {\n        name: string;\n        count: number;\n    }[];\n    /**\n     * Removes a collection from the database.\n     * @param {string} collectionName - name of collection to remove\n     */\n    removeCollection(collectionName: string): void;\n    /**\n     * Serialize database to a string which can be loaded via {@link Loki#loadJSON}\n     *\n     * @returns {string} Stringified representation of the loki database.\n     */\n    serialize(options?: Loki.SerializeOptions): string | string[];\n    toJSON(): Loki.Serialized;\n    /**\n     * Database level destructured JSON serialization routine to allow alternate serialization methods.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {object} options - output format options for use externally to loki\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to only output an individual collection or db (-1)\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {string|Array} A custom, restructured aggregation of independent serializations.\n     */\n    serializeDestructured(options?: Loki.SerializeDestructuredOptions): string | string[];\n    /**\n     * Collection level utility method to serialize a collection in a 'destructured' format\n     *\n     * @param {object} options - used to determine output of method\n     * @param {int} options.delimited - whether to return single delimited string or an array\n     * @param {string} options.delimiter - (optional) if delimited, this is delimiter to use\n     * @param {int} options.collectionIndex -  specify which collection to serialize data for\n     *\n     * @returns {string|array} A custom, restructured aggregation of independent serializations for a single collection.\n     */\n    serializeCollection(options?: {\n        delimited?: boolean;\n        collectionIndex?: number;\n        delimiter?: string;\n    }): string | string[];\n    /**\n     * Database level destructured JSON deserialization routine to minimize memory overhead.\n     * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n     * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n     * your own structured persistence or data exchange.\n     *\n     * @param {string|array} destructuredSource - destructured json or array to deserialize from\n     * @param {object} options - source format options\n     * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n     * @param {int} options.partition - can be used to deserialize only a single partition\n     * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n     * @param {string} options.delimiter - override default delimiter\n     *\n     * @returns {object|array} An object representation of the deserialized database, not yet applied to 'this' db or document array\n     */\n    deserializeDestructured(destructuredSource: string | string[], options?: Loki.SerializeDestructuredOptions): any;\n    /**\n     * Collection level utility function to deserializes a destructured collection.\n     *\n     * @param {string|string[]} destructuredSource - destructured representation of collection to inflate\n     * @param {object} options - used to describe format of destructuredSource input\n     * @param {int} [options.delimited=false] - whether source is delimited string or an array\n     * @param {string} options.delimiter - if delimited, this is delimiter to use (if other than default)\n     *\n     * @returns {Array} an array of documents to attach to collection.data.\n     */\n    deserializeCollection<T extends object = object>(destructuredSource: string | string[], options?: Loki.DeserializeCollectionOptions): Doc<T>[];\n    /**\n     * Inflates a loki database from a serialized JSON string\n     *\n     * @param {string} serializedDb - a serialized loki database string\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSON(serializedDb: string | string[], options?: Collection.DeserializeOptions): void;\n    /**\n     * Inflates a loki database from a JS object\n     *\n     * @param {object} dbObject - a serialized loki database object\n     * @param {object} options - apply or override collection level settings\n     * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n     */\n    loadJSONObject(dbObject: Loki, options?: Collection.DeserializeOptions): void;\n    loadJSONObject(dbObject: Loki.Serialized, options?: Collection.DeserializeOptions): void;\n    /**\n     * Emits the close event. In autosave scenarios, if the database is dirty, this will save and disable timer.\n     * Does not actually destroy the db.\n     *\n     * @returns {Promise} a Promise that resolves after closing the database succeeded\n     */\n    close(): Promise<void>;\n    /**-------------------------+\n     | Changes API               |\n     +--------------------------*/\n    /**\n     * The Changes API enables the tracking the changes occurred in the collections since the beginning of the session,\n     * so it's possible to create a differential dataset for synchronization purposes (possibly to a remote db)\n     */\n    /**\n     * (Changes API) : takes all the changes stored in each\n     * collection and creates a single array for the entire database. If an array of names\n     * of collections is passed then only the included collections will be tracked.\n     *\n     * @param {Array} [arrayOfCollectionNames=] - array of collection names. No arg means all collections are processed.\n     * @returns {Array} array of changes\n     * @see private method _createChange() in Collection\n     */\n    generateChangesNotification(arrayOfCollectionNames?: string[]): Collection.Change[];\n    /**\n     * (Changes API) - stringify changes for network transmission\n     * @returns {string} string representation of the changes\n     */\n    serializeChanges(collectionNamesArray?: string[]): string;\n    /**\n     * (Changes API) : clears all the changes in all collections.\n     */\n    clearChanges(): void;\n    /**\n     * Wait for throttledSaves to complete and invoke your callback when drained or duration is met.\n     *\n     * @param {object} options - configuration options\n     * @param {boolean} [options.recursiveWait=true] - if after queue is drained, another save was kicked off, wait for it\n     * @param {boolean} [options.recursiveWaitLimit=false] - limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDuration=2000] - cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves when save queue is drained, it is passed a sucess parameter value\n     */\n    throttledSaveDrain(options?: Loki.ThrottledDrainOptions): Promise<void>;\n    /**\n     * Internal load logic, decoupled from throttling/contention logic\n     *\n     * @param {object} options - an object containing inflation options for each collection\n     * @param {boolean} ignore_not_found - does not raise an error if database is not found\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    private _loadDatabase(options?, ignore_not_found?);\n    /**\n     * Handles manually loading from an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *    To avoid contention with any throttledSaves, we will drain the save queue first.\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @param {object} [options={}] - if throttling saves and loads, this controls how we drain save queue before loading\n     * @param {boolean} [options.recursiveWait=true] wait recursively until no saves are queued\n     * @param {boolean} [options.recursiveWaitLimit=false] limit our recursive waiting to a duration\n     * @param {number} [options.recursiveWaitLimitDelay=2000] cutoff in ms to stop recursively re-draining\n     * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n     * @returns {Promise} a Promise that resolves after the database is loaded\n     */\n    loadDatabase(options?: Loki.LoadDatabaseOptions): Promise<void>;\n    private _saveDatabase();\n    /**\n     * Handles manually saving to an adapter storage (such as fs-storage)\n     *    This method utilizes loki configuration options (if provided) to determine which\n     *    persistence method to use, or environment detection (if configuration was not provided).\n     *\n     * If you are configured with autosave, you do not need to call this method yourself.\n     *\n     * @returns {Promise} a Promise that resolves after the database is persisted\n     */\n    saveDatabase(): Promise<void>;\n    /**\n     * Handles deleting a database from the underlying storage adapter\n     *\n     * @returns {Promise} a Promise that resolves after the database is deleted\n     */\n    deleteDatabase(): Promise<void>;\n    /****************\n     * Autosave API\n     ****************/\n    /**\n     * Check whether any collections are \"dirty\" meaning we need to save the (entire) database\n     * @returns {boolean} - true if database has changed since last autosave, otherwise false\n     */\n    private _autosaveDirty();\n    /**\n     * Resets dirty flags on all collections.\n     */\n    private _autosaveClearFlags();\n    /**\n     * Starts periodically saves to the underlying storage adapter.\n     */\n    private _autosaveEnable();\n    /**\n     * Stops the autosave interval timer.\n     */\n    private _autosaveDisable();\n}\nexport declare namespace Loki {\n    interface Options {\n        env?: Environment;\n        serializationMethod?: SerializationMethod;\n        destructureDelimiter?: string;\n        comparatorMap?: IComparatorMap;\n        rangedIndexFactoryMap?: IRangedIndexFactoryMap;\n        lokiOperatorPackageMap?: ILokiOperatorPackageMap;\n    }\n    interface PersistenceOptions {\n        adapter?: StorageAdapter;\n        autosave?: boolean;\n        autosaveInterval?: number;\n        autoload?: boolean;\n        throttledSaves?: boolean;\n        persistenceMethod?: Loki.PersistenceMethod;\n        inflate?: any;\n    }\n    interface CopyOptions {\n        removeNonSerializable?: boolean;\n    }\n    interface SerializeOptions {\n        serializationMethod?: SerializationMethod;\n    }\n    interface SerializeDestructuredOptions {\n        partitioned?: boolean;\n        partition?: number;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface DeserializeCollectionOptions {\n        partitioned?: boolean;\n        delimited?: boolean;\n        delimiter?: string;\n    }\n    interface ThrottledDrainOptions {\n        recursiveWait?: boolean;\n        recursiveWaitLimit?: boolean;\n        recursiveWaitLimitDuration?: number;\n        started?: Date;\n    }\n    interface Serialized {\n        _env: Environment;\n        _serializationMethod: SerializationMethod;\n        _autosave: boolean;\n        _autosaveInterval: number;\n        _collections: Collection[];\n        databaseVersion: number;\n        engineVersion: number;\n        filename: string;\n        _persistenceAdapter: StorageAdapter;\n        _persistenceMethod: PersistenceMethod;\n        _throttledSaves: boolean;\n    }\n    type LoadDatabaseOptions = Collection.DeserializeOptions & ThrottledDrainOptions;\n    type SerializationMethod = \"normal\" | \"pretty\" | \"destructured\";\n    type PersistenceMethod = \"fs-storage\" | \"local-storage\" | \"indexed-storage\" | \"memory-storage\" | \"adapter\";\n    type Environment = \"NATIVESCRIPT\" | \"NODEJS\" | \"CORDOVA\" | \"BROWSER\" | \"MEMORY\";\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/loki/src/operator_packages.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\n/** Hash interface for named LokiOperatorPackage registration */\nexport interface ILokiOperatorPackageMap {\n    [name: string]: LokiOperatorPackage;\n}\n/**\n * Helper function for determining 'loki' abstract equality which is a little more abstract than ==\n *     aeqHelper(5, '5') === true\n *     aeqHelper(5.0, '5') === true\n *     aeqHelper(new Date(\"1/1/2011\"), new Date(\"1/1/2011\")) === true\n *     aeqHelper({a:1}, {z:4}) === true (all objects sorted equally)\n *     aeqHelper([1, 2, 3], [1, 3]) === false\n *     aeqHelper([1, 2, 3], [1, 2, 3]) === true\n *     aeqHelper(undefined, null) === true\n * @param {any} prop1\n * @param {any} prop2\n * @returns {boolean}\n * @hidden\n */\nexport declare function aeqHelper(prop1: any, prop2: any): boolean;\n/**\n * Helper function for determining 'less-than' conditions for ops, sorting, and binary indices.\n *     In the future we might want $lt and $gt ops to use their own functionality/helper.\n *     Since binary indices on a property might need to index [12, NaN, new Date(), Infinity], we\n *     need this function (as well as gtHelper) to always ensure one value is LT, GT, or EQ to another.\n * @hidden\n */\nexport declare function ltHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @hidden\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} equal\n * @returns {boolean}\n */\nexport declare function gtHelper(prop1: any, prop2: any, equal: boolean): boolean;\n/**\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} descending\n * @returns {number}\n * @hidden\n */\nexport declare function sortHelper(prop1: any, prop2: any, descending: boolean): number;\n/**\n * Default implementation of LokiOperatorPackage, using fastest javascript comparison operators.\n */\nexport declare class LokiOperatorPackage {\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n    $in(a: any, b: any): boolean;\n    $nin(a: any, b: any): boolean;\n    $keyin(a: string, b: object): boolean;\n    $nkeyin(a: string, b: object): boolean;\n    $definedin(a: string, b: object): boolean;\n    $undefinedin(a: string, b: object): boolean;\n    $regex(a: string, b: RegExp): boolean;\n    $containsNone(a: any, b: any): boolean;\n    $containsAny(a: any, b: any): boolean;\n    $contains(a: any, b: any): boolean;\n    $type(a: any, b: any): boolean;\n    $finite(a: number, b: boolean): boolean;\n    $size(a: any, b: any): boolean;\n    $len(a: any, b: any): boolean;\n    $where(a: any, b: any): boolean;\n    $not(a: any, b: any): boolean;\n    $and(a: any, b: any): boolean;\n    $or(a: any, b: any): boolean;\n    private doQueryOp(val, op);\n    private containsCheckFn(a);\n}\n/**\n * LokiOperatorPackage which utilizes abstract 'loki' comparisons for basic relational equality op implementations.\n */\nexport declare class LokiAbstractOperatorPackage extends LokiOperatorPackage {\n    constructor();\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * LokiOperatorPackage which utilizes provided comparator for basic relational equality op implementations.\n */\nexport declare class ComparatorOperatorPackage<T> extends LokiOperatorPackage {\n    comparator: ILokiComparer<T>;\n    constructor(comparator: ILokiComparer<T>);\n    $eq(a: any, b: any): boolean;\n    $ne(a: any, b: any): boolean;\n    $gt(a: any, b: any): boolean;\n    $gte(a: any, b: any): boolean;\n    $lt(a: any, b: any): boolean;\n    $lte(a: any, b: any): boolean;\n    $between(a: any, range: [any, any]): boolean;\n}\n/**\n * Map/Register of named LokiOperatorPackages which implement all unindexed query ops within 'find' query objects\n */\nexport declare let LokiOperatorPackageMap: ILokiOperatorPackageMap;\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/loki/src/ranged_indexes.d.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\nexport declare type RangedValueOperator = \"$gt\" | \"$gte\" | \"$lt\" | \"$lte\" | \"$eq\" | \"$neq\" | \"$between\";\nexport interface IRangedIndexRequest<T> {\n    op: RangedValueOperator;\n    val: T;\n    high?: T;\n}\n/** Defines interface which all loki ranged indexes need to implement */\nexport interface IRangedIndex<T> {\n    insert(id: number, val: T): void;\n    update(id: number, val: T): void;\n    remove(id: number): void;\n    restore(tree: any): void;\n    backup(): IRangedIndex<T>;\n    rangeRequest(range?: IRangedIndexRequest<T>): number[];\n    validateIndex(): boolean;\n}\n/** Hash Interface for global ranged index factory map*/\nexport interface IRangedIndexFactoryMap {\n    [name: string]: (name: string, comparator: ILokiComparer<any>) => IRangedIndex<any>;\n}\n/** Map/Register of named factory functions returning IRangedIndex instances */\nexport declare let RangedIndexFactoryMap: IRangedIndexFactoryMap;\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/loki/src/result_set.d.ts",
    "content": "import { Collection } from \"./collection\";\nimport { CloneMethod } from \"./clone\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\nimport { Query as FullTextSearchQuery } from \"../../full-text-search/src/query_types\";\n/**\n * ResultSet class allowing chainable queries.  Intended to be instanced internally.\n *    Collection.find(), Collection.where(), and Collection.chain() instantiate this.\n *\n * @example\n *    mycollection.chain()\n *      .find({ 'doors' : 4 })\n *      .where(function(obj) { return obj.name === 'Toyota' })\n *      .data();\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport declare class ResultSet<T extends object = object> {\n    _collection: Collection<T>;\n    _filteredRows: number[];\n    _filterInitialized: boolean;\n    private _scoring;\n    /**\n     * Constructor.\n     * @param {Collection} collection - the collection which this ResultSet will query against\n     */\n    constructor(collection: Collection<T>);\n    /**\n     * Reset the ResultSet to its initial state.\n     * @returns {ResultSet} Reference to this ResultSet, for future chain operations.\n     */\n    reset(): this;\n    /**\n     * Override of toJSON to avoid circular references\n     */\n    toJSON(): ResultSet<T>;\n    /**\n     * Allows you to limit the number of documents passed to next chain operation.\n     * A ResultSet copy() is made to avoid altering original ResultSet.\n     * @param {int} qty - The number of documents to return.\n     * @returns {ResultSet} Returns a copy of the ResultSet, limited by qty, for subsequent chain ops.\n     */\n    limit(qty: number): this;\n    /**\n     * Used for skipping 'pos' number of documents in the ResultSet.\n     * @param {int} pos - Number of documents to skip; all preceding documents are filtered out.\n     * @returns {ResultSet} Returns a copy of the ResultSet, containing docs starting at 'pos' for subsequent chain ops.\n     */\n    offset(pos: number): this;\n    /**\n     * To support reuse of ResultSet in branched query situations.\n     * @returns {ResultSet} Returns a copy of the ResultSet (set) but the underlying document references will be the same.\n     */\n    copy(): ResultSet<T>;\n    /**\n     * Executes a named collection transform or raw array of transform steps against the ResultSet.\n     * @param {(string|array)} transform - name of collection transform or raw transform array\n     * @param {object} [parameters=] - object property hash of parameters, if the transform requires them.\n     * @returns {ResultSet} either (this) ResultSet or a clone of of this ResultSet (depending on steps)\n     */\n    transform(transform: string | Collection.Transform<T>[], parameters?: object): this;\n    /**\n     * User supplied compare function is provided two documents to compare. (chainable)\n     * @example\n     *    rslt.sort(function(obj1, obj2) {\n       *      if (obj1.name === obj2.name) return 0;\n       *      if (obj1.name > obj2.name) return 1;\n       *      if (obj1.name < obj2.name) return -1;\n       *    });\n     * @param {function} comparefun - A javascript compare function used for sorting.\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    sort(comparefun: (a: Doc<T>, b: Doc<T>) => number): this;\n    /**\n     * Simpler, loose evaluation for user to sort based on a property name. (chainable).\n     * Sorting based on the same lt/gt helper functions used for binary indices.\n     * @param {string} propname - name of property to sort by.\n     * @param {boolean|object=} options - boolean for sort descending or options object\n     * @param {boolean} [options.desc=false] - whether to sort descending\n     * @param {string} [options.sortComparator] override default with name of comparator registered in ComparatorMap\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    simplesort(propname: keyof T, options?: boolean | ResultSet.SimpleSortOptions): this;\n    /**\n     * Allows sorting a ResultSet based on multiple columns.\n     * @example\n     * // to sort by age and then name (both ascending)\n     * rs.compoundsort(['age', 'name']);\n     * // to sort by age (ascending) and then by name (descending)\n     * rs.compoundsort(['age', ['name', true]);\n     * @param {array} properties - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n     * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n     */\n    compoundsort(properties: (keyof T | [keyof T, boolean])[]): this;\n    /**\n     * Helper function for compoundsort(), performing individual object comparisons\n     * @param {Array} properties - array of property names, in order, by which to evaluate sort order\n     * @param {object} obj1 - first object to compare\n     * @param {object} obj2 - second object to compare\n     * @returns {number} 0, -1, or 1 to designate if identical (sortwise) or which should be first\n     */\n    private _compoundeval(properties, obj1, obj2);\n    /**\n     * Sorts the ResultSet based on the last full-text-search scoring.\n     * @param {boolean} [ascending=false] - sort ascending\n     * @returns {ResultSet}\n     */\n    sortByScoring(ascending?: boolean): this;\n    /**\n     * Returns the scoring of the last full-text-search.\n     * @returns {ScoreResult[]}\n     */\n    getScoring(): Scorer.ScoreResult[];\n    /**\n     * Oversee the operation of OR'ed query expressions.\n     * OR'ed expression evaluation runs each expression individually against the full collection,\n     * and finally does a set OR on each expression's results.\n     * Each evaluation can utilize a binary index to prevent multiple linear array scans.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findOr(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $or(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Oversee the operation of AND'ed query expressions.\n     * AND'ed expression evaluation runs each expression progressively against the full collection,\n     * internally utilizing existing chained ResultSet functionality.\n     * Only the first filter can utilize a binary index.\n     * @param {array} expressionArray - array of expressions\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    findAnd(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    $and(expressionArray: ResultSet.Query<Doc<T>>[]): this;\n    /**\n     * Used for querying via a mongo-style query object.\n     *\n     * @param {object} query - A mongo-style query object used for filtering current results.\n     * @param {boolean} firstOnly - (Optional) Used by collection.findOne() - flag if this was invoked via findOne()\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    find(query?: ResultSet.Query<Doc<T>>, firstOnly?: boolean): this;\n    /**\n     * Used for filtering via a javascript filter function.\n     * @param {function} fun - A javascript function used for filtering current results by.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    where(fun: (obj: Doc<T>) => boolean): this;\n    /**\n     * Returns the number of documents in the ResultSet.\n     * @returns {number} The number of documents in the ResultSet.\n     */\n    count(): number;\n    /**\n     * Terminates the chain and returns array of filtered documents\n     * @param {object} options\n     * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n     *        the collection is not configured for clone object.\n     * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n     *        Possible values 'parse-stringify', 'deep', and 'shallow' and\n     * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n     *\n     * @returns {Array} Array of documents in the ResultSet\n     */\n    data(options?: ResultSet.DataOptions): Doc<T>[];\n    /**\n     * Used to run an update operation on all documents currently in the ResultSet.\n     * @param {function} updateFunction - User supplied updateFunction(obj) will be executed for each document object.\n     * @returns {ResultSet} this ResultSet for further chain ops.\n     */\n    update(updateFunction: (obj: Doc<T>) => Doc<T>): this;\n    /**\n     * Removes all document objects which are currently in ResultSet from collection (as well as ResultSet)\n     * @returns {ResultSet} this (empty) ResultSet for further chain ops.\n     */\n    remove(): this;\n    /**\n     * data transformation via user supplied functions\n     *\n     * @param {function} mapFunction - this function accepts a single document for you to transform and return\n     * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n     * @returns {value} The output of your reduceFunction\n     */\n    mapReduce<U1, U2>(mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2;\n    /**\n     * Left joining two sets of data. Join keys can be defined or calculated properties\n     * eqJoin expects the right join key values to be unique.  Otherwise left data will be joined on the last joinData object with that key\n     * @param {Array|ResultSet|Collection} joinData - Data array to join to.\n     * @param {(string|function)} leftJoinKey - Property name in this result set to join on or a function to produce a value to join on\n     * @param {(string|function)} rightJoinKey - Property name in the joinData to join on or a function to produce a value to join on\n     * @param {function} [mapFun=] - a function that receives each matching pair and maps them into output objects - function(left,right){return joinedObject}\n     * @param {object} [dataOptions=] - optional options to apply to data() calls for left and right sides\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - allows overriding the default or collection specified cloning method\n     * @returns {ResultSet} A ResultSet with data in the format [{left: leftObj, right: rightObj}]\n     */\n    eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinKey: string | ((obj: any) => string), rightJoinKey: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: ResultSet.DataOptions): ResultSet<any>;\n    /**\n     * Applies a map function into a new collection for further chaining.\n     * @param {function} mapFun - javascript map function\n     * @param {object} [dataOptions=] - options to data() before input to your map function\n     * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n     * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n     * @param {string} dataOptions.forceCloneMethod - Allows overriding the default or collection specified cloning method\n     * @return {ResultSet}\n     */\n    map<U extends object>(mapFun: (obj: Doc<T>, index: number, array: Doc<T>[]) => U, dataOptions?: ResultSet.DataOptions): ResultSet<U>;\n}\nexport declare namespace ResultSet {\n    interface DataOptions {\n        forceClones?: boolean;\n        forceCloneMethod?: CloneMethod;\n        removeMeta?: boolean;\n    }\n    interface SimpleSortOptions {\n        desc?: boolean;\n        sortComparator?: string;\n    }\n    type ContainsHelperType<R> = R extends string ? string | string[] : R extends any[] ? R[number] | R[number][] : R extends object ? keyof R | (keyof R)[] : never;\n    type LokiOps<R> = {\n        $eq?: R;\n    } | {\n        $ne?: R;\n    } | {\n        $gt?: R;\n    } | {\n        $gte?: R;\n    } | {\n        $lt?: R;\n    } | {\n        $lte?: R;\n    } | {\n        $between?: [R, R];\n    } | {\n        $in?: R[];\n    } | {\n        $nin?: R[];\n    } | {\n        $keyin?: object;\n    } | {\n        $nkeyin?: object;\n    } | {\n        $definedin?: object;\n    } | {\n        $undefinedin?: object;\n    } | {\n        $regex?: RegExp | string | [string, string];\n    } | {\n        $containsNone?: ContainsHelperType<R>;\n    } | {\n        $containsAny?: ContainsHelperType<R>;\n    } | {\n        $contains?: ContainsHelperType<R>;\n    } | {\n        $type?: string;\n    } | {\n        $finite?: boolean;\n    } | {\n        $size?: number;\n    } | {\n        $len?: number;\n    } | {\n        $where?: (val?: R) => boolean;\n    };\n    type Query<T> = {\n        [P in keyof T]?: LokiOps<T[P]> | T[P];\n    } & {\n        $and?: Query<T>[];\n    } & {\n        $or?: Query<T>[];\n    } & {\n        $fts?: FullTextSearchQuery;\n    };\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/loki/src/unique_index.d.ts",
    "content": "export declare class UniqueIndex {\n    private _field;\n    private _lokiMap;\n    private _valMap;\n    /**\n     * Constructs an unique index object.\n     * @param {string} propertyField - the property field to index\n     */\n    constructor(propertyField: string);\n    /**\n     * Sets a document's unique index.\n     * @param {number} id loki id to associate with value\n     * @param {*} value  value to associate with id\n     */\n    set(id: number, value: any): void;\n    /**\n     * Returns the $loki id of an unique value.\n     * @param {*} value the value to retrieve a loki id match for\n     */\n    get(value: any): number;\n    /**\n     * Updates a document's unique index.\n     * @param {number} id (loki) id of document to update the value to\n     * @param {*} value value to associate with loki id\n     */\n    update(id: number, value: any): void;\n    /**\n     * Removes an unique index.\n     * @param {number} id (loki) id to remove from index\n     */\n    remove(id: number): void;\n    /**\n     * Clears the unique index.\n     */\n    clear(): void;\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/memory-storage/src/index.d.ts",
    "content": "import { MemoryStorage } from \"./memory_storage\";\nexport { MemoryStorage };\nexport default MemoryStorage;\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/memory-storage/src/memory_storage.d.ts",
    "content": "import { Dict, StorageAdapter } from \"../../common/types\";\n/**\n * An in-memory persistence adapter for an in-memory database.\n * This simple 'key/value' adapter is intended for unit testing and diagnostics.\n */\nexport declare class MemoryStorage implements StorageAdapter {\n    hashStore: Dict<{\n        savecount: number;\n        lastsave: Date;\n        value: string;\n    }>;\n    options: MemoryStorage.Options;\n    /**\n     * Registers the local storage as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the local storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} options - memory storage options\n     * @param {boolean} [options.asyncResponses=false] - whether callbacks are invoked asynchronously (default: false)\n     * @param {int} [options.asyncTimeout=50] - timeout in ms to queue callbacks (default: 50)\n     */\n    constructor(options?: MemoryStorage.Options);\n    /**\n     * Loads a serialized database from its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<string>;\n    /**\n     * Saves a serialized database to its in-memory store.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {string} dbstring - the database content\n     * @returns {Promise} a Promise that resolves after the database was persisted\n     */\n    saveDatabase(dbname: string, dbstring: string): Promise<void>;\n    /**\n     * Deletes a database from its in-memory store.\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     */\n    deleteDatabase(dbname: string): Promise<void>;\n}\nexport declare namespace MemoryStorage {\n    interface Options {\n        asyncResponses?: boolean;\n        asyncTimeout?: number;\n    }\n}\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/partitioning-adapter/src/index.d.ts",
    "content": "import { PartitioningAdapter } from \"./partitioning_adapter\";\nexport { PartitioningAdapter };\nexport default PartitioningAdapter;\n"
  },
  {
    "path": "dist/packages/partitioning-adapter/types/partitioning-adapter/src/partitioning_adapter.d.ts",
    "content": "import { Loki } from \"../../loki/src/loki\";\nimport { StorageAdapter } from \"../../common/types\";\n/**\n * An adapter for adapters. Converts a non reference mode adapter into a reference mode adapter\n * which can perform destructuring and partitioning. Each collection will be stored in its own key/save and\n * only dirty collections will be saved. If you  turn on paging with default page size of 25megs and save\n * a 75 meg collection it should use up roughly 3 save slots (key/value pairs sent to inner adapter).\n * A dirty collection that spans three pages will save all three pages again\n * Paging mode was added mainly because Chrome has issues saving 'too large' of a string within a\n * single IndexedDB row. If a single document update causes the collection to be flagged as dirty, all\n * of that collection's pages will be written on next save.\n */\nexport declare class PartitioningAdapter implements StorageAdapter {\n    mode: string;\n    private _adapter;\n    private _dbref;\n    private _dbname;\n    private _pageIterator;\n    private _paging;\n    private _pageSize;\n    private _delimiter;\n    private _dirtyPartitions;\n    /**\n     * Registers the partitioning adapter as plugin.\n     */\n    static register(): void;\n    /**\n     * Deregisters the partitioning storage as plugin.\n     */\n    static deregister(): void;\n    /**\n     * @param {object} adapter - reference to a 'non-reference' mode loki adapter instance.\n     * @param {boolean} paging - (default: false) set to true to enable paging collection data.\n     * @param {number} pageSize - (default : 25MB) you can use this to limit size of strings passed to inner adapter.\n     * @param {string} delimiter - allows you to override the default delimiter\n     */\n    constructor(adapter: StorageAdapter, {paging, pageSize, delimiter}?: {\n        paging?: boolean;\n        pageSize?: number;\n        delimiter?: string;\n    });\n    /**\n     * Loads a database which was partitioned into several key/value saves.\n     * (Loki persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @returns {Promise} a Promise that resolves after the database was loaded\n     */\n    loadDatabase(dbname: string): Promise<any>;\n    /**\n     * Used to sequentially load each collection partition, one at a time.\n     *\n     * @param {int} partition - ordinal collection position to load next\n     * @returns {Promise} a Promise that resolves after the next partition is loaded\n     */\n    private _loadNextPartition(partition);\n    /**\n     * Used to sequentially load the next page of collection partition, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next page is loaded\n     */\n    private _loadNextPage();\n    /**\n     * Saves a database by partioning into separate key/value saves.\n     * (Loki 'reference mode' persistence adapter interface function)\n     *\n     * @param {string} dbname - name of the database (filename/keyname)\n     * @param {object} dbref - reference to database which we will partition and save.\n     * @returns {Promise} a Promise that resolves after the database was deleted\n     *\n     */\n    exportDatabase(dbname: string, dbref: Loki): Promise<void>;\n    /**\n     * Helper method used internally to save each dirty collection, one at a time.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPartition();\n    /**\n     * Helper method used internally to generate and save the next page of the current (dirty) partition.\n     *\n     * @returns {Promise} a Promise that resolves after the next partition is saved\n     */\n    private _saveNextPage();\n}\n"
  },
  {
    "path": "docs/comparators.md",
    "content": "# Loki Comparators\n\n>Comparators (in javascript and loki) are functions which accept two values and return :\n>- 0 : if the first and second are considered equal\n>- -1 : if the first is less than the second\n>- 1 : if the first is greater than the second\n\n## Overview\nSince comparators now play a important role in customizing and fine-tuning LokiDB, this page will attempt to summarize the reasoning behind this increased structuring. \n\nIn the previous version of LokiDB (LokiJS), various components such as find ops, BinaryIndices and sorting shared a common set of helper functions serving as a common comparator. This arbitrary co-mingling inadvertently became standard as it would have been too much of a breaking change to decouple that later on (although some attempts to provide additional options were later added).\n\nIn LokiDB, to support decoupling these various components, we have established a 'ComparatorMap' which is a collection of named comparator functions.\n\nLokiDB utilizes these comparators for : \n- Unindexed sorting\n- Used with [RangedIndexes](./ranged_indexes.md) (such as our provided \"avl\" index) for higher performance filtering.\n- Can be optionally leveraged within unindexed find() operations (like $eq, $gt, $gte, $lt, $lte, $bewtween) when using our new 'ComparatorOperatorPackage' (See [operators.md](./operators.md)).  \n\n## Why would I need more than the default \"js\" comparator?\n\nOut of the box, LokiDB provides some base comparators :\n- \"js\" (default) : fastest, pure javascript with strict equality for $eq\n- \"abstract-js\": fast, pure javascript with loose equality\n- \"abstract-date\": can be used for comparing dates in various formats\n- \"loki\" comparators: slower, safer for mixed datatypes in ranged indexes.  This more closely resembles the comparator functionality which existed in LokiJS.\n- (possible additon) \"string-insensitive\" : could be used for comparing, sorting strings with case insensitivity.\n\nIndividual comparators can be selected from the above to be used for indexing, sorting, or filtering... whichever makes the most sense from a performance, functional, or type safety perspective.\n\n## Custom, user-defined comparators\nIf the various 'built-in' comparators don't fit a particular use case,  users can define their own comparator functions and add to (or override) comparators within the ComparatorMap.  They can then be leveraged in various places for sorting, indexing, filtering.  This configuration is done when instancing your Loki database instance, within the constructor.\n\nAn Example of this might look like the following : \n```javascript\n// define comparator function\nlet myComparator = (a, b) => {\n   if (a === b) return 0;\n   if (a > b) return 1;\n   return -1;\n}\n\n// pass in any number of comparators to add to or override those aleady registered\nlet db = new Loki(\"test.db\", {\n   comparatorMap: {\n      \"MyComparator\": myComparator\n   }\n});\n```\n\nHaving configured the above example, you might use them within collections, such as this simplesort() operation :\n```javascript\n// when instancing a new collection, you can specify this to override the default \"js\" unindexedSortComparator.\nlet coll = db.addCollection(\"users\", {\n   unindexedSortComparator: \"MyComparator\"\n});\n\ncoll.insert(someDocuments);\n\n// this will use the currently configured default unindexedSortComparator\nlet result = coll.simplesort(\"name\");\n\n// simplesort also allows you to override the default comparator in options\nlet reversed = coll.simplesort(\"name\", { \n   desc: true,\n   unindexedSortComparator: \"string-insensitive\" \n});\n\n```\n\nOther uses for utilizing the named comparators include defining your own [LokiOperatorPackage](./operators.md) and using within [RangedIndexes](./ranged_indexes.md).  Those topics will go into details and give code samples within their respective pages.\n\nTransform steps such as 'find' filtering and simplesort steps will also be able to leverage these, either explicitly or via options.\n\n## Summary\nIn the future, anywhere where these comparators can be leveraged, we will likely do so... to allow the ability for the user to customize and optimize LokiDB to best work with their data.\n\nRegistration of user defined comparators needs to done every time you re-instance the database.  Only the names of the comparators are persisted within your saved/serialized database.  While this is an additional responsibility, it also allows experimentation to determine the performance (for tuning).\n\n**_Warning_** : If a user defined comparator is paired with a range index, it is important that the comparator not change over time.  Ranged indexes (typically) persist themselves as ordered represenations and future relative calculations of re-organization across inserts, updates, and removes depend on consistent comparison results.\n\nIf your custom comparator is **_not_** used by a ranged index, you are free to experiment and refine the comparison results over time to reflect and refine the functional output of various LokiDB tasks. "
  },
  {
    "path": "docs/css/codemirror/codemirror.css",
    "content": "/* BASICS */\n\n.CodeMirror {\n  /* Set height, width, borders, and global font properties here */\n  font-family: monospace;\n  height: 300px;\n  color: black;\n}\n\n/* PADDING */\n\n.CodeMirror-lines {\n  padding: 4px 0; /* Vertical padding around content */\n}\n.CodeMirror pre {\n  padding: 0 4px; /* Horizontal padding of content */\n}\n\n.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {\n  background-color: white; /* The little square between H and V scrollbars */\n}\n\n/* GUTTER */\n\n.CodeMirror-gutters {\n  border-right: 1px solid #ddd;\n  background-color: #f7f7f7;\n  white-space: nowrap;\n}\n.CodeMirror-linenumbers {}\n.CodeMirror-linenumber {\n  padding: 0 3px 0 5px;\n  min-width: 20px;\n  text-align: right;\n  color: #999;\n  white-space: nowrap;\n}\n\n.CodeMirror-guttermarker { color: black; }\n.CodeMirror-guttermarker-subtle { color: #999; }\n\n/* CURSOR */\n\n.CodeMirror-cursor {\n  border-left: 1px solid black;\n  border-right: none;\n  width: 0;\n}\n/* Shown when moving in bi-directional text */\n.CodeMirror div.CodeMirror-secondarycursor {\n  border-left: 1px solid silver;\n}\n.cm-fat-cursor .CodeMirror-cursor {\n  width: auto;\n  border: 0 !important;\n  background: #7e7;\n}\n.cm-fat-cursor div.CodeMirror-cursors {\n  z-index: 1;\n}\n\n.cm-animate-fat-cursor {\n  width: auto;\n  border: 0;\n  -webkit-animation: blink 1.06s steps(1) infinite;\n  -moz-animation: blink 1.06s steps(1) infinite;\n  animation: blink 1.06s steps(1) infinite;\n  background-color: #7e7;\n}\n@-moz-keyframes blink {\n  0% {}\n  50% { background-color: transparent; }\n  100% {}\n}\n@-webkit-keyframes blink {\n  0% {}\n  50% { background-color: transparent; }\n  100% {}\n}\n@keyframes blink {\n  0% {}\n  50% { background-color: transparent; }\n  100% {}\n}\n\n/* Can style cursor different in overwrite (non-insert) mode */\n.CodeMirror-overwrite .CodeMirror-cursor {}\n\n.cm-tab { display: inline-block; text-decoration: inherit; }\n\n.CodeMirror-rulers {\n  position: absolute;\n  left: 0; right: 0; top: -50px; bottom: -20px;\n  overflow: hidden;\n}\n.CodeMirror-ruler {\n  border-left: 1px solid #ccc;\n  top: 0; bottom: 0;\n  position: absolute;\n}\n\n/* DEFAULT THEME */\n\n.cm-s-default .cm-header {color: blue;}\n.cm-s-default .cm-quote {color: #090;}\n.cm-negative {color: #d44;}\n.cm-positive {color: #292;}\n.cm-header, .cm-strong {font-weight: bold;}\n.cm-em {font-style: italic;}\n.cm-link {text-decoration: underline;}\n.cm-strikethrough {text-decoration: line-through;}\n\n.cm-s-default .cm-keyword {color: #708;}\n.cm-s-default .cm-atom {color: #219;}\n.cm-s-default .cm-number {color: #164;}\n.cm-s-default .cm-def {color: #00f;}\n.cm-s-default .cm-variable,\n.cm-s-default .cm-punctuation,\n.cm-s-default .cm-property,\n.cm-s-default .cm-operator {}\n.cm-s-default .cm-variable-2 {color: #05a;}\n.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}\n.cm-s-default .cm-comment {color: #a50;}\n.cm-s-default .cm-string {color: #a11;}\n.cm-s-default .cm-string-2 {color: #f50;}\n.cm-s-default .cm-meta {color: #555;}\n.cm-s-default .cm-qualifier {color: #555;}\n.cm-s-default .cm-builtin {color: #30a;}\n.cm-s-default .cm-bracket {color: #997;}\n.cm-s-default .cm-tag {color: #170;}\n.cm-s-default .cm-attribute {color: #00c;}\n.cm-s-default .cm-hr {color: #999;}\n.cm-s-default .cm-link {color: #00c;}\n\n.cm-s-default .cm-error {color: #f00;}\n.cm-invalidchar {color: #f00;}\n\n.CodeMirror-composing { border-bottom: 2px solid; }\n\n/* Default styles for common addons */\n\ndiv.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}\ndiv.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}\n.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }\n.CodeMirror-activeline-background {background: #e8f2ff;}\n\n/* STOP */\n\n/* The rest of this file contains styles related to the mechanics of\n   the editor. You probably shouldn't touch them. */\n\n.CodeMirror {\n  position: relative;\n  overflow: hidden;\n  background: white;\n}\n\n.CodeMirror-scroll {\n  overflow: scroll !important; /* Things will break if this is overridden */\n  /* 30px is the magic margin used to hide the element's real scrollbars */\n  /* See overflow: hidden in .CodeMirror */\n  margin-bottom: -30px; margin-right: -30px;\n  padding-bottom: 30px;\n  height: 100%;\n  outline: none; /* Prevent dragging from highlighting the element */\n  position: relative;\n}\n.CodeMirror-sizer {\n  position: relative;\n  border-right: 30px solid transparent;\n}\n\n/* The fake, visible scrollbars. Used to force redraw during scrolling\n   before actual scrolling happens, thus preventing shaking and\n   flickering artifacts. */\n.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {\n  position: absolute;\n  z-index: 6;\n  display: none;\n}\n.CodeMirror-vscrollbar {\n  right: 0; top: 0;\n  overflow-x: hidden;\n  overflow-y: scroll;\n}\n.CodeMirror-hscrollbar {\n  bottom: 0; left: 0;\n  overflow-y: hidden;\n  overflow-x: scroll;\n}\n.CodeMirror-scrollbar-filler {\n  right: 0; bottom: 0;\n}\n.CodeMirror-gutter-filler {\n  left: 0; bottom: 0;\n}\n\n.CodeMirror-gutters {\n  position: absolute; left: 0; top: 0;\n  min-height: 100%;\n  z-index: 3;\n}\n.CodeMirror-gutter {\n  white-space: normal;\n  height: 100%;\n  display: inline-block;\n  vertical-align: top;\n  margin-bottom: -30px;\n}\n.CodeMirror-gutter-wrapper {\n  position: absolute;\n  z-index: 4;\n  background: none !important;\n  border: none !important;\n}\n.CodeMirror-gutter-background {\n  position: absolute;\n  top: 0; bottom: 0;\n  z-index: 4;\n}\n.CodeMirror-gutter-elt {\n  position: absolute;\n  cursor: default;\n  z-index: 4;\n}\n.CodeMirror-gutter-wrapper ::selection { background-color: transparent }\n.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }\n\n.CodeMirror-lines {\n  cursor: text;\n  min-height: 1px; /* prevents collapsing before first draw */\n}\n.CodeMirror pre {\n  /* Reset some styles that the rest of the page might have set */\n  -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;\n  border-width: 0;\n  background: transparent;\n  font-family: inherit;\n  font-size: inherit;\n  margin: 0;\n  white-space: pre;\n  word-wrap: normal;\n  line-height: inherit;\n  color: inherit;\n  z-index: 2;\n  position: relative;\n  overflow: visible;\n  -webkit-tap-highlight-color: transparent;\n  -webkit-font-variant-ligatures: contextual;\n  font-variant-ligatures: contextual;\n}\n.CodeMirror-wrap pre {\n  word-wrap: break-word;\n  white-space: pre-wrap;\n  word-break: normal;\n}\n\n.CodeMirror-linebackground {\n  position: absolute;\n  left: 0; right: 0; top: 0; bottom: 0;\n  z-index: 0;\n}\n\n.CodeMirror-linewidget {\n  position: relative;\n  z-index: 2;\n  overflow: auto;\n}\n\n.CodeMirror-widget {}\n\n.CodeMirror-rtl pre { direction: rtl; }\n\n.CodeMirror-code {\n  outline: none;\n}\n\n/* Force content-box sizing for the elements where we expect it */\n.CodeMirror-scroll,\n.CodeMirror-sizer,\n.CodeMirror-gutter,\n.CodeMirror-gutters,\n.CodeMirror-linenumber {\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\n.CodeMirror-measure {\n  position: absolute;\n  width: 100%;\n  height: 0;\n  overflow: hidden;\n  visibility: hidden;\n}\n\n.CodeMirror-cursor {\n  position: absolute;\n  pointer-events: none;\n}\n.CodeMirror-measure pre { position: static; }\n\ndiv.CodeMirror-cursors {\n  visibility: hidden;\n  position: relative;\n  z-index: 3;\n}\ndiv.CodeMirror-dragcursors {\n  visibility: visible;\n}\n\n.CodeMirror-focused div.CodeMirror-cursors {\n  visibility: visible;\n}\n\n.CodeMirror-selected { background: #d9d9d9; }\n.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }\n.CodeMirror-crosshair { cursor: crosshair; }\n.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }\n.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }\n\n.cm-searching {\n  background: #ffa;\n  background: rgba(255, 255, 0, .4);\n}\n\n/* Used to force a border model for a node */\n.cm-force-border { padding-right: .1px; }\n\n@media print {\n  /* Hide the cursor when printing */\n  .CodeMirror div.CodeMirror-cursors {\n    visibility: hidden;\n  }\n}\n\n/* See issue #2901 */\n.cm-tab-wrap-hack:after { content: ''; }\n\n/* Help users use markselection to safely style text background */\nspan.CodeMirror-selectedtext { background: none; }\n"
  },
  {
    "path": "docs/css/codemirror/foldgutter.css",
    "content": ".CodeMirror-foldmarker {\n  color: blue;\n  text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px;\n  font-family: arial;\n  line-height: .3;\n  cursor: pointer;\n}\n.CodeMirror-foldgutter {\n  width: .7em;\n}\n.CodeMirror-foldgutter-open,\n.CodeMirror-foldgutter-folded {\n  cursor: pointer;\n}\n.CodeMirror-foldgutter-open:after {\n  content: \"\\25BE\";\n}\n.CodeMirror-foldgutter-folded:after {\n  content: \"\\25B8\";\n}\n"
  },
  {
    "path": "docs/css/javascript_editor.css",
    "content": ".jse-editor {\n  display: block;\n  position: relative;\n  border: 1px solid #d5d5d5;\n  font-size: 91.1%;\n}\n\n.jse-button {\n  margin: 5px;\n  flex: 1;\n  font-size: 12px;\n}\n\n.jse-output {\n  padding: 10px 10px 10px 15px;\n  font-size: 11px;\n  font-family: monaco, monospace;\n  max-height: 15em;\n  border-top: 1px solid #d5d5d5;\n  background: transparent;\n  overflow-y: scroll;\n}\n\n.jse-output span {\n  display: block;\n}\n\n.jse-output-log {\n}\n\n.jse-output-error {\n  color: red;\n}\n"
  },
  {
    "path": "docs/index.md",
    "content": "[![Build Status](https://travis-ci.org/LokiJS-Forge/LokiDB.svg?branch=master)](https://travis-ci.org/LokiJS-Forge/LokiDB)\n[![Coverage Status](https://coveralls.io/repos/github/LokiJS-Forge/LokiDB/badge.svg?branch=feature%2Fadd_build_system)](https://coveralls.io/github/LokiJS-Forge/LokiDB?branch=feature%2Fadd_build_system)\n\n\n# Welcome to LokiDB\n- Javascript Quickstart\n- Typescript Quickstart\n\n# API Reference\n- [Check it out](api/index.html).\n\n# Topics\n- Query Examples\n- Persistence\n- CollectionTransforms\n- [Understanding Comparators](./comparators.md)\n- [LokiOperatorPackage](./operator_packages.md)\n- [Loki Ranged Indexes](./ranged_indexes.md)\n\n# Getting Started\n\n```javascript\n\n```"
  },
  {
    "path": "docs/js/codemirror/addon/edit/matchbrackets.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  var ie_lt8 = /MSIE \\d/.test(navigator.userAgent) &&\n    (document.documentMode == null || document.documentMode < 8);\n\n  var Pos = CodeMirror.Pos;\n\n  var matching = {\"(\": \")>\", \")\": \"(<\", \"[\": \"]>\", \"]\": \"[<\", \"{\": \"}>\", \"}\": \"{<\"};\n\n  function findMatchingBracket(cm, where, config) {\n    var line = cm.getLineHandle(where.line), pos = where.ch - 1;\n    var afterCursor = config && config.afterCursor\n    if (afterCursor == null)\n      afterCursor = /(^| )cm-fat-cursor($| )/.test(cm.getWrapperElement().className)\n\n    // A cursor is defined as between two characters, but in in vim command mode\n    // (i.e. not insert mode), the cursor is visually represented as a\n    // highlighted box on top of the 2nd character. Otherwise, we allow matches\n    // from before or after the cursor.\n    var match = (!afterCursor && pos >= 0 && matching[line.text.charAt(pos)]) ||\n        matching[line.text.charAt(++pos)];\n    if (!match) return null;\n    var dir = match.charAt(1) == \">\" ? 1 : -1;\n    if (config && config.strict && (dir > 0) != (pos == where.ch)) return null;\n    var style = cm.getTokenTypeAt(Pos(where.line, pos + 1));\n\n    var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config);\n    if (found == null) return null;\n    return {from: Pos(where.line, pos), to: found && found.pos,\n            match: found && found.ch == match.charAt(0), forward: dir > 0};\n  }\n\n  // bracketRegex is used to specify which type of bracket to scan\n  // should be a regexp, e.g. /[[\\]]/\n  //\n  // Note: If \"where\" is on an open bracket, then this bracket is ignored.\n  //\n  // Returns false when no bracket was found, null when it reached\n  // maxScanLines and gave up\n  function scanForBracket(cm, where, dir, style, config) {\n    var maxScanLen = (config && config.maxScanLineLength) || 10000;\n    var maxScanLines = (config && config.maxScanLines) || 1000;\n\n    var stack = [];\n    var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\\]]/;\n    var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)\n                          : Math.max(cm.firstLine() - 1, where.line - maxScanLines);\n    for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {\n      var line = cm.getLine(lineNo);\n      if (!line) continue;\n      var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1;\n      if (line.length > maxScanLen) continue;\n      if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0);\n      for (; pos != end; pos += dir) {\n        var ch = line.charAt(pos);\n        if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) {\n          var match = matching[ch];\n          if ((match.charAt(1) == \">\") == (dir > 0)) stack.push(ch);\n          else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch};\n          else stack.pop();\n        }\n      }\n    }\n    return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;\n  }\n\n  function matchBrackets(cm, autoclear, config) {\n    // Disable brace matching in long lines, since it'll cause hugely slow updates\n    var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000;\n    var marks = [], ranges = cm.listSelections();\n    for (var i = 0; i < ranges.length; i++) {\n      var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, config);\n      if (match && cm.getLine(match.from.line).length <= maxHighlightLen) {\n        var style = match.match ? \"CodeMirror-matchingbracket\" : \"CodeMirror-nonmatchingbracket\";\n        marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style}));\n        if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen)\n          marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style}));\n      }\n    }\n\n    if (marks.length) {\n      // Kludge to work around the IE bug from issue #1193, where text\n      // input stops going to the textare whever this fires.\n      if (ie_lt8 && cm.state.focused) cm.focus();\n\n      var clear = function() {\n        cm.operation(function() {\n          for (var i = 0; i < marks.length; i++) marks[i].clear();\n        });\n      };\n      if (autoclear) setTimeout(clear, 800);\n      else return clear;\n    }\n  }\n\n  var currentlyHighlighted = null;\n  function doMatchBrackets(cm) {\n    cm.operation(function() {\n      if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}\n      currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);\n    });\n  }\n\n  CodeMirror.defineOption(\"matchBrackets\", false, function(cm, val, old) {\n    if (old && old != CodeMirror.Init) {\n      cm.off(\"cursorActivity\", doMatchBrackets);\n      if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}\n    }\n    if (val) {\n      cm.state.matchBrackets = typeof val == \"object\" ? val : {};\n      cm.on(\"cursorActivity\", doMatchBrackets);\n    }\n  });\n\n  CodeMirror.defineExtension(\"matchBrackets\", function() {matchBrackets(this, true);});\n  CodeMirror.defineExtension(\"findMatchingBracket\", function(pos, config, oldConfig){\n    // Backwards-compatibility kludge\n    if (oldConfig || typeof config == \"boolean\") {\n      if (!oldConfig) {\n        config = config ? {strict: true} : null\n      } else {\n        oldConfig.strict = config\n        config = oldConfig\n      }\n    }\n    return findMatchingBracket(this, pos, config)\n  });\n  CodeMirror.defineExtension(\"scanForBracket\", function(pos, dir, style, config){\n    return scanForBracket(this, pos, dir, style, config);\n  });\n});\n"
  },
  {
    "path": "docs/js/codemirror/addon/fold/brace-fold.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.registerHelper(\"fold\", \"brace\", function(cm, start) {\n  var line = start.line, lineText = cm.getLine(line);\n  var tokenType;\n\n  function findOpening(openCh) {\n    for (var at = start.ch, pass = 0;;) {\n      var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1);\n      if (found == -1) {\n        if (pass == 1) break;\n        pass = 1;\n        at = lineText.length;\n        continue;\n      }\n      if (pass == 1 && found < start.ch) break;\n      tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1));\n      if (!/^(comment|string)/.test(tokenType)) return found + 1;\n      at = found - 1;\n    }\n  }\n\n  var startToken = \"{\", endToken = \"}\", startCh = findOpening(\"{\");\n  if (startCh == null) {\n    startToken = \"[\", endToken = \"]\";\n    startCh = findOpening(\"[\");\n  }\n\n  if (startCh == null) return;\n  var count = 1, lastLine = cm.lastLine(), end, endCh;\n  outer: for (var i = line; i <= lastLine; ++i) {\n    var text = cm.getLine(i), pos = i == line ? startCh : 0;\n    for (;;) {\n      var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);\n      if (nextOpen < 0) nextOpen = text.length;\n      if (nextClose < 0) nextClose = text.length;\n      pos = Math.min(nextOpen, nextClose);\n      if (pos == text.length) break;\n      if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) {\n        if (pos == nextOpen) ++count;\n        else if (!--count) { end = i; endCh = pos; break outer; }\n      }\n      ++pos;\n    }\n  }\n  if (end == null || line == end && endCh == startCh) return;\n  return {from: CodeMirror.Pos(line, startCh),\n          to: CodeMirror.Pos(end, endCh)};\n});\n\nCodeMirror.registerHelper(\"fold\", \"import\", function(cm, start) {\n  function hasImport(line) {\n    if (line < cm.firstLine() || line > cm.lastLine()) return null;\n    var start = cm.getTokenAt(CodeMirror.Pos(line, 1));\n    if (!/\\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));\n    if (start.type != \"keyword\" || start.string != \"import\") return null;\n    // Now find closing semicolon, return its position\n    for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) {\n      var text = cm.getLine(i), semi = text.indexOf(\";\");\n      if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)};\n    }\n  }\n\n  var startLine = start.line, has = hasImport(startLine), prev;\n  if (!has || hasImport(startLine - 1) || ((prev = hasImport(startLine - 2)) && prev.end.line == startLine - 1))\n    return null;\n  for (var end = has.end;;) {\n    var next = hasImport(end.line + 1);\n    if (next == null) break;\n    end = next.end;\n  }\n  return {from: cm.clipPos(CodeMirror.Pos(startLine, has.startCh + 1)), to: end};\n});\n\nCodeMirror.registerHelper(\"fold\", \"include\", function(cm, start) {\n  function hasInclude(line) {\n    if (line < cm.firstLine() || line > cm.lastLine()) return null;\n    var start = cm.getTokenAt(CodeMirror.Pos(line, 1));\n    if (!/\\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));\n    if (start.type == \"meta\" && start.string.slice(0, 8) == \"#include\") return start.start + 8;\n  }\n\n  var startLine = start.line, has = hasInclude(startLine);\n  if (has == null || hasInclude(startLine - 1) != null) return null;\n  for (var end = startLine;;) {\n    var next = hasInclude(end + 1);\n    if (next == null) break;\n    ++end;\n  }\n  return {from: CodeMirror.Pos(startLine, has + 1),\n          to: cm.clipPos(CodeMirror.Pos(end))};\n});\n\n});\n"
  },
  {
    "path": "docs/js/codemirror/addon/fold/foldcode.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  function doFold(cm, pos, options, force) {\n    if (options && options.call) {\n      var finder = options;\n      options = null;\n    } else {\n      var finder = getOption(cm, options, \"rangeFinder\");\n    }\n    if (typeof pos == \"number\") pos = CodeMirror.Pos(pos, 0);\n    var minSize = getOption(cm, options, \"minFoldSize\");\n\n    function getRange(allowFolded) {\n      var range = finder(cm, pos);\n      if (!range || range.to.line - range.from.line < minSize) return null;\n      var marks = cm.findMarksAt(range.from);\n      for (var i = 0; i < marks.length; ++i) {\n        if (marks[i].__isFold && force !== \"fold\") {\n          if (!allowFolded) return null;\n          range.cleared = true;\n          marks[i].clear();\n        }\n      }\n      return range;\n    }\n\n    var range = getRange(true);\n    if (getOption(cm, options, \"scanUp\")) while (!range && pos.line > cm.firstLine()) {\n      pos = CodeMirror.Pos(pos.line - 1, 0);\n      range = getRange(false);\n    }\n    if (!range || range.cleared || force === \"unfold\") return;\n\n    var myWidget = makeWidget(cm, options);\n    CodeMirror.on(myWidget, \"mousedown\", function(e) {\n      myRange.clear();\n      CodeMirror.e_preventDefault(e);\n    });\n    var myRange = cm.markText(range.from, range.to, {\n      replacedWith: myWidget,\n      clearOnEnter: getOption(cm, options, \"clearOnEnter\"),\n      __isFold: true\n    });\n    myRange.on(\"clear\", function(from, to) {\n      CodeMirror.signal(cm, \"unfold\", cm, from, to);\n    });\n    CodeMirror.signal(cm, \"fold\", cm, range.from, range.to);\n  }\n\n  function makeWidget(cm, options) {\n    var widget = getOption(cm, options, \"widget\");\n    if (typeof widget == \"string\") {\n      var text = document.createTextNode(widget);\n      widget = document.createElement(\"span\");\n      widget.appendChild(text);\n      widget.className = \"CodeMirror-foldmarker\";\n    }\n    return widget;\n  }\n\n  // Clumsy backwards-compatible interface\n  CodeMirror.newFoldFunction = function(rangeFinder, widget) {\n    return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); };\n  };\n\n  // New-style interface\n  CodeMirror.defineExtension(\"foldCode\", function(pos, options, force) {\n    doFold(this, pos, options, force);\n  });\n\n  CodeMirror.defineExtension(\"isFolded\", function(pos) {\n    var marks = this.findMarksAt(pos);\n    for (var i = 0; i < marks.length; ++i)\n      if (marks[i].__isFold) return true;\n  });\n\n  CodeMirror.commands.toggleFold = function(cm) {\n    cm.foldCode(cm.getCursor());\n  };\n  CodeMirror.commands.fold = function(cm) {\n    cm.foldCode(cm.getCursor(), null, \"fold\");\n  };\n  CodeMirror.commands.unfold = function(cm) {\n    cm.foldCode(cm.getCursor(), null, \"unfold\");\n  };\n  CodeMirror.commands.foldAll = function(cm) {\n    cm.operation(function() {\n      for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)\n        cm.foldCode(CodeMirror.Pos(i, 0), null, \"fold\");\n    });\n  };\n  CodeMirror.commands.unfoldAll = function(cm) {\n    cm.operation(function() {\n      for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)\n        cm.foldCode(CodeMirror.Pos(i, 0), null, \"unfold\");\n    });\n  };\n\n  CodeMirror.registerHelper(\"fold\", \"combine\", function() {\n    var funcs = Array.prototype.slice.call(arguments, 0);\n    return function(cm, start) {\n      for (var i = 0; i < funcs.length; ++i) {\n        var found = funcs[i](cm, start);\n        if (found) return found;\n      }\n    };\n  });\n\n  CodeMirror.registerHelper(\"fold\", \"auto\", function(cm, start) {\n    var helpers = cm.getHelpers(start, \"fold\");\n    for (var i = 0; i < helpers.length; i++) {\n      var cur = helpers[i](cm, start);\n      if (cur) return cur;\n    }\n  });\n\n  var defaultOptions = {\n    rangeFinder: CodeMirror.fold.auto,\n    widget: \"\\u2194\",\n    minFoldSize: 0,\n    scanUp: false,\n    clearOnEnter: true\n  };\n\n  CodeMirror.defineOption(\"foldOptions\", null);\n\n  function getOption(cm, options, name) {\n    if (options && options[name] !== undefined)\n      return options[name];\n    var editorOptions = cm.options.foldOptions;\n    if (editorOptions && editorOptions[name] !== undefined)\n      return editorOptions[name];\n    return defaultOptions[name];\n  }\n\n  CodeMirror.defineExtension(\"foldOption\", function(options, name) {\n    return getOption(this, options, name);\n  });\n});\n"
  },
  {
    "path": "docs/js/codemirror/addon/fold/foldgutter.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"./foldcode\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"./foldcode\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineOption(\"foldGutter\", false, function(cm, val, old) {\n    if (old && old != CodeMirror.Init) {\n      cm.clearGutter(cm.state.foldGutter.options.gutter);\n      cm.state.foldGutter = null;\n      cm.off(\"gutterClick\", onGutterClick);\n      cm.off(\"change\", onChange);\n      cm.off(\"viewportChange\", onViewportChange);\n      cm.off(\"fold\", onFold);\n      cm.off(\"unfold\", onFold);\n      cm.off(\"swapDoc\", onChange);\n    }\n    if (val) {\n      cm.state.foldGutter = new State(parseOptions(val));\n      updateInViewport(cm);\n      cm.on(\"gutterClick\", onGutterClick);\n      cm.on(\"change\", onChange);\n      cm.on(\"viewportChange\", onViewportChange);\n      cm.on(\"fold\", onFold);\n      cm.on(\"unfold\", onFold);\n      cm.on(\"swapDoc\", onChange);\n    }\n  });\n\n  var Pos = CodeMirror.Pos;\n\n  function State(options) {\n    this.options = options;\n    this.from = this.to = 0;\n  }\n\n  function parseOptions(opts) {\n    if (opts === true) opts = {};\n    if (opts.gutter == null) opts.gutter = \"CodeMirror-foldgutter\";\n    if (opts.indicatorOpen == null) opts.indicatorOpen = \"CodeMirror-foldgutter-open\";\n    if (opts.indicatorFolded == null) opts.indicatorFolded = \"CodeMirror-foldgutter-folded\";\n    return opts;\n  }\n\n  function isFolded(cm, line) {\n    var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0));\n    for (var i = 0; i < marks.length; ++i)\n      if (marks[i].__isFold && marks[i].find().from.line == line) return marks[i];\n  }\n\n  function marker(spec) {\n    if (typeof spec == \"string\") {\n      var elt = document.createElement(\"div\");\n      elt.className = spec + \" CodeMirror-guttermarker-subtle\";\n      return elt;\n    } else {\n      return spec.cloneNode(true);\n    }\n  }\n\n  function updateFoldInfo(cm, from, to) {\n    var opts = cm.state.foldGutter.options, cur = from;\n    var minSize = cm.foldOption(opts, \"minFoldSize\");\n    var func = cm.foldOption(opts, \"rangeFinder\");\n    cm.eachLine(from, to, function(line) {\n      var mark = null;\n      if (isFolded(cm, cur)) {\n        mark = marker(opts.indicatorFolded);\n      } else {\n        var pos = Pos(cur, 0);\n        var range = func && func(cm, pos);\n        if (range && range.to.line - range.from.line >= minSize)\n          mark = marker(opts.indicatorOpen);\n      }\n      cm.setGutterMarker(line, opts.gutter, mark);\n      ++cur;\n    });\n  }\n\n  function updateInViewport(cm) {\n    var vp = cm.getViewport(), state = cm.state.foldGutter;\n    if (!state) return;\n    cm.operation(function() {\n      updateFoldInfo(cm, vp.from, vp.to);\n    });\n    state.from = vp.from; state.to = vp.to;\n  }\n\n  function onGutterClick(cm, line, gutter) {\n    var state = cm.state.foldGutter;\n    if (!state) return;\n    var opts = state.options;\n    if (gutter != opts.gutter) return;\n    var folded = isFolded(cm, line);\n    if (folded) folded.clear();\n    else cm.foldCode(Pos(line, 0), opts.rangeFinder);\n  }\n\n  function onChange(cm) {\n    var state = cm.state.foldGutter;\n    if (!state) return;\n    var opts = state.options;\n    state.from = state.to = 0;\n    clearTimeout(state.changeUpdate);\n    state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);\n  }\n\n  function onViewportChange(cm) {\n    var state = cm.state.foldGutter;\n    if (!state) return;\n    var opts = state.options;\n    clearTimeout(state.changeUpdate);\n    state.changeUpdate = setTimeout(function() {\n      var vp = cm.getViewport();\n      if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {\n        updateInViewport(cm);\n      } else {\n        cm.operation(function() {\n          if (vp.from < state.from) {\n            updateFoldInfo(cm, vp.from, state.from);\n            state.from = vp.from;\n          }\n          if (vp.to > state.to) {\n            updateFoldInfo(cm, state.to, vp.to);\n            state.to = vp.to;\n          }\n        });\n      }\n    }, opts.updateViewportTimeSpan || 400);\n  }\n\n  function onFold(cm, from) {\n    var state = cm.state.foldGutter;\n    if (!state) return;\n    var line = from.line;\n    if (line >= state.from && line < state.to)\n      updateFoldInfo(cm, line, line + 1);\n  }\n});\n"
  },
  {
    "path": "docs/js/codemirror/lib/codemirror.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// This is CodeMirror (http://codemirror.net), a code editor\n// implemented in JavaScript on top of the browser's DOM.\n//\n// You can find some technical background for some of the code below\n// at http://marijnhaverbeke.nl/blog/#cm-internals .\n\n(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n\ttypeof define === 'function' && define.amd ? define(factory) :\n\t(global.CodeMirror = factory());\n}(this, (function () { 'use strict';\n\n// Kludges for bugs and behavior differences that can't be feature\n// detected are enabled based on userAgent etc sniffing.\nvar userAgent = navigator.userAgent;\nvar platform = navigator.platform;\n\nvar gecko = /gecko\\/\\d/i.test(userAgent);\nvar ie_upto10 = /MSIE \\d/.test(userAgent);\nvar ie_11up = /Trident\\/(?:[7-9]|\\d{2,})\\..*rv:(\\d+)/.exec(userAgent);\nvar edge = /Edge\\/(\\d+)/.exec(userAgent);\nvar ie = ie_upto10 || ie_11up || edge;\nvar ie_version = ie && (ie_upto10 ? document.documentMode || 6 : +(edge || ie_11up)[1]);\nvar webkit = !edge && /WebKit\\//.test(userAgent);\nvar qtwebkit = webkit && /Qt\\/\\d+\\.\\d+/.test(userAgent);\nvar chrome = !edge && /Chrome\\//.test(userAgent);\nvar presto = /Opera\\//.test(userAgent);\nvar safari = /Apple Computer/.test(navigator.vendor);\nvar mac_geMountainLion = /Mac OS X 1\\d\\D([8-9]|\\d\\d)\\D/.test(userAgent);\nvar phantom = /PhantomJS/.test(userAgent);\n\nvar ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\\/\\w+/.test(userAgent);\nvar android = /Android/.test(userAgent);\n// This is woefully incomplete. Suggestions for alternative methods welcome.\nvar mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);\nvar mac = ios || /Mac/.test(platform);\nvar chromeOS = /\\bCrOS\\b/.test(userAgent);\nvar windows = /win/i.test(platform);\n\nvar presto_version = presto && userAgent.match(/Version\\/(\\d*\\.\\d*)/);\nif (presto_version) { presto_version = Number(presto_version[1]); }\nif (presto_version && presto_version >= 15) { presto = false; webkit = true; }\n// Some browsers use the wrong event properties to signal cmd/ctrl on OS X\nvar flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));\nvar captureRightClick = gecko || (ie && ie_version >= 9);\n\nfunction classTest(cls) { return new RegExp(\"(^|\\\\s)\" + cls + \"(?:$|\\\\s)\\\\s*\") }\n\nvar rmClass = function(node, cls) {\n  var current = node.className;\n  var match = classTest(cls).exec(current);\n  if (match) {\n    var after = current.slice(match.index + match[0].length);\n    node.className = current.slice(0, match.index) + (after ? match[1] + after : \"\");\n  }\n};\n\nfunction removeChildren(e) {\n  for (var count = e.childNodes.length; count > 0; --count)\n    { e.removeChild(e.firstChild); }\n  return e\n}\n\nfunction removeChildrenAndAdd(parent, e) {\n  return removeChildren(parent).appendChild(e)\n}\n\nfunction elt(tag, content, className, style) {\n  var e = document.createElement(tag);\n  if (className) { e.className = className; }\n  if (style) { e.style.cssText = style; }\n  if (typeof content == \"string\") { e.appendChild(document.createTextNode(content)); }\n  else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]); } }\n  return e\n}\n// wrapper for elt, which removes the elt from the accessibility tree\nfunction eltP(tag, content, className, style) {\n  var e = elt(tag, content, className, style);\n  e.setAttribute(\"role\", \"presentation\");\n  return e\n}\n\nvar range;\nif (document.createRange) { range = function(node, start, end, endNode) {\n  var r = document.createRange();\n  r.setEnd(endNode || node, end);\n  r.setStart(node, start);\n  return r\n}; }\nelse { range = function(node, start, end) {\n  var r = document.body.createTextRange();\n  try { r.moveToElementText(node.parentNode); }\n  catch(e) { return r }\n  r.collapse(true);\n  r.moveEnd(\"character\", end);\n  r.moveStart(\"character\", start);\n  return r\n}; }\n\nfunction contains(parent, child) {\n  if (child.nodeType == 3) // Android browser always returns false when child is a textnode\n    { child = child.parentNode; }\n  if (parent.contains)\n    { return parent.contains(child) }\n  do {\n    if (child.nodeType == 11) { child = child.host; }\n    if (child == parent) { return true }\n  } while (child = child.parentNode)\n}\n\nfunction activeElt() {\n  // IE and Edge may throw an \"Unspecified Error\" when accessing document.activeElement.\n  // IE < 10 will throw when accessed while the page is loading or in an iframe.\n  // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable.\n  var activeElement;\n  try {\n    activeElement = document.activeElement;\n  } catch(e) {\n    activeElement = document.body || null;\n  }\n  while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)\n    { activeElement = activeElement.shadowRoot.activeElement; }\n  return activeElement\n}\n\nfunction addClass(node, cls) {\n  var current = node.className;\n  if (!classTest(cls).test(current)) { node.className += (current ? \" \" : \"\") + cls; }\n}\nfunction joinClasses(a, b) {\n  var as = a.split(\" \");\n  for (var i = 0; i < as.length; i++)\n    { if (as[i] && !classTest(as[i]).test(b)) { b += \" \" + as[i]; } }\n  return b\n}\n\nvar selectInput = function(node) { node.select(); };\nif (ios) // Mobile Safari apparently has a bug where select() is broken.\n  { selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; }\nelse if (ie) // Suppress mysterious IE10 errors\n  { selectInput = function(node) { try { node.select(); } catch(_e) {} }; }\n\nfunction bind(f) {\n  var args = Array.prototype.slice.call(arguments, 1);\n  return function(){return f.apply(null, args)}\n}\n\nfunction copyObj(obj, target, overwrite) {\n  if (!target) { target = {}; }\n  for (var prop in obj)\n    { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))\n      { target[prop] = obj[prop]; } }\n  return target\n}\n\n// Counts the column offset in a string, taking tabs into account.\n// Used mostly to find indentation.\nfunction countColumn(string, end, tabSize, startIndex, startValue) {\n  if (end == null) {\n    end = string.search(/[^\\s\\u00a0]/);\n    if (end == -1) { end = string.length; }\n  }\n  for (var i = startIndex || 0, n = startValue || 0;;) {\n    var nextTab = string.indexOf(\"\\t\", i);\n    if (nextTab < 0 || nextTab >= end)\n      { return n + (end - i) }\n    n += nextTab - i;\n    n += tabSize - (n % tabSize);\n    i = nextTab + 1;\n  }\n}\n\nvar Delayed = function() {this.id = null;};\nDelayed.prototype.set = function (ms, f) {\n  clearTimeout(this.id);\n  this.id = setTimeout(f, ms);\n};\n\nfunction indexOf(array, elt) {\n  for (var i = 0; i < array.length; ++i)\n    { if (array[i] == elt) { return i } }\n  return -1\n}\n\n// Number of pixels added to scroller and sizer to hide scrollbar\nvar scrollerGap = 30;\n\n// Returned or thrown by various protocols to signal 'I'm not\n// handling this'.\nvar Pass = {toString: function(){return \"CodeMirror.Pass\"}};\n\n// Reused option objects for setSelection & friends\nvar sel_dontScroll = {scroll: false};\nvar sel_mouse = {origin: \"*mouse\"};\nvar sel_move = {origin: \"+move\"};\n\n// The inverse of countColumn -- find the offset that corresponds to\n// a particular column.\nfunction findColumn(string, goal, tabSize) {\n  for (var pos = 0, col = 0;;) {\n    var nextTab = string.indexOf(\"\\t\", pos);\n    if (nextTab == -1) { nextTab = string.length; }\n    var skipped = nextTab - pos;\n    if (nextTab == string.length || col + skipped >= goal)\n      { return pos + Math.min(skipped, goal - col) }\n    col += nextTab - pos;\n    col += tabSize - (col % tabSize);\n    pos = nextTab + 1;\n    if (col >= goal) { return pos }\n  }\n}\n\nvar spaceStrs = [\"\"];\nfunction spaceStr(n) {\n  while (spaceStrs.length <= n)\n    { spaceStrs.push(lst(spaceStrs) + \" \"); }\n  return spaceStrs[n]\n}\n\nfunction lst(arr) { return arr[arr.length-1] }\n\nfunction map(array, f) {\n  var out = [];\n  for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i); }\n  return out\n}\n\nfunction insertSorted(array, value, score) {\n  var pos = 0, priority = score(value);\n  while (pos < array.length && score(array[pos]) <= priority) { pos++; }\n  array.splice(pos, 0, value);\n}\n\nfunction nothing() {}\n\nfunction createObj(base, props) {\n  var inst;\n  if (Object.create) {\n    inst = Object.create(base);\n  } else {\n    nothing.prototype = base;\n    inst = new nothing();\n  }\n  if (props) { copyObj(props, inst); }\n  return inst\n}\n\nvar nonASCIISingleCaseWordChar = /[\\u00df\\u0587\\u0590-\\u05f4\\u0600-\\u06ff\\u3040-\\u309f\\u30a0-\\u30ff\\u3400-\\u4db5\\u4e00-\\u9fcc\\uac00-\\ud7af]/;\nfunction isWordCharBasic(ch) {\n  return /\\w/.test(ch) || ch > \"\\x80\" &&\n    (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))\n}\nfunction isWordChar(ch, helper) {\n  if (!helper) { return isWordCharBasic(ch) }\n  if (helper.source.indexOf(\"\\\\w\") > -1 && isWordCharBasic(ch)) { return true }\n  return helper.test(ch)\n}\n\nfunction isEmpty(obj) {\n  for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } }\n  return true\n}\n\n// Extending unicode characters. A series of a non-extending char +\n// any number of extending chars is treated as a single unit as far\n// as editing and measuring is concerned. This is not fully correct,\n// since some scripts/fonts/browsers also treat other configurations\n// of code points as a group.\nvar extendingChars = /[\\u0300-\\u036f\\u0483-\\u0489\\u0591-\\u05bd\\u05bf\\u05c1\\u05c2\\u05c4\\u05c5\\u05c7\\u0610-\\u061a\\u064b-\\u065e\\u0670\\u06d6-\\u06dc\\u06de-\\u06e4\\u06e7\\u06e8\\u06ea-\\u06ed\\u0711\\u0730-\\u074a\\u07a6-\\u07b0\\u07eb-\\u07f3\\u0816-\\u0819\\u081b-\\u0823\\u0825-\\u0827\\u0829-\\u082d\\u0900-\\u0902\\u093c\\u0941-\\u0948\\u094d\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09bc\\u09be\\u09c1-\\u09c4\\u09cd\\u09d7\\u09e2\\u09e3\\u0a01\\u0a02\\u0a3c\\u0a41\\u0a42\\u0a47\\u0a48\\u0a4b-\\u0a4d\\u0a51\\u0a70\\u0a71\\u0a75\\u0a81\\u0a82\\u0abc\\u0ac1-\\u0ac5\\u0ac7\\u0ac8\\u0acd\\u0ae2\\u0ae3\\u0b01\\u0b3c\\u0b3e\\u0b3f\\u0b41-\\u0b44\\u0b4d\\u0b56\\u0b57\\u0b62\\u0b63\\u0b82\\u0bbe\\u0bc0\\u0bcd\\u0bd7\\u0c3e-\\u0c40\\u0c46-\\u0c48\\u0c4a-\\u0c4d\\u0c55\\u0c56\\u0c62\\u0c63\\u0cbc\\u0cbf\\u0cc2\\u0cc6\\u0ccc\\u0ccd\\u0cd5\\u0cd6\\u0ce2\\u0ce3\\u0d3e\\u0d41-\\u0d44\\u0d4d\\u0d57\\u0d62\\u0d63\\u0dca\\u0dcf\\u0dd2-\\u0dd4\\u0dd6\\u0ddf\\u0e31\\u0e34-\\u0e3a\\u0e47-\\u0e4e\\u0eb1\\u0eb4-\\u0eb9\\u0ebb\\u0ebc\\u0ec8-\\u0ecd\\u0f18\\u0f19\\u0f35\\u0f37\\u0f39\\u0f71-\\u0f7e\\u0f80-\\u0f84\\u0f86\\u0f87\\u0f90-\\u0f97\\u0f99-\\u0fbc\\u0fc6\\u102d-\\u1030\\u1032-\\u1037\\u1039\\u103a\\u103d\\u103e\\u1058\\u1059\\u105e-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108d\\u109d\\u135f\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17b7-\\u17bd\\u17c6\\u17c9-\\u17d3\\u17dd\\u180b-\\u180d\\u18a9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193b\\u1a17\\u1a18\\u1a56\\u1a58-\\u1a5e\\u1a60\\u1a62\\u1a65-\\u1a6c\\u1a73-\\u1a7c\\u1a7f\\u1b00-\\u1b03\\u1b34\\u1b36-\\u1b3a\\u1b3c\\u1b42\\u1b6b-\\u1b73\\u1b80\\u1b81\\u1ba2-\\u1ba5\\u1ba8\\u1ba9\\u1c2c-\\u1c33\\u1c36\\u1c37\\u1cd0-\\u1cd2\\u1cd4-\\u1ce0\\u1ce2-\\u1ce8\\u1ced\\u1dc0-\\u1de6\\u1dfd-\\u1dff\\u200c\\u200d\\u20d0-\\u20f0\\u2cef-\\u2cf1\\u2de0-\\u2dff\\u302a-\\u302f\\u3099\\u309a\\ua66f-\\ua672\\ua67c\\ua67d\\ua6f0\\ua6f1\\ua802\\ua806\\ua80b\\ua825\\ua826\\ua8c4\\ua8e0-\\ua8f1\\ua926-\\ua92d\\ua947-\\ua951\\ua980-\\ua982\\ua9b3\\ua9b6-\\ua9b9\\ua9bc\\uaa29-\\uaa2e\\uaa31\\uaa32\\uaa35\\uaa36\\uaa43\\uaa4c\\uaab0\\uaab2-\\uaab4\\uaab7\\uaab8\\uaabe\\uaabf\\uaac1\\uabe5\\uabe8\\uabed\\udc00-\\udfff\\ufb1e\\ufe00-\\ufe0f\\ufe20-\\ufe26\\uff9e\\uff9f]/;\nfunction isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) }\n\n// Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range.\nfunction skipExtendingChars(str, pos, dir) {\n  while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir; }\n  return pos\n}\n\n// Returns the value from the range [`from`; `to`] that satisfies\n// `pred` and is closest to `from`. Assumes that at least `to` satisfies `pred`.\nfunction findFirst(pred, from, to) {\n  for (;;) {\n    if (Math.abs(from - to) <= 1) { return pred(from) ? from : to }\n    var mid = Math.floor((from + to) / 2);\n    if (pred(mid)) { to = mid; }\n    else { from = mid; }\n  }\n}\n\n// The display handles the DOM integration, both for input reading\n// and content drawing. It holds references to DOM nodes and\n// display-related state.\n\nfunction Display(place, doc, input) {\n  var d = this;\n  this.input = input;\n\n  // Covers bottom-right square when both scrollbars are present.\n  d.scrollbarFiller = elt(\"div\", null, \"CodeMirror-scrollbar-filler\");\n  d.scrollbarFiller.setAttribute(\"cm-not-content\", \"true\");\n  // Covers bottom of gutter when coverGutterNextToScrollbar is on\n  // and h scrollbar is present.\n  d.gutterFiller = elt(\"div\", null, \"CodeMirror-gutter-filler\");\n  d.gutterFiller.setAttribute(\"cm-not-content\", \"true\");\n  // Will contain the actual code, positioned to cover the viewport.\n  d.lineDiv = eltP(\"div\", null, \"CodeMirror-code\");\n  // Elements are added to these to represent selection and cursors.\n  d.selectionDiv = elt(\"div\", null, null, \"position: relative; z-index: 1\");\n  d.cursorDiv = elt(\"div\", null, \"CodeMirror-cursors\");\n  // A visibility: hidden element used to find the size of things.\n  d.measure = elt(\"div\", null, \"CodeMirror-measure\");\n  // When lines outside of the viewport are measured, they are drawn in this.\n  d.lineMeasure = elt(\"div\", null, \"CodeMirror-measure\");\n  // Wraps everything that needs to exist inside the vertically-padded coordinate system\n  d.lineSpace = eltP(\"div\", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],\n                    null, \"position: relative; outline: none\");\n  var lines = eltP(\"div\", [d.lineSpace], \"CodeMirror-lines\");\n  // Moved around its parent to cover visible view.\n  d.mover = elt(\"div\", [lines], null, \"position: relative\");\n  // Set to the height of the document, allowing scrolling.\n  d.sizer = elt(\"div\", [d.mover], \"CodeMirror-sizer\");\n  d.sizerWidth = null;\n  // Behavior of elts with overflow: auto and padding is\n  // inconsistent across browsers. This is used to ensure the\n  // scrollable area is big enough.\n  d.heightForcer = elt(\"div\", null, null, \"position: absolute; height: \" + scrollerGap + \"px; width: 1px;\");\n  // Will contain the gutters, if any.\n  d.gutters = elt(\"div\", null, \"CodeMirror-gutters\");\n  d.lineGutter = null;\n  // Actual scrollable element.\n  d.scroller = elt(\"div\", [d.sizer, d.heightForcer, d.gutters], \"CodeMirror-scroll\");\n  d.scroller.setAttribute(\"tabIndex\", \"-1\");\n  // The element in which the editor lives.\n  d.wrapper = elt(\"div\", [d.scrollbarFiller, d.gutterFiller, d.scroller], \"CodeMirror\");\n\n  // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)\n  if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }\n  if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true; }\n\n  if (place) {\n    if (place.appendChild) { place.appendChild(d.wrapper); }\n    else { place(d.wrapper); }\n  }\n\n  // Current rendered range (may be bigger than the view window).\n  d.viewFrom = d.viewTo = doc.first;\n  d.reportedViewFrom = d.reportedViewTo = doc.first;\n  // Information about the rendered lines.\n  d.view = [];\n  d.renderedView = null;\n  // Holds info about a single rendered line when it was rendered\n  // for measurement, while not in view.\n  d.externalMeasured = null;\n  // Empty space (in pixels) above the view\n  d.viewOffset = 0;\n  d.lastWrapHeight = d.lastWrapWidth = 0;\n  d.updateLineNumbers = null;\n\n  d.nativeBarWidth = d.barHeight = d.barWidth = 0;\n  d.scrollbarsClipped = false;\n\n  // Used to only resize the line number gutter when necessary (when\n  // the amount of lines crosses a boundary that makes its width change)\n  d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;\n  // Set to true when a non-horizontal-scrolling line widget is\n  // added. As an optimization, line widget aligning is skipped when\n  // this is false.\n  d.alignWidgets = false;\n\n  d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;\n\n  // Tracks the maximum line length so that the horizontal scrollbar\n  // can be kept static when scrolling.\n  d.maxLine = null;\n  d.maxLineLength = 0;\n  d.maxLineChanged = false;\n\n  // Used for measuring wheel scrolling granularity\n  d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;\n\n  // True when shift is held down.\n  d.shift = false;\n\n  // Used to track whether anything happened since the context menu\n  // was opened.\n  d.selForContextMenu = null;\n\n  d.activeTouch = null;\n\n  input.init(d);\n}\n\n// Find the line object corresponding to the given line number.\nfunction getLine(doc, n) {\n  n -= doc.first;\n  if (n < 0 || n >= doc.size) { throw new Error(\"There is no line \" + (n + doc.first) + \" in the document.\") }\n  var chunk = doc;\n  while (!chunk.lines) {\n    for (var i = 0;; ++i) {\n      var child = chunk.children[i], sz = child.chunkSize();\n      if (n < sz) { chunk = child; break }\n      n -= sz;\n    }\n  }\n  return chunk.lines[n]\n}\n\n// Get the part of a document between two positions, as an array of\n// strings.\nfunction getBetween(doc, start, end) {\n  var out = [], n = start.line;\n  doc.iter(start.line, end.line + 1, function (line) {\n    var text = line.text;\n    if (n == end.line) { text = text.slice(0, end.ch); }\n    if (n == start.line) { text = text.slice(start.ch); }\n    out.push(text);\n    ++n;\n  });\n  return out\n}\n// Get the lines between from and to, as array of strings.\nfunction getLines(doc, from, to) {\n  var out = [];\n  doc.iter(from, to, function (line) { out.push(line.text); }); // iter aborts when callback returns truthy value\n  return out\n}\n\n// Update the height of a line, propagating the height change\n// upwards to parent nodes.\nfunction updateLineHeight(line, height) {\n  var diff = height - line.height;\n  if (diff) { for (var n = line; n; n = n.parent) { n.height += diff; } }\n}\n\n// Given a line object, find its line number by walking up through\n// its parent links.\nfunction lineNo(line) {\n  if (line.parent == null) { return null }\n  var cur = line.parent, no = indexOf(cur.lines, line);\n  for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {\n    for (var i = 0;; ++i) {\n      if (chunk.children[i] == cur) { break }\n      no += chunk.children[i].chunkSize();\n    }\n  }\n  return no + cur.first\n}\n\n// Find the line at the given vertical position, using the height\n// information in the document tree.\nfunction lineAtHeight(chunk, h) {\n  var n = chunk.first;\n  outer: do {\n    for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) {\n      var child = chunk.children[i$1], ch = child.height;\n      if (h < ch) { chunk = child; continue outer }\n      h -= ch;\n      n += child.chunkSize();\n    }\n    return n\n  } while (!chunk.lines)\n  var i = 0;\n  for (; i < chunk.lines.length; ++i) {\n    var line = chunk.lines[i], lh = line.height;\n    if (h < lh) { break }\n    h -= lh;\n  }\n  return n + i\n}\n\nfunction isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}\n\nfunction lineNumberFor(options, i) {\n  return String(options.lineNumberFormatter(i + options.firstLineNumber))\n}\n\n// A Pos instance represents a position within the text.\nfunction Pos(line, ch, sticky) {\n  if ( sticky === void 0 ) sticky = null;\n\n  if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) }\n  this.line = line;\n  this.ch = ch;\n  this.sticky = sticky;\n}\n\n// Compare two positions, return 0 if they are the same, a negative\n// number when a is less, and a positive number otherwise.\nfunction cmp(a, b) { return a.line - b.line || a.ch - b.ch }\n\nfunction equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 }\n\nfunction copyPos(x) {return Pos(x.line, x.ch)}\nfunction maxPos(a, b) { return cmp(a, b) < 0 ? b : a }\nfunction minPos(a, b) { return cmp(a, b) < 0 ? a : b }\n\n// Most of the external API clips given positions to make sure they\n// actually exist within the document.\nfunction clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))}\nfunction clipPos(doc, pos) {\n  if (pos.line < doc.first) { return Pos(doc.first, 0) }\n  var last = doc.first + doc.size - 1;\n  if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) }\n  return clipToLen(pos, getLine(doc, pos.line).text.length)\n}\nfunction clipToLen(pos, linelen) {\n  var ch = pos.ch;\n  if (ch == null || ch > linelen) { return Pos(pos.line, linelen) }\n  else if (ch < 0) { return Pos(pos.line, 0) }\n  else { return pos }\n}\nfunction clipPosArray(doc, array) {\n  var out = [];\n  for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]); }\n  return out\n}\n\n// Optimize some code when these features are not used.\nvar sawReadOnlySpans = false;\nvar sawCollapsedSpans = false;\n\nfunction seeReadOnlySpans() {\n  sawReadOnlySpans = true;\n}\n\nfunction seeCollapsedSpans() {\n  sawCollapsedSpans = true;\n}\n\n// TEXTMARKER SPANS\n\nfunction MarkedSpan(marker, from, to) {\n  this.marker = marker;\n  this.from = from; this.to = to;\n}\n\n// Search an array of spans for a span matching the given marker.\nfunction getMarkedSpanFor(spans, marker) {\n  if (spans) { for (var i = 0; i < spans.length; ++i) {\n    var span = spans[i];\n    if (span.marker == marker) { return span }\n  } }\n}\n// Remove a span from an array, returning undefined if no spans are\n// left (we don't store arrays for lines without spans).\nfunction removeMarkedSpan(spans, span) {\n  var r;\n  for (var i = 0; i < spans.length; ++i)\n    { if (spans[i] != span) { (r || (r = [])).push(spans[i]); } }\n  return r\n}\n// Add a span to a line.\nfunction addMarkedSpan(line, span) {\n  line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];\n  span.marker.attachLine(line);\n}\n\n// Used for the algorithm that adjusts markers for a change in the\n// document. These functions cut an array of spans at a given\n// character position, returning an array of remaining chunks (or\n// undefined if nothing remains).\nfunction markedSpansBefore(old, startCh, isInsert) {\n  var nw;\n  if (old) { for (var i = 0; i < old.length; ++i) {\n    var span = old[i], marker = span.marker;\n    var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);\n    if (startsBefore || span.from == startCh && marker.type == \"bookmark\" && (!isInsert || !span.marker.insertLeft)) {\n      var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));\n    }\n  } }\n  return nw\n}\nfunction markedSpansAfter(old, endCh, isInsert) {\n  var nw;\n  if (old) { for (var i = 0; i < old.length; ++i) {\n    var span = old[i], marker = span.marker;\n    var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);\n    if (endsAfter || span.from == endCh && marker.type == \"bookmark\" && (!isInsert || span.marker.insertLeft)) {\n      var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,\n                                            span.to == null ? null : span.to - endCh));\n    }\n  } }\n  return nw\n}\n\n// Given a change object, compute the new set of marker spans that\n// cover the line in which the change took place. Removes spans\n// entirely within the change, reconnects spans belonging to the\n// same marker that appear on both sides of the change, and cuts off\n// spans partially within the change. Returns an array of span\n// arrays with one element for each line in (after) the change.\nfunction stretchSpansOverChange(doc, change) {\n  if (change.full) { return null }\n  var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;\n  var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;\n  if (!oldFirst && !oldLast) { return null }\n\n  var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;\n  // Get the spans that 'stick out' on both sides\n  var first = markedSpansBefore(oldFirst, startCh, isInsert);\n  var last = markedSpansAfter(oldLast, endCh, isInsert);\n\n  // Next, merge those two ends\n  var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);\n  if (first) {\n    // Fix up .to properties of first\n    for (var i = 0; i < first.length; ++i) {\n      var span = first[i];\n      if (span.to == null) {\n        var found = getMarkedSpanFor(last, span.marker);\n        if (!found) { span.to = startCh; }\n        else if (sameLine) { span.to = found.to == null ? null : found.to + offset; }\n      }\n    }\n  }\n  if (last) {\n    // Fix up .from in last (or move them into first in case of sameLine)\n    for (var i$1 = 0; i$1 < last.length; ++i$1) {\n      var span$1 = last[i$1];\n      if (span$1.to != null) { span$1.to += offset; }\n      if (span$1.from == null) {\n        var found$1 = getMarkedSpanFor(first, span$1.marker);\n        if (!found$1) {\n          span$1.from = offset;\n          if (sameLine) { (first || (first = [])).push(span$1); }\n        }\n      } else {\n        span$1.from += offset;\n        if (sameLine) { (first || (first = [])).push(span$1); }\n      }\n    }\n  }\n  // Make sure we didn't create any zero-length spans\n  if (first) { first = clearEmptySpans(first); }\n  if (last && last != first) { last = clearEmptySpans(last); }\n\n  var newMarkers = [first];\n  if (!sameLine) {\n    // Fill gap with whole-line-spans\n    var gap = change.text.length - 2, gapMarkers;\n    if (gap > 0 && first)\n      { for (var i$2 = 0; i$2 < first.length; ++i$2)\n        { if (first[i$2].to == null)\n          { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)); } } }\n    for (var i$3 = 0; i$3 < gap; ++i$3)\n      { newMarkers.push(gapMarkers); }\n    newMarkers.push(last);\n  }\n  return newMarkers\n}\n\n// Remove spans that are empty and don't have a clearWhenEmpty\n// option of false.\nfunction clearEmptySpans(spans) {\n  for (var i = 0; i < spans.length; ++i) {\n    var span = spans[i];\n    if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)\n      { spans.splice(i--, 1); }\n  }\n  if (!spans.length) { return null }\n  return spans\n}\n\n// Used to 'clip' out readOnly ranges when making a change.\nfunction removeReadOnlyRanges(doc, from, to) {\n  var markers = null;\n  doc.iter(from.line, to.line + 1, function (line) {\n    if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {\n      var mark = line.markedSpans[i].marker;\n      if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))\n        { (markers || (markers = [])).push(mark); }\n    } }\n  });\n  if (!markers) { return null }\n  var parts = [{from: from, to: to}];\n  for (var i = 0; i < markers.length; ++i) {\n    var mk = markers[i], m = mk.find(0);\n    for (var j = 0; j < parts.length; ++j) {\n      var p = parts[j];\n      if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue }\n      var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);\n      if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)\n        { newParts.push({from: p.from, to: m.from}); }\n      if (dto > 0 || !mk.inclusiveRight && !dto)\n        { newParts.push({from: m.to, to: p.to}); }\n      parts.splice.apply(parts, newParts);\n      j += newParts.length - 3;\n    }\n  }\n  return parts\n}\n\n// Connect or disconnect spans from a line.\nfunction detachMarkedSpans(line) {\n  var spans = line.markedSpans;\n  if (!spans) { return }\n  for (var i = 0; i < spans.length; ++i)\n    { spans[i].marker.detachLine(line); }\n  line.markedSpans = null;\n}\nfunction attachMarkedSpans(line, spans) {\n  if (!spans) { return }\n  for (var i = 0; i < spans.length; ++i)\n    { spans[i].marker.attachLine(line); }\n  line.markedSpans = spans;\n}\n\n// Helpers used when computing which overlapping collapsed span\n// counts as the larger one.\nfunction extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }\nfunction extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }\n\n// Returns a number indicating which of two overlapping collapsed\n// spans is larger (and thus includes the other). Falls back to\n// comparing ids when the spans cover exactly the same range.\nfunction compareCollapsedMarkers(a, b) {\n  var lenDiff = a.lines.length - b.lines.length;\n  if (lenDiff != 0) { return lenDiff }\n  var aPos = a.find(), bPos = b.find();\n  var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);\n  if (fromCmp) { return -fromCmp }\n  var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);\n  if (toCmp) { return toCmp }\n  return b.id - a.id\n}\n\n// Find out whether a line ends or starts in a collapsed span. If\n// so, return the marker for that span.\nfunction collapsedSpanAtSide(line, start) {\n  var sps = sawCollapsedSpans && line.markedSpans, found;\n  if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {\n    sp = sps[i];\n    if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&\n        (!found || compareCollapsedMarkers(found, sp.marker) < 0))\n      { found = sp.marker; }\n  } }\n  return found\n}\nfunction collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) }\nfunction collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) }\n\n// Test whether there exists a collapsed span that partially\n// overlaps (covers the start or end, but not both) of a new span.\n// Such overlap is not allowed.\nfunction conflictingCollapsedRange(doc, lineNo$$1, from, to, marker) {\n  var line = getLine(doc, lineNo$$1);\n  var sps = sawCollapsedSpans && line.markedSpans;\n  if (sps) { for (var i = 0; i < sps.length; ++i) {\n    var sp = sps[i];\n    if (!sp.marker.collapsed) { continue }\n    var found = sp.marker.find(0);\n    var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);\n    var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);\n    if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue }\n    if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||\n        fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0))\n      { return true }\n  } }\n}\n\n// A visual line is a line as drawn on the screen. Folding, for\n// example, can cause multiple logical lines to appear on the same\n// visual line. This finds the start of the visual line that the\n// given line is part of (usually that is the line itself).\nfunction visualLine(line) {\n  var merged;\n  while (merged = collapsedSpanAtStart(line))\n    { line = merged.find(-1, true).line; }\n  return line\n}\n\nfunction visualLineEnd(line) {\n  var merged;\n  while (merged = collapsedSpanAtEnd(line))\n    { line = merged.find(1, true).line; }\n  return line\n}\n\n// Returns an array of logical lines that continue the visual line\n// started by the argument, or undefined if there are no such lines.\nfunction visualLineContinued(line) {\n  var merged, lines;\n  while (merged = collapsedSpanAtEnd(line)) {\n    line = merged.find(1, true).line\n    ;(lines || (lines = [])).push(line);\n  }\n  return lines\n}\n\n// Get the line number of the start of the visual line that the\n// given line number is part of.\nfunction visualLineNo(doc, lineN) {\n  var line = getLine(doc, lineN), vis = visualLine(line);\n  if (line == vis) { return lineN }\n  return lineNo(vis)\n}\n\n// Get the line number of the start of the next visual line after\n// the given line.\nfunction visualLineEndNo(doc, lineN) {\n  if (lineN > doc.lastLine()) { return lineN }\n  var line = getLine(doc, lineN), merged;\n  if (!lineIsHidden(doc, line)) { return lineN }\n  while (merged = collapsedSpanAtEnd(line))\n    { line = merged.find(1, true).line; }\n  return lineNo(line) + 1\n}\n\n// Compute whether a line is hidden. Lines count as hidden when they\n// are part of a visual line that starts with another line, or when\n// they are entirely covered by collapsed, non-widget span.\nfunction lineIsHidden(doc, line) {\n  var sps = sawCollapsedSpans && line.markedSpans;\n  if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {\n    sp = sps[i];\n    if (!sp.marker.collapsed) { continue }\n    if (sp.from == null) { return true }\n    if (sp.marker.widgetNode) { continue }\n    if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))\n      { return true }\n  } }\n}\nfunction lineIsHiddenInner(doc, line, span) {\n  if (span.to == null) {\n    var end = span.marker.find(1, true);\n    return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker))\n  }\n  if (span.marker.inclusiveRight && span.to == line.text.length)\n    { return true }\n  for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) {\n    sp = line.markedSpans[i];\n    if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&\n        (sp.to == null || sp.to != span.from) &&\n        (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&\n        lineIsHiddenInner(doc, line, sp)) { return true }\n  }\n}\n\n// Find the height above the given line.\nfunction heightAtLine(lineObj) {\n  lineObj = visualLine(lineObj);\n\n  var h = 0, chunk = lineObj.parent;\n  for (var i = 0; i < chunk.lines.length; ++i) {\n    var line = chunk.lines[i];\n    if (line == lineObj) { break }\n    else { h += line.height; }\n  }\n  for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {\n    for (var i$1 = 0; i$1 < p.children.length; ++i$1) {\n      var cur = p.children[i$1];\n      if (cur == chunk) { break }\n      else { h += cur.height; }\n    }\n  }\n  return h\n}\n\n// Compute the character length of a line, taking into account\n// collapsed ranges (see markText) that might hide parts, and join\n// other lines onto it.\nfunction lineLength(line) {\n  if (line.height == 0) { return 0 }\n  var len = line.text.length, merged, cur = line;\n  while (merged = collapsedSpanAtStart(cur)) {\n    var found = merged.find(0, true);\n    cur = found.from.line;\n    len += found.from.ch - found.to.ch;\n  }\n  cur = line;\n  while (merged = collapsedSpanAtEnd(cur)) {\n    var found$1 = merged.find(0, true);\n    len -= cur.text.length - found$1.from.ch;\n    cur = found$1.to.line;\n    len += cur.text.length - found$1.to.ch;\n  }\n  return len\n}\n\n// Find the longest line in the document.\nfunction findMaxLine(cm) {\n  var d = cm.display, doc = cm.doc;\n  d.maxLine = getLine(doc, doc.first);\n  d.maxLineLength = lineLength(d.maxLine);\n  d.maxLineChanged = true;\n  doc.iter(function (line) {\n    var len = lineLength(line);\n    if (len > d.maxLineLength) {\n      d.maxLineLength = len;\n      d.maxLine = line;\n    }\n  });\n}\n\n// BIDI HELPERS\n\nfunction iterateBidiSections(order, from, to, f) {\n  if (!order) { return f(from, to, \"ltr\") }\n  var found = false;\n  for (var i = 0; i < order.length; ++i) {\n    var part = order[i];\n    if (part.from < to && part.to > from || from == to && part.to == from) {\n      f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? \"rtl\" : \"ltr\");\n      found = true;\n    }\n  }\n  if (!found) { f(from, to, \"ltr\"); }\n}\n\nvar bidiOther = null;\nfunction getBidiPartAt(order, ch, sticky) {\n  var found;\n  bidiOther = null;\n  for (var i = 0; i < order.length; ++i) {\n    var cur = order[i];\n    if (cur.from < ch && cur.to > ch) { return i }\n    if (cur.to == ch) {\n      if (cur.from != cur.to && sticky == \"before\") { found = i; }\n      else { bidiOther = i; }\n    }\n    if (cur.from == ch) {\n      if (cur.from != cur.to && sticky != \"before\") { found = i; }\n      else { bidiOther = i; }\n    }\n  }\n  return found != null ? found : bidiOther\n}\n\n// Bidirectional ordering algorithm\n// See http://unicode.org/reports/tr9/tr9-13.html for the algorithm\n// that this (partially) implements.\n\n// One-char codes used for character types:\n// L (L):   Left-to-Right\n// R (R):   Right-to-Left\n// r (AL):  Right-to-Left Arabic\n// 1 (EN):  European Number\n// + (ES):  European Number Separator\n// % (ET):  European Number Terminator\n// n (AN):  Arabic Number\n// , (CS):  Common Number Separator\n// m (NSM): Non-Spacing Mark\n// b (BN):  Boundary Neutral\n// s (B):   Paragraph Separator\n// t (S):   Segment Separator\n// w (WS):  Whitespace\n// N (ON):  Other Neutrals\n\n// Returns null if characters are ordered as they appear\n// (left-to-right), or an array of sections ({from, to, level}\n// objects) in the order in which they occur visually.\nvar bidiOrdering = (function() {\n  // Character types for codepoints 0 to 0xff\n  var lowTypes = \"bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN\";\n  // Character types for codepoints 0x600 to 0x6f9\n  var arabicTypes = \"nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111\";\n  function charType(code) {\n    if (code <= 0xf7) { return lowTypes.charAt(code) }\n    else if (0x590 <= code && code <= 0x5f4) { return \"R\" }\n    else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) }\n    else if (0x6ee <= code && code <= 0x8ac) { return \"r\" }\n    else if (0x2000 <= code && code <= 0x200b) { return \"w\" }\n    else if (code == 0x200c) { return \"b\" }\n    else { return \"L\" }\n  }\n\n  var bidiRE = /[\\u0590-\\u05f4\\u0600-\\u06ff\\u0700-\\u08ac]/;\n  var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;\n\n  function BidiSpan(level, from, to) {\n    this.level = level;\n    this.from = from; this.to = to;\n  }\n\n  return function(str, direction) {\n    var outerType = direction == \"ltr\" ? \"L\" : \"R\";\n\n    if (str.length == 0 || direction == \"ltr\" && !bidiRE.test(str)) { return false }\n    var len = str.length, types = [];\n    for (var i = 0; i < len; ++i)\n      { types.push(charType(str.charCodeAt(i))); }\n\n    // W1. Examine each non-spacing mark (NSM) in the level run, and\n    // change the type of the NSM to the type of the previous\n    // character. If the NSM is at the start of the level run, it will\n    // get the type of sor.\n    for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) {\n      var type = types[i$1];\n      if (type == \"m\") { types[i$1] = prev; }\n      else { prev = type; }\n    }\n\n    // W2. Search backwards from each instance of a European number\n    // until the first strong type (R, L, AL, or sor) is found. If an\n    // AL is found, change the type of the European number to Arabic\n    // number.\n    // W3. Change all ALs to R.\n    for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) {\n      var type$1 = types[i$2];\n      if (type$1 == \"1\" && cur == \"r\") { types[i$2] = \"n\"; }\n      else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == \"r\") { types[i$2] = \"R\"; } }\n    }\n\n    // W4. A single European separator between two European numbers\n    // changes to a European number. A single common separator between\n    // two numbers of the same type changes to that type.\n    for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) {\n      var type$2 = types[i$3];\n      if (type$2 == \"+\" && prev$1 == \"1\" && types[i$3+1] == \"1\") { types[i$3] = \"1\"; }\n      else if (type$2 == \",\" && prev$1 == types[i$3+1] &&\n               (prev$1 == \"1\" || prev$1 == \"n\")) { types[i$3] = prev$1; }\n      prev$1 = type$2;\n    }\n\n    // W5. A sequence of European terminators adjacent to European\n    // numbers changes to all European numbers.\n    // W6. Otherwise, separators and terminators change to Other\n    // Neutral.\n    for (var i$4 = 0; i$4 < len; ++i$4) {\n      var type$3 = types[i$4];\n      if (type$3 == \",\") { types[i$4] = \"N\"; }\n      else if (type$3 == \"%\") {\n        var end = (void 0);\n        for (end = i$4 + 1; end < len && types[end] == \"%\"; ++end) {}\n        var replace = (i$4 && types[i$4-1] == \"!\") || (end < len && types[end] == \"1\") ? \"1\" : \"N\";\n        for (var j = i$4; j < end; ++j) { types[j] = replace; }\n        i$4 = end - 1;\n      }\n    }\n\n    // W7. Search backwards from each instance of a European number\n    // until the first strong type (R, L, or sor) is found. If an L is\n    // found, then change the type of the European number to L.\n    for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) {\n      var type$4 = types[i$5];\n      if (cur$1 == \"L\" && type$4 == \"1\") { types[i$5] = \"L\"; }\n      else if (isStrong.test(type$4)) { cur$1 = type$4; }\n    }\n\n    // N1. A sequence of neutrals takes the direction of the\n    // surrounding strong text if the text on both sides has the same\n    // direction. European and Arabic numbers act as if they were R in\n    // terms of their influence on neutrals. Start-of-level-run (sor)\n    // and end-of-level-run (eor) are used at level run boundaries.\n    // N2. Any remaining neutrals take the embedding direction.\n    for (var i$6 = 0; i$6 < len; ++i$6) {\n      if (isNeutral.test(types[i$6])) {\n        var end$1 = (void 0);\n        for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {}\n        var before = (i$6 ? types[i$6-1] : outerType) == \"L\";\n        var after = (end$1 < len ? types[end$1] : outerType) == \"L\";\n        var replace$1 = before == after ? (before ? \"L\" : \"R\") : outerType;\n        for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1; }\n        i$6 = end$1 - 1;\n      }\n    }\n\n    // Here we depart from the documented algorithm, in order to avoid\n    // building up an actual levels array. Since there are only three\n    // levels (0, 1, 2) in an implementation that doesn't take\n    // explicit embedding into account, we can build up the order on\n    // the fly, without following the level-based algorithm.\n    var order = [], m;\n    for (var i$7 = 0; i$7 < len;) {\n      if (countsAsLeft.test(types[i$7])) {\n        var start = i$7;\n        for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}\n        order.push(new BidiSpan(0, start, i$7));\n      } else {\n        var pos = i$7, at = order.length;\n        for (++i$7; i$7 < len && types[i$7] != \"L\"; ++i$7) {}\n        for (var j$2 = pos; j$2 < i$7;) {\n          if (countsAsNum.test(types[j$2])) {\n            if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); }\n            var nstart = j$2;\n            for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}\n            order.splice(at, 0, new BidiSpan(2, nstart, j$2));\n            pos = j$2;\n          } else { ++j$2; }\n        }\n        if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)); }\n      }\n    }\n    if (order[0].level == 1 && (m = str.match(/^\\s+/))) {\n      order[0].from = m[0].length;\n      order.unshift(new BidiSpan(0, 0, m[0].length));\n    }\n    if (lst(order).level == 1 && (m = str.match(/\\s+$/))) {\n      lst(order).to -= m[0].length;\n      order.push(new BidiSpan(0, len - m[0].length, len));\n    }\n\n    return direction == \"rtl\" ? order.reverse() : order\n  }\n})();\n\n// Get the bidi ordering for the given line (and cache it). Returns\n// false for lines that are fully left-to-right, and an array of\n// BidiSpan objects otherwise.\nfunction getOrder(line, direction) {\n  var order = line.order;\n  if (order == null) { order = line.order = bidiOrdering(line.text, direction); }\n  return order\n}\n\nfunction moveCharLogically(line, ch, dir) {\n  var target = skipExtendingChars(line.text, ch + dir, dir);\n  return target < 0 || target > line.text.length ? null : target\n}\n\nfunction moveLogically(line, start, dir) {\n  var ch = moveCharLogically(line, start.ch, dir);\n  return ch == null ? null : new Pos(start.line, ch, dir < 0 ? \"after\" : \"before\")\n}\n\nfunction endOfLine(visually, cm, lineObj, lineNo, dir) {\n  if (visually) {\n    var order = getOrder(lineObj, cm.doc.direction);\n    if (order) {\n      var part = dir < 0 ? lst(order) : order[0];\n      var moveInStorageOrder = (dir < 0) == (part.level == 1);\n      var sticky = moveInStorageOrder ? \"after\" : \"before\";\n      var ch;\n      // With a wrapped rtl chunk (possibly spanning multiple bidi parts),\n      // it could be that the last bidi part is not on the last visual line,\n      // since visual lines contain content order-consecutive chunks.\n      // Thus, in rtl, we are looking for the first (content-order) character\n      // in the rtl chunk that is on the last line (that is, the same line\n      // as the last (content-order) character).\n      if (part.level > 0) {\n        var prep = prepareMeasureForLine(cm, lineObj);\n        ch = dir < 0 ? lineObj.text.length - 1 : 0;\n        var targetTop = measureCharPrepared(cm, prep, ch).top;\n        ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch);\n        if (sticky == \"before\") { ch = moveCharLogically(lineObj, ch, 1); }\n      } else { ch = dir < 0 ? part.to : part.from; }\n      return new Pos(lineNo, ch, sticky)\n    }\n  }\n  return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? \"before\" : \"after\")\n}\n\nfunction moveVisually(cm, line, start, dir) {\n  var bidi = getOrder(line, cm.doc.direction);\n  if (!bidi) { return moveLogically(line, start, dir) }\n  if (start.ch >= line.text.length) {\n    start.ch = line.text.length;\n    start.sticky = \"before\";\n  } else if (start.ch <= 0) {\n    start.ch = 0;\n    start.sticky = \"after\";\n  }\n  var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos];\n  if (cm.doc.direction == \"ltr\" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {\n    // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,\n    // nothing interesting happens.\n    return moveLogically(line, start, dir)\n  }\n\n  var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); };\n  var prep;\n  var getWrappedLineExtent = function (ch) {\n    if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }\n    prep = prep || prepareMeasureForLine(cm, line);\n    return wrappedLineExtentChar(cm, line, prep, ch)\n  };\n  var wrappedLineExtent = getWrappedLineExtent(start.sticky == \"before\" ? mv(start, -1) : start.ch);\n\n  if (cm.doc.direction == \"rtl\" || part.level == 1) {\n    var moveInStorageOrder = (part.level == 1) == (dir < 0);\n    var ch = mv(start, moveInStorageOrder ? 1 : -1);\n    if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {\n      // Case 2: We move within an rtl part or in an rtl editor on the same visual line\n      var sticky = moveInStorageOrder ? \"before\" : \"after\";\n      return new Pos(start.line, ch, sticky)\n    }\n  }\n\n  // Case 3: Could not move within this bidi part in this visual line, so leave\n  // the current bidi part\n\n  var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {\n    var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder\n      ? new Pos(start.line, mv(ch, 1), \"before\")\n      : new Pos(start.line, ch, \"after\"); };\n\n    for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {\n      var part = bidi[partPos];\n      var moveInStorageOrder = (dir > 0) == (part.level != 1);\n      var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1);\n      if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }\n      ch = moveInStorageOrder ? part.from : mv(part.to, -1);\n      if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }\n    }\n  };\n\n  // Case 3a: Look for other bidi parts on the same visual line\n  var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent);\n  if (res) { return res }\n\n  // Case 3b: Look for other bidi parts on the next visual line\n  var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1);\n  if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {\n    res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh));\n    if (res) { return res }\n  }\n\n  // Case 4: Nowhere to move\n  return null\n}\n\n// EVENT HANDLING\n\n// Lightweight event framework. on/off also work on DOM nodes,\n// registering native DOM handlers.\n\nvar noHandlers = [];\n\nvar on = function(emitter, type, f) {\n  if (emitter.addEventListener) {\n    emitter.addEventListener(type, f, false);\n  } else if (emitter.attachEvent) {\n    emitter.attachEvent(\"on\" + type, f);\n  } else {\n    var map$$1 = emitter._handlers || (emitter._handlers = {});\n    map$$1[type] = (map$$1[type] || noHandlers).concat(f);\n  }\n};\n\nfunction getHandlers(emitter, type) {\n  return emitter._handlers && emitter._handlers[type] || noHandlers\n}\n\nfunction off(emitter, type, f) {\n  if (emitter.removeEventListener) {\n    emitter.removeEventListener(type, f, false);\n  } else if (emitter.detachEvent) {\n    emitter.detachEvent(\"on\" + type, f);\n  } else {\n    var map$$1 = emitter._handlers, arr = map$$1 && map$$1[type];\n    if (arr) {\n      var index = indexOf(arr, f);\n      if (index > -1)\n        { map$$1[type] = arr.slice(0, index).concat(arr.slice(index + 1)); }\n    }\n  }\n}\n\nfunction signal(emitter, type /*, values...*/) {\n  var handlers = getHandlers(emitter, type);\n  if (!handlers.length) { return }\n  var args = Array.prototype.slice.call(arguments, 2);\n  for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args); }\n}\n\n// The DOM events that CodeMirror handles can be overridden by\n// registering a (non-DOM) handler on the editor for the event name,\n// and preventDefault-ing the event in that handler.\nfunction signalDOMEvent(cm, e, override) {\n  if (typeof e == \"string\")\n    { e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; }\n  signal(cm, override || e.type, cm, e);\n  return e_defaultPrevented(e) || e.codemirrorIgnore\n}\n\nfunction signalCursorActivity(cm) {\n  var arr = cm._handlers && cm._handlers.cursorActivity;\n  if (!arr) { return }\n  var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);\n  for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1)\n    { set.push(arr[i]); } }\n}\n\nfunction hasHandler(emitter, type) {\n  return getHandlers(emitter, type).length > 0\n}\n\n// Add on and off methods to a constructor's prototype, to make\n// registering events on such objects more convenient.\nfunction eventMixin(ctor) {\n  ctor.prototype.on = function(type, f) {on(this, type, f);};\n  ctor.prototype.off = function(type, f) {off(this, type, f);};\n}\n\n// Due to the fact that we still support jurassic IE versions, some\n// compatibility wrappers are needed.\n\nfunction e_preventDefault(e) {\n  if (e.preventDefault) { e.preventDefault(); }\n  else { e.returnValue = false; }\n}\nfunction e_stopPropagation(e) {\n  if (e.stopPropagation) { e.stopPropagation(); }\n  else { e.cancelBubble = true; }\n}\nfunction e_defaultPrevented(e) {\n  return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false\n}\nfunction e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}\n\nfunction e_target(e) {return e.target || e.srcElement}\nfunction e_button(e) {\n  var b = e.which;\n  if (b == null) {\n    if (e.button & 1) { b = 1; }\n    else if (e.button & 2) { b = 3; }\n    else if (e.button & 4) { b = 2; }\n  }\n  if (mac && e.ctrlKey && b == 1) { b = 3; }\n  return b\n}\n\n// Detect drag-and-drop\nvar dragAndDrop = function() {\n  // There is *some* kind of drag-and-drop support in IE6-8, but I\n  // couldn't get it to work yet.\n  if (ie && ie_version < 9) { return false }\n  var div = elt('div');\n  return \"draggable\" in div || \"dragDrop\" in div\n}();\n\nvar zwspSupported;\nfunction zeroWidthElement(measure) {\n  if (zwspSupported == null) {\n    var test = elt(\"span\", \"\\u200b\");\n    removeChildrenAndAdd(measure, elt(\"span\", [test, document.createTextNode(\"x\")]));\n    if (measure.firstChild.offsetHeight != 0)\n      { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); }\n  }\n  var node = zwspSupported ? elt(\"span\", \"\\u200b\") :\n    elt(\"span\", \"\\u00a0\", null, \"display: inline-block; width: 1px; margin-right: -1px\");\n  node.setAttribute(\"cm-text\", \"\");\n  return node\n}\n\n// Feature-detect IE's crummy client rect reporting for bidi text\nvar badBidiRects;\nfunction hasBadBidiRects(measure) {\n  if (badBidiRects != null) { return badBidiRects }\n  var txt = removeChildrenAndAdd(measure, document.createTextNode(\"A\\u062eA\"));\n  var r0 = range(txt, 0, 1).getBoundingClientRect();\n  var r1 = range(txt, 1, 2).getBoundingClientRect();\n  removeChildren(measure);\n  if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780)\n  return badBidiRects = (r1.right - r0.right < 3)\n}\n\n// See if \"\".split is the broken IE version, if so, provide an\n// alternative way to split lines.\nvar splitLinesAuto = \"\\n\\nb\".split(/\\n/).length != 3 ? function (string) {\n  var pos = 0, result = [], l = string.length;\n  while (pos <= l) {\n    var nl = string.indexOf(\"\\n\", pos);\n    if (nl == -1) { nl = string.length; }\n    var line = string.slice(pos, string.charAt(nl - 1) == \"\\r\" ? nl - 1 : nl);\n    var rt = line.indexOf(\"\\r\");\n    if (rt != -1) {\n      result.push(line.slice(0, rt));\n      pos += rt + 1;\n    } else {\n      result.push(line);\n      pos = nl + 1;\n    }\n  }\n  return result\n} : function (string) { return string.split(/\\r\\n?|\\n/); };\n\nvar hasSelection = window.getSelection ? function (te) {\n  try { return te.selectionStart != te.selectionEnd }\n  catch(e) { return false }\n} : function (te) {\n  var range$$1;\n  try {range$$1 = te.ownerDocument.selection.createRange();}\n  catch(e) {}\n  if (!range$$1 || range$$1.parentElement() != te) { return false }\n  return range$$1.compareEndPoints(\"StartToEnd\", range$$1) != 0\n};\n\nvar hasCopyEvent = (function () {\n  var e = elt(\"div\");\n  if (\"oncopy\" in e) { return true }\n  e.setAttribute(\"oncopy\", \"return;\");\n  return typeof e.oncopy == \"function\"\n})();\n\nvar badZoomedRects = null;\nfunction hasBadZoomedRects(measure) {\n  if (badZoomedRects != null) { return badZoomedRects }\n  var node = removeChildrenAndAdd(measure, elt(\"span\", \"x\"));\n  var normal = node.getBoundingClientRect();\n  var fromRange = range(node, 0, 1).getBoundingClientRect();\n  return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1\n}\n\n// Known modes, by name and by MIME\nvar modes = {};\nvar mimeModes = {};\n\n// Extra arguments are stored as the mode's dependencies, which is\n// used by (legacy) mechanisms like loadmode.js to automatically\n// load a mode. (Preferred mechanism is the require/define calls.)\nfunction defineMode(name, mode) {\n  if (arguments.length > 2)\n    { mode.dependencies = Array.prototype.slice.call(arguments, 2); }\n  modes[name] = mode;\n}\n\nfunction defineMIME(mime, spec) {\n  mimeModes[mime] = spec;\n}\n\n// Given a MIME type, a {name, ...options} config object, or a name\n// string, return a mode config object.\nfunction resolveMode(spec) {\n  if (typeof spec == \"string\" && mimeModes.hasOwnProperty(spec)) {\n    spec = mimeModes[spec];\n  } else if (spec && typeof spec.name == \"string\" && mimeModes.hasOwnProperty(spec.name)) {\n    var found = mimeModes[spec.name];\n    if (typeof found == \"string\") { found = {name: found}; }\n    spec = createObj(found, spec);\n    spec.name = found.name;\n  } else if (typeof spec == \"string\" && /^[\\w\\-]+\\/[\\w\\-]+\\+xml$/.test(spec)) {\n    return resolveMode(\"application/xml\")\n  } else if (typeof spec == \"string\" && /^[\\w\\-]+\\/[\\w\\-]+\\+json$/.test(spec)) {\n    return resolveMode(\"application/json\")\n  }\n  if (typeof spec == \"string\") { return {name: spec} }\n  else { return spec || {name: \"null\"} }\n}\n\n// Given a mode spec (anything that resolveMode accepts), find and\n// initialize an actual mode object.\nfunction getMode(options, spec) {\n  spec = resolveMode(spec);\n  var mfactory = modes[spec.name];\n  if (!mfactory) { return getMode(options, \"text/plain\") }\n  var modeObj = mfactory(options, spec);\n  if (modeExtensions.hasOwnProperty(spec.name)) {\n    var exts = modeExtensions[spec.name];\n    for (var prop in exts) {\n      if (!exts.hasOwnProperty(prop)) { continue }\n      if (modeObj.hasOwnProperty(prop)) { modeObj[\"_\" + prop] = modeObj[prop]; }\n      modeObj[prop] = exts[prop];\n    }\n  }\n  modeObj.name = spec.name;\n  if (spec.helperType) { modeObj.helperType = spec.helperType; }\n  if (spec.modeProps) { for (var prop$1 in spec.modeProps)\n    { modeObj[prop$1] = spec.modeProps[prop$1]; } }\n\n  return modeObj\n}\n\n// This can be used to attach properties to mode objects from\n// outside the actual mode definition.\nvar modeExtensions = {};\nfunction extendMode(mode, properties) {\n  var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});\n  copyObj(properties, exts);\n}\n\nfunction copyState(mode, state) {\n  if (state === true) { return state }\n  if (mode.copyState) { return mode.copyState(state) }\n  var nstate = {};\n  for (var n in state) {\n    var val = state[n];\n    if (val instanceof Array) { val = val.concat([]); }\n    nstate[n] = val;\n  }\n  return nstate\n}\n\n// Given a mode and a state (for that mode), find the inner mode and\n// state at the position that the state refers to.\nfunction innerMode(mode, state) {\n  var info;\n  while (mode.innerMode) {\n    info = mode.innerMode(state);\n    if (!info || info.mode == mode) { break }\n    state = info.state;\n    mode = info.mode;\n  }\n  return info || {mode: mode, state: state}\n}\n\nfunction startState(mode, a1, a2) {\n  return mode.startState ? mode.startState(a1, a2) : true\n}\n\n// STRING STREAM\n\n// Fed to the mode parsers, provides helper functions to make\n// parsers more succinct.\n\nvar StringStream = function(string, tabSize, lineOracle) {\n  this.pos = this.start = 0;\n  this.string = string;\n  this.tabSize = tabSize || 8;\n  this.lastColumnPos = this.lastColumnValue = 0;\n  this.lineStart = 0;\n  this.lineOracle = lineOracle;\n};\n\nStringStream.prototype.eol = function () {return this.pos >= this.string.length};\nStringStream.prototype.sol = function () {return this.pos == this.lineStart};\nStringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined};\nStringStream.prototype.next = function () {\n  if (this.pos < this.string.length)\n    { return this.string.charAt(this.pos++) }\n};\nStringStream.prototype.eat = function (match) {\n  var ch = this.string.charAt(this.pos);\n  var ok;\n  if (typeof match == \"string\") { ok = ch == match; }\n  else { ok = ch && (match.test ? match.test(ch) : match(ch)); }\n  if (ok) {++this.pos; return ch}\n};\nStringStream.prototype.eatWhile = function (match) {\n  var start = this.pos;\n  while (this.eat(match)){}\n  return this.pos > start\n};\nStringStream.prototype.eatSpace = function () {\n    var this$1 = this;\n\n  var start = this.pos;\n  while (/[\\s\\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos; }\n  return this.pos > start\n};\nStringStream.prototype.skipToEnd = function () {this.pos = this.string.length;};\nStringStream.prototype.skipTo = function (ch) {\n  var found = this.string.indexOf(ch, this.pos);\n  if (found > -1) {this.pos = found; return true}\n};\nStringStream.prototype.backUp = function (n) {this.pos -= n;};\nStringStream.prototype.column = function () {\n  if (this.lastColumnPos < this.start) {\n    this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);\n    this.lastColumnPos = this.start;\n  }\n  return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)\n};\nStringStream.prototype.indentation = function () {\n  return countColumn(this.string, null, this.tabSize) -\n    (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)\n};\nStringStream.prototype.match = function (pattern, consume, caseInsensitive) {\n  if (typeof pattern == \"string\") {\n    var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; };\n    var substr = this.string.substr(this.pos, pattern.length);\n    if (cased(substr) == cased(pattern)) {\n      if (consume !== false) { this.pos += pattern.length; }\n      return true\n    }\n  } else {\n    var match = this.string.slice(this.pos).match(pattern);\n    if (match && match.index > 0) { return null }\n    if (match && consume !== false) { this.pos += match[0].length; }\n    return match\n  }\n};\nStringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)};\nStringStream.prototype.hideFirstChars = function (n, inner) {\n  this.lineStart += n;\n  try { return inner() }\n  finally { this.lineStart -= n; }\n};\nStringStream.prototype.lookAhead = function (n) {\n  var oracle = this.lineOracle;\n  return oracle && oracle.lookAhead(n)\n};\n\nvar SavedContext = function(state, lookAhead) {\n  this.state = state;\n  this.lookAhead = lookAhead;\n};\n\nvar Context = function(doc, state, line, lookAhead) {\n  this.state = state;\n  this.doc = doc;\n  this.line = line;\n  this.maxLookAhead = lookAhead || 0;\n};\n\nContext.prototype.lookAhead = function (n) {\n  var line = this.doc.getLine(this.line + n);\n  if (line != null && n > this.maxLookAhead) { this.maxLookAhead = n; }\n  return line\n};\n\nContext.prototype.nextLine = function () {\n  this.line++;\n  if (this.maxLookAhead > 0) { this.maxLookAhead--; }\n};\n\nContext.fromSaved = function (doc, saved, line) {\n  if (saved instanceof SavedContext)\n    { return new Context(doc, copyState(doc.mode, saved.state), line, saved.lookAhead) }\n  else\n    { return new Context(doc, copyState(doc.mode, saved), line) }\n};\n\nContext.prototype.save = function (copy) {\n  var state = copy !== false ? copyState(this.doc.mode, this.state) : this.state;\n  return this.maxLookAhead > 0 ? new SavedContext(state, this.maxLookAhead) : state\n};\n\n\n// Compute a style array (an array starting with a mode generation\n// -- for invalidation -- followed by pairs of end positions and\n// style strings), which is used to highlight the tokens on the\n// line.\nfunction highlightLine(cm, line, context, forceToEnd) {\n  // A styles array always starts with a number identifying the\n  // mode/overlays that it is based on (for easy invalidation).\n  var st = [cm.state.modeGen], lineClasses = {};\n  // Compute the base array of styles\n  runMode(cm, line.text, cm.doc.mode, context, function (end, style) { return st.push(end, style); },\n          lineClasses, forceToEnd);\n  var state = context.state;\n\n  // Run overlays, adjust style array.\n  var loop = function ( o ) {\n    var overlay = cm.state.overlays[o], i = 1, at = 0;\n    context.state = true;\n    runMode(cm, line.text, overlay.mode, context, function (end, style) {\n      var start = i;\n      // Ensure there's a token end at the current position, and that i points at it\n      while (at < end) {\n        var i_end = st[i];\n        if (i_end > end)\n          { st.splice(i, 1, end, st[i+1], i_end); }\n        i += 2;\n        at = Math.min(end, i_end);\n      }\n      if (!style) { return }\n      if (overlay.opaque) {\n        st.splice(start, i - start, end, \"overlay \" + style);\n        i = start + 2;\n      } else {\n        for (; start < i; start += 2) {\n          var cur = st[start+1];\n          st[start+1] = (cur ? cur + \" \" : \"\") + \"overlay \" + style;\n        }\n      }\n    }, lineClasses);\n  };\n\n  for (var o = 0; o < cm.state.overlays.length; ++o) loop( o );\n  context.state = state;\n\n  return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}\n}\n\nfunction getLineStyles(cm, line, updateFrontier) {\n  if (!line.styles || line.styles[0] != cm.state.modeGen) {\n    var context = getContextBefore(cm, lineNo(line));\n    var resetState = line.text.length > cm.options.maxHighlightLength && copyState(cm.doc.mode, context.state);\n    var result = highlightLine(cm, line, context);\n    if (resetState) { context.state = resetState; }\n    line.stateAfter = context.save(!resetState);\n    line.styles = result.styles;\n    if (result.classes) { line.styleClasses = result.classes; }\n    else if (line.styleClasses) { line.styleClasses = null; }\n    if (updateFrontier === cm.doc.highlightFrontier)\n      { cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier); }\n  }\n  return line.styles\n}\n\nfunction getContextBefore(cm, n, precise) {\n  var doc = cm.doc, display = cm.display;\n  if (!doc.mode.startState) { return new Context(doc, true, n) }\n  var start = findStartLine(cm, n, precise);\n  var saved = start > doc.first && getLine(doc, start - 1).stateAfter;\n  var context = saved ? Context.fromSaved(doc, saved, start) : new Context(doc, startState(doc.mode), start);\n\n  doc.iter(start, n, function (line) {\n    processLine(cm, line.text, context);\n    var pos = context.line;\n    line.stateAfter = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo ? context.save() : null;\n    context.nextLine();\n  });\n  if (precise) { doc.modeFrontier = context.line; }\n  return context\n}\n\n// Lightweight form of highlight -- proceed over this line and\n// update state, but don't save a style array. Used for lines that\n// aren't currently visible.\nfunction processLine(cm, text, context, startAt) {\n  var mode = cm.doc.mode;\n  var stream = new StringStream(text, cm.options.tabSize, context);\n  stream.start = stream.pos = startAt || 0;\n  if (text == \"\") { callBlankLine(mode, context.state); }\n  while (!stream.eol()) {\n    readToken(mode, stream, context.state);\n    stream.start = stream.pos;\n  }\n}\n\nfunction callBlankLine(mode, state) {\n  if (mode.blankLine) { return mode.blankLine(state) }\n  if (!mode.innerMode) { return }\n  var inner = innerMode(mode, state);\n  if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) }\n}\n\nfunction readToken(mode, stream, state, inner) {\n  for (var i = 0; i < 10; i++) {\n    if (inner) { inner[0] = innerMode(mode, state).mode; }\n    var style = mode.token(stream, state);\n    if (stream.pos > stream.start) { return style }\n  }\n  throw new Error(\"Mode \" + mode.name + \" failed to advance stream.\")\n}\n\nvar Token = function(stream, type, state) {\n  this.start = stream.start; this.end = stream.pos;\n  this.string = stream.current();\n  this.type = type || null;\n  this.state = state;\n};\n\n// Utility for getTokenAt and getLineTokens\nfunction takeToken(cm, pos, precise, asArray) {\n  var doc = cm.doc, mode = doc.mode, style;\n  pos = clipPos(doc, pos);\n  var line = getLine(doc, pos.line), context = getContextBefore(cm, pos.line, precise);\n  var stream = new StringStream(line.text, cm.options.tabSize, context), tokens;\n  if (asArray) { tokens = []; }\n  while ((asArray || stream.pos < pos.ch) && !stream.eol()) {\n    stream.start = stream.pos;\n    style = readToken(mode, stream, context.state);\n    if (asArray) { tokens.push(new Token(stream, style, copyState(doc.mode, context.state))); }\n  }\n  return asArray ? tokens : new Token(stream, style, context.state)\n}\n\nfunction extractLineClasses(type, output) {\n  if (type) { for (;;) {\n    var lineClass = type.match(/(?:^|\\s+)line-(background-)?(\\S+)/);\n    if (!lineClass) { break }\n    type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);\n    var prop = lineClass[1] ? \"bgClass\" : \"textClass\";\n    if (output[prop] == null)\n      { output[prop] = lineClass[2]; }\n    else if (!(new RegExp(\"(?:^|\\s)\" + lineClass[2] + \"(?:$|\\s)\")).test(output[prop]))\n      { output[prop] += \" \" + lineClass[2]; }\n  } }\n  return type\n}\n\n// Run the given mode's parser over a line, calling f for each token.\nfunction runMode(cm, text, mode, context, f, lineClasses, forceToEnd) {\n  var flattenSpans = mode.flattenSpans;\n  if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans; }\n  var curStart = 0, curStyle = null;\n  var stream = new StringStream(text, cm.options.tabSize, context), style;\n  var inner = cm.options.addModeClass && [null];\n  if (text == \"\") { extractLineClasses(callBlankLine(mode, context.state), lineClasses); }\n  while (!stream.eol()) {\n    if (stream.pos > cm.options.maxHighlightLength) {\n      flattenSpans = false;\n      if (forceToEnd) { processLine(cm, text, context, stream.pos); }\n      stream.pos = text.length;\n      style = null;\n    } else {\n      style = extractLineClasses(readToken(mode, stream, context.state, inner), lineClasses);\n    }\n    if (inner) {\n      var mName = inner[0].name;\n      if (mName) { style = \"m-\" + (style ? mName + \" \" + style : mName); }\n    }\n    if (!flattenSpans || curStyle != style) {\n      while (curStart < stream.start) {\n        curStart = Math.min(stream.start, curStart + 5000);\n        f(curStart, curStyle);\n      }\n      curStyle = style;\n    }\n    stream.start = stream.pos;\n  }\n  while (curStart < stream.pos) {\n    // Webkit seems to refuse to render text nodes longer than 57444\n    // characters, and returns inaccurate measurements in nodes\n    // starting around 5000 chars.\n    var pos = Math.min(stream.pos, curStart + 5000);\n    f(pos, curStyle);\n    curStart = pos;\n  }\n}\n\n// Finds the line to start with when starting a parse. Tries to\n// find a line with a stateAfter, so that it can start with a\n// valid state. If that fails, it returns the line with the\n// smallest indentation, which tends to need the least context to\n// parse correctly.\nfunction findStartLine(cm, n, precise) {\n  var minindent, minline, doc = cm.doc;\n  var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);\n  for (var search = n; search > lim; --search) {\n    if (search <= doc.first) { return doc.first }\n    var line = getLine(doc, search - 1), after = line.stateAfter;\n    if (after && (!precise || search + (after instanceof SavedContext ? after.lookAhead : 0) <= doc.modeFrontier))\n      { return search }\n    var indented = countColumn(line.text, null, cm.options.tabSize);\n    if (minline == null || minindent > indented) {\n      minline = search - 1;\n      minindent = indented;\n    }\n  }\n  return minline\n}\n\nfunction retreatFrontier(doc, n) {\n  doc.modeFrontier = Math.min(doc.modeFrontier, n);\n  if (doc.highlightFrontier < n - 10) { return }\n  var start = doc.first;\n  for (var line = n - 1; line > start; line--) {\n    var saved = getLine(doc, line).stateAfter;\n    // change is on 3\n    // state on line 1 looked ahead 2 -- so saw 3\n    // test 1 + 2 < 3 should cover this\n    if (saved && (!(saved instanceof SavedContext) || line + saved.lookAhead < n)) {\n      start = line + 1;\n      break\n    }\n  }\n  doc.highlightFrontier = Math.min(doc.highlightFrontier, start);\n}\n\n// LINE DATA STRUCTURE\n\n// Line objects. These hold state related to a line, including\n// highlighting info (the styles array).\nvar Line = function(text, markedSpans, estimateHeight) {\n  this.text = text;\n  attachMarkedSpans(this, markedSpans);\n  this.height = estimateHeight ? estimateHeight(this) : 1;\n};\n\nLine.prototype.lineNo = function () { return lineNo(this) };\neventMixin(Line);\n\n// Change the content (text, markers) of a line. Automatically\n// invalidates cached information and tries to re-estimate the\n// line's height.\nfunction updateLine(line, text, markedSpans, estimateHeight) {\n  line.text = text;\n  if (line.stateAfter) { line.stateAfter = null; }\n  if (line.styles) { line.styles = null; }\n  if (line.order != null) { line.order = null; }\n  detachMarkedSpans(line);\n  attachMarkedSpans(line, markedSpans);\n  var estHeight = estimateHeight ? estimateHeight(line) : 1;\n  if (estHeight != line.height) { updateLineHeight(line, estHeight); }\n}\n\n// Detach a line from the document tree and its markers.\nfunction cleanUpLine(line) {\n  line.parent = null;\n  detachMarkedSpans(line);\n}\n\n// Convert a style as returned by a mode (either null, or a string\n// containing one or more styles) to a CSS style. This is cached,\n// and also looks for line-wide styles.\nvar styleToClassCache = {};\nvar styleToClassCacheWithMode = {};\nfunction interpretTokenStyle(style, options) {\n  if (!style || /^\\s*$/.test(style)) { return null }\n  var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;\n  return cache[style] ||\n    (cache[style] = style.replace(/\\S+/g, \"cm-$&\"))\n}\n\n// Render the DOM representation of the text of a line. Also builds\n// up a 'line map', which points at the DOM nodes that represent\n// specific stretches of text, and is used by the measuring code.\n// The returned object contains the DOM node, this map, and\n// information about line-wide styles that were set by the mode.\nfunction buildLineContent(cm, lineView) {\n  // The padding-right forces the element to have a 'border', which\n  // is needed on Webkit to be able to get line-level bounding\n  // rectangles for it (in measureChar).\n  var content = eltP(\"span\", null, null, webkit ? \"padding-right: .1px\" : null);\n  var builder = {pre: eltP(\"pre\", [content], \"CodeMirror-line\"), content: content,\n                 col: 0, pos: 0, cm: cm,\n                 trailingSpace: false,\n                 splitSpaces: (ie || webkit) && cm.getOption(\"lineWrapping\")};\n  lineView.measure = {};\n\n  // Iterate over the logical lines that make up this visual line.\n  for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {\n    var line = i ? lineView.rest[i - 1] : lineView.line, order = (void 0);\n    builder.pos = 0;\n    builder.addToken = buildToken;\n    // Optionally wire in some hacks into the token-rendering\n    // algorithm, to deal with browser quirks.\n    if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line, cm.doc.direction)))\n      { builder.addToken = buildTokenBadBidi(builder.addToken, order); }\n    builder.map = [];\n    var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);\n    insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));\n    if (line.styleClasses) {\n      if (line.styleClasses.bgClass)\n        { builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || \"\"); }\n      if (line.styleClasses.textClass)\n        { builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || \"\"); }\n    }\n\n    // Ensure at least a single node is present, for measuring.\n    if (builder.map.length == 0)\n      { builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); }\n\n    // Store the map and a cache object for the current logical line\n    if (i == 0) {\n      lineView.measure.map = builder.map;\n      lineView.measure.cache = {};\n    } else {\n      (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map)\n      ;(lineView.measure.caches || (lineView.measure.caches = [])).push({});\n    }\n  }\n\n  // See issue #2901\n  if (webkit) {\n    var last = builder.content.lastChild;\n    if (/\\bcm-tab\\b/.test(last.className) || (last.querySelector && last.querySelector(\".cm-tab\")))\n      { builder.content.className = \"cm-tab-wrap-hack\"; }\n  }\n\n  signal(cm, \"renderLine\", cm, lineView.line, builder.pre);\n  if (builder.pre.className)\n    { builder.textClass = joinClasses(builder.pre.className, builder.textClass || \"\"); }\n\n  return builder\n}\n\nfunction defaultSpecialCharPlaceholder(ch) {\n  var token = elt(\"span\", \"\\u2022\", \"cm-invalidchar\");\n  token.title = \"\\\\u\" + ch.charCodeAt(0).toString(16);\n  token.setAttribute(\"aria-label\", token.title);\n  return token\n}\n\n// Build up the DOM representation for a single token, and add it to\n// the line map. Takes care to render special characters separately.\nfunction buildToken(builder, text, style, startStyle, endStyle, title, css) {\n  if (!text) { return }\n  var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text;\n  var special = builder.cm.state.specialChars, mustWrap = false;\n  var content;\n  if (!special.test(text)) {\n    builder.col += text.length;\n    content = document.createTextNode(displayText);\n    builder.map.push(builder.pos, builder.pos + text.length, content);\n    if (ie && ie_version < 9) { mustWrap = true; }\n    builder.pos += text.length;\n  } else {\n    content = document.createDocumentFragment();\n    var pos = 0;\n    while (true) {\n      special.lastIndex = pos;\n      var m = special.exec(text);\n      var skipped = m ? m.index - pos : text.length - pos;\n      if (skipped) {\n        var txt = document.createTextNode(displayText.slice(pos, pos + skipped));\n        if (ie && ie_version < 9) { content.appendChild(elt(\"span\", [txt])); }\n        else { content.appendChild(txt); }\n        builder.map.push(builder.pos, builder.pos + skipped, txt);\n        builder.col += skipped;\n        builder.pos += skipped;\n      }\n      if (!m) { break }\n      pos += skipped + 1;\n      var txt$1 = (void 0);\n      if (m[0] == \"\\t\") {\n        var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;\n        txt$1 = content.appendChild(elt(\"span\", spaceStr(tabWidth), \"cm-tab\"));\n        txt$1.setAttribute(\"role\", \"presentation\");\n        txt$1.setAttribute(\"cm-text\", \"\\t\");\n        builder.col += tabWidth;\n      } else if (m[0] == \"\\r\" || m[0] == \"\\n\") {\n        txt$1 = content.appendChild(elt(\"span\", m[0] == \"\\r\" ? \"\\u240d\" : \"\\u2424\", \"cm-invalidchar\"));\n        txt$1.setAttribute(\"cm-text\", m[0]);\n        builder.col += 1;\n      } else {\n        txt$1 = builder.cm.options.specialCharPlaceholder(m[0]);\n        txt$1.setAttribute(\"cm-text\", m[0]);\n        if (ie && ie_version < 9) { content.appendChild(elt(\"span\", [txt$1])); }\n        else { content.appendChild(txt$1); }\n        builder.col += 1;\n      }\n      builder.map.push(builder.pos, builder.pos + 1, txt$1);\n      builder.pos++;\n    }\n  }\n  builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32;\n  if (style || startStyle || endStyle || mustWrap || css) {\n    var fullStyle = style || \"\";\n    if (startStyle) { fullStyle += startStyle; }\n    if (endStyle) { fullStyle += endStyle; }\n    var token = elt(\"span\", [content], fullStyle, css);\n    if (title) { token.title = title; }\n    return builder.content.appendChild(token)\n  }\n  builder.content.appendChild(content);\n}\n\nfunction splitSpaces(text, trailingBefore) {\n  if (text.length > 1 && !/  /.test(text)) { return text }\n  var spaceBefore = trailingBefore, result = \"\";\n  for (var i = 0; i < text.length; i++) {\n    var ch = text.charAt(i);\n    if (ch == \" \" && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32))\n      { ch = \"\\u00a0\"; }\n    result += ch;\n    spaceBefore = ch == \" \";\n  }\n  return result\n}\n\n// Work around nonsense dimensions being reported for stretches of\n// right-to-left text.\nfunction buildTokenBadBidi(inner, order) {\n  return function (builder, text, style, startStyle, endStyle, title, css) {\n    style = style ? style + \" cm-force-border\" : \"cm-force-border\";\n    var start = builder.pos, end = start + text.length;\n    for (;;) {\n      // Find the part that overlaps with the start of this text\n      var part = (void 0);\n      for (var i = 0; i < order.length; i++) {\n        part = order[i];\n        if (part.to > start && part.from <= start) { break }\n      }\n      if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, title, css) }\n      inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css);\n      startStyle = null;\n      text = text.slice(part.to - start);\n      start = part.to;\n    }\n  }\n}\n\nfunction buildCollapsedSpan(builder, size, marker, ignoreWidget) {\n  var widget = !ignoreWidget && marker.widgetNode;\n  if (widget) { builder.map.push(builder.pos, builder.pos + size, widget); }\n  if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {\n    if (!widget)\n      { widget = builder.content.appendChild(document.createElement(\"span\")); }\n    widget.setAttribute(\"cm-marker\", marker.id);\n  }\n  if (widget) {\n    builder.cm.display.input.setUneditable(widget);\n    builder.content.appendChild(widget);\n  }\n  builder.pos += size;\n  builder.trailingSpace = false;\n}\n\n// Outputs a number of spans to make up a line, taking highlighting\n// and marked text into account.\nfunction insertLineContent(line, builder, styles) {\n  var spans = line.markedSpans, allText = line.text, at = 0;\n  if (!spans) {\n    for (var i$1 = 1; i$1 < styles.length; i$1+=2)\n      { builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)); }\n    return\n  }\n\n  var len = allText.length, pos = 0, i = 1, text = \"\", style, css;\n  var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;\n  for (;;) {\n    if (nextChange == pos) { // Update current marker set\n      spanStyle = spanEndStyle = spanStartStyle = title = css = \"\";\n      collapsed = null; nextChange = Infinity;\n      var foundBookmarks = [], endStyles = (void 0);\n      for (var j = 0; j < spans.length; ++j) {\n        var sp = spans[j], m = sp.marker;\n        if (m.type == \"bookmark\" && sp.from == pos && m.widgetNode) {\n          foundBookmarks.push(m);\n        } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {\n          if (sp.to != null && sp.to != pos && nextChange > sp.to) {\n            nextChange = sp.to;\n            spanEndStyle = \"\";\n          }\n          if (m.className) { spanStyle += \" \" + m.className; }\n          if (m.css) { css = (css ? css + \";\" : \"\") + m.css; }\n          if (m.startStyle && sp.from == pos) { spanStartStyle += \" \" + m.startStyle; }\n          if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to); }\n          if (m.title && !title) { title = m.title; }\n          if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))\n            { collapsed = sp; }\n        } else if (sp.from > pos && nextChange > sp.from) {\n          nextChange = sp.from;\n        }\n      }\n      if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2)\n        { if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += \" \" + endStyles[j$1]; } } }\n\n      if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2)\n        { buildCollapsedSpan(builder, 0, foundBookmarks[j$2]); } }\n      if (collapsed && (collapsed.from || 0) == pos) {\n        buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,\n                           collapsed.marker, collapsed.from == null);\n        if (collapsed.to == null) { return }\n        if (collapsed.to == pos) { collapsed = false; }\n      }\n    }\n    if (pos >= len) { break }\n\n    var upto = Math.min(len, nextChange);\n    while (true) {\n      if (text) {\n        var end = pos + text.length;\n        if (!collapsed) {\n          var tokenText = end > upto ? text.slice(0, upto - pos) : text;\n          builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,\n                           spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : \"\", title, css);\n        }\n        if (end >= upto) {text = text.slice(upto - pos); pos = upto; break}\n        pos = end;\n        spanStartStyle = \"\";\n      }\n      text = allText.slice(at, at = styles[i++]);\n      style = interpretTokenStyle(styles[i++], builder.cm.options);\n    }\n  }\n}\n\n\n// These objects are used to represent the visible (currently drawn)\n// part of the document. A LineView may correspond to multiple\n// logical lines, if those are connected by collapsed ranges.\nfunction LineView(doc, line, lineN) {\n  // The starting line\n  this.line = line;\n  // Continuing lines, if any\n  this.rest = visualLineContinued(line);\n  // Number of logical lines in this visual line\n  this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;\n  this.node = this.text = null;\n  this.hidden = lineIsHidden(doc, line);\n}\n\n// Create a range of LineView objects for the given lines.\nfunction buildViewArray(cm, from, to) {\n  var array = [], nextPos;\n  for (var pos = from; pos < to; pos = nextPos) {\n    var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);\n    nextPos = pos + view.size;\n    array.push(view);\n  }\n  return array\n}\n\nvar operationGroup = null;\n\nfunction pushOperation(op) {\n  if (operationGroup) {\n    operationGroup.ops.push(op);\n  } else {\n    op.ownsGroup = operationGroup = {\n      ops: [op],\n      delayedCallbacks: []\n    };\n  }\n}\n\nfunction fireCallbacksForOps(group) {\n  // Calls delayed callbacks and cursorActivity handlers until no\n  // new ones appear\n  var callbacks = group.delayedCallbacks, i = 0;\n  do {\n    for (; i < callbacks.length; i++)\n      { callbacks[i].call(null); }\n    for (var j = 0; j < group.ops.length; j++) {\n      var op = group.ops[j];\n      if (op.cursorActivityHandlers)\n        { while (op.cursorActivityCalled < op.cursorActivityHandlers.length)\n          { op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); } }\n    }\n  } while (i < callbacks.length)\n}\n\nfunction finishOperation(op, endCb) {\n  var group = op.ownsGroup;\n  if (!group) { return }\n\n  try { fireCallbacksForOps(group); }\n  finally {\n    operationGroup = null;\n    endCb(group);\n  }\n}\n\nvar orphanDelayedCallbacks = null;\n\n// Often, we want to signal events at a point where we are in the\n// middle of some work, but don't want the handler to start calling\n// other methods on the editor, which might be in an inconsistent\n// state or simply not expect any other events to happen.\n// signalLater looks whether there are any handlers, and schedules\n// them to be executed when the last operation ends, or, if no\n// operation is active, when a timeout fires.\nfunction signalLater(emitter, type /*, values...*/) {\n  var arr = getHandlers(emitter, type);\n  if (!arr.length) { return }\n  var args = Array.prototype.slice.call(arguments, 2), list;\n  if (operationGroup) {\n    list = operationGroup.delayedCallbacks;\n  } else if (orphanDelayedCallbacks) {\n    list = orphanDelayedCallbacks;\n  } else {\n    list = orphanDelayedCallbacks = [];\n    setTimeout(fireOrphanDelayed, 0);\n  }\n  var loop = function ( i ) {\n    list.push(function () { return arr[i].apply(null, args); });\n  };\n\n  for (var i = 0; i < arr.length; ++i)\n    loop( i );\n}\n\nfunction fireOrphanDelayed() {\n  var delayed = orphanDelayedCallbacks;\n  orphanDelayedCallbacks = null;\n  for (var i = 0; i < delayed.length; ++i) { delayed[i](); }\n}\n\n// When an aspect of a line changes, a string is added to\n// lineView.changes. This updates the relevant part of the line's\n// DOM structure.\nfunction updateLineForChanges(cm, lineView, lineN, dims) {\n  for (var j = 0; j < lineView.changes.length; j++) {\n    var type = lineView.changes[j];\n    if (type == \"text\") { updateLineText(cm, lineView); }\n    else if (type == \"gutter\") { updateLineGutter(cm, lineView, lineN, dims); }\n    else if (type == \"class\") { updateLineClasses(cm, lineView); }\n    else if (type == \"widget\") { updateLineWidgets(cm, lineView, dims); }\n  }\n  lineView.changes = null;\n}\n\n// Lines with gutter elements, widgets or a background class need to\n// be wrapped, and have the extra elements added to the wrapper div\nfunction ensureLineWrapped(lineView) {\n  if (lineView.node == lineView.text) {\n    lineView.node = elt(\"div\", null, null, \"position: relative\");\n    if (lineView.text.parentNode)\n      { lineView.text.parentNode.replaceChild(lineView.node, lineView.text); }\n    lineView.node.appendChild(lineView.text);\n    if (ie && ie_version < 8) { lineView.node.style.zIndex = 2; }\n  }\n  return lineView.node\n}\n\nfunction updateLineBackground(cm, lineView) {\n  var cls = lineView.bgClass ? lineView.bgClass + \" \" + (lineView.line.bgClass || \"\") : lineView.line.bgClass;\n  if (cls) { cls += \" CodeMirror-linebackground\"; }\n  if (lineView.background) {\n    if (cls) { lineView.background.className = cls; }\n    else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }\n  } else if (cls) {\n    var wrap = ensureLineWrapped(lineView);\n    lineView.background = wrap.insertBefore(elt(\"div\", null, cls), wrap.firstChild);\n    cm.display.input.setUneditable(lineView.background);\n  }\n}\n\n// Wrapper around buildLineContent which will reuse the structure\n// in display.externalMeasured when possible.\nfunction getLineContent(cm, lineView) {\n  var ext = cm.display.externalMeasured;\n  if (ext && ext.line == lineView.line) {\n    cm.display.externalMeasured = null;\n    lineView.measure = ext.measure;\n    return ext.built\n  }\n  return buildLineContent(cm, lineView)\n}\n\n// Redraw the line's text. Interacts with the background and text\n// classes because the mode may output tokens that influence these\n// classes.\nfunction updateLineText(cm, lineView) {\n  var cls = lineView.text.className;\n  var built = getLineContent(cm, lineView);\n  if (lineView.text == lineView.node) { lineView.node = built.pre; }\n  lineView.text.parentNode.replaceChild(built.pre, lineView.text);\n  lineView.text = built.pre;\n  if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {\n    lineView.bgClass = built.bgClass;\n    lineView.textClass = built.textClass;\n    updateLineClasses(cm, lineView);\n  } else if (cls) {\n    lineView.text.className = cls;\n  }\n}\n\nfunction updateLineClasses(cm, lineView) {\n  updateLineBackground(cm, lineView);\n  if (lineView.line.wrapClass)\n    { ensureLineWrapped(lineView).className = lineView.line.wrapClass; }\n  else if (lineView.node != lineView.text)\n    { lineView.node.className = \"\"; }\n  var textClass = lineView.textClass ? lineView.textClass + \" \" + (lineView.line.textClass || \"\") : lineView.line.textClass;\n  lineView.text.className = textClass || \"\";\n}\n\nfunction updateLineGutter(cm, lineView, lineN, dims) {\n  if (lineView.gutter) {\n    lineView.node.removeChild(lineView.gutter);\n    lineView.gutter = null;\n  }\n  if (lineView.gutterBackground) {\n    lineView.node.removeChild(lineView.gutterBackground);\n    lineView.gutterBackground = null;\n  }\n  if (lineView.line.gutterClass) {\n    var wrap = ensureLineWrapped(lineView);\n    lineView.gutterBackground = elt(\"div\", null, \"CodeMirror-gutter-background \" + lineView.line.gutterClass,\n                                    (\"left: \" + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + \"px; width: \" + (dims.gutterTotalWidth) + \"px\"));\n    cm.display.input.setUneditable(lineView.gutterBackground);\n    wrap.insertBefore(lineView.gutterBackground, lineView.text);\n  }\n  var markers = lineView.line.gutterMarkers;\n  if (cm.options.lineNumbers || markers) {\n    var wrap$1 = ensureLineWrapped(lineView);\n    var gutterWrap = lineView.gutter = elt(\"div\", null, \"CodeMirror-gutter-wrapper\", (\"left: \" + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + \"px\"));\n    cm.display.input.setUneditable(gutterWrap);\n    wrap$1.insertBefore(gutterWrap, lineView.text);\n    if (lineView.line.gutterClass)\n      { gutterWrap.className += \" \" + lineView.line.gutterClass; }\n    if (cm.options.lineNumbers && (!markers || !markers[\"CodeMirror-linenumbers\"]))\n      { lineView.lineNumber = gutterWrap.appendChild(\n        elt(\"div\", lineNumberFor(cm.options, lineN),\n            \"CodeMirror-linenumber CodeMirror-gutter-elt\",\n            (\"left: \" + (dims.gutterLeft[\"CodeMirror-linenumbers\"]) + \"px; width: \" + (cm.display.lineNumInnerWidth) + \"px\"))); }\n    if (markers) { for (var k = 0; k < cm.options.gutters.length; ++k) {\n      var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];\n      if (found)\n        { gutterWrap.appendChild(elt(\"div\", [found], \"CodeMirror-gutter-elt\",\n                                   (\"left: \" + (dims.gutterLeft[id]) + \"px; width: \" + (dims.gutterWidth[id]) + \"px\"))); }\n    } }\n  }\n}\n\nfunction updateLineWidgets(cm, lineView, dims) {\n  if (lineView.alignable) { lineView.alignable = null; }\n  for (var node = lineView.node.firstChild, next = (void 0); node; node = next) {\n    next = node.nextSibling;\n    if (node.className == \"CodeMirror-linewidget\")\n      { lineView.node.removeChild(node); }\n  }\n  insertLineWidgets(cm, lineView, dims);\n}\n\n// Build a line's DOM representation from scratch\nfunction buildLineElement(cm, lineView, lineN, dims) {\n  var built = getLineContent(cm, lineView);\n  lineView.text = lineView.node = built.pre;\n  if (built.bgClass) { lineView.bgClass = built.bgClass; }\n  if (built.textClass) { lineView.textClass = built.textClass; }\n\n  updateLineClasses(cm, lineView);\n  updateLineGutter(cm, lineView, lineN, dims);\n  insertLineWidgets(cm, lineView, dims);\n  return lineView.node\n}\n\n// A lineView may contain multiple logical lines (when merged by\n// collapsed spans). The widgets for all of them need to be drawn.\nfunction insertLineWidgets(cm, lineView, dims) {\n  insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);\n  if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)\n    { insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); } }\n}\n\nfunction insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {\n  if (!line.widgets) { return }\n  var wrap = ensureLineWrapped(lineView);\n  for (var i = 0, ws = line.widgets; i < ws.length; ++i) {\n    var widget = ws[i], node = elt(\"div\", [widget.node], \"CodeMirror-linewidget\");\n    if (!widget.handleMouseEvents) { node.setAttribute(\"cm-ignore-events\", \"true\"); }\n    positionLineWidget(widget, node, lineView, dims);\n    cm.display.input.setUneditable(node);\n    if (allowAbove && widget.above)\n      { wrap.insertBefore(node, lineView.gutter || lineView.text); }\n    else\n      { wrap.appendChild(node); }\n    signalLater(widget, \"redraw\");\n  }\n}\n\nfunction positionLineWidget(widget, node, lineView, dims) {\n  if (widget.noHScroll) {\n    (lineView.alignable || (lineView.alignable = [])).push(node);\n    var width = dims.wrapperWidth;\n    node.style.left = dims.fixedPos + \"px\";\n    if (!widget.coverGutter) {\n      width -= dims.gutterTotalWidth;\n      node.style.paddingLeft = dims.gutterTotalWidth + \"px\";\n    }\n    node.style.width = width + \"px\";\n  }\n  if (widget.coverGutter) {\n    node.style.zIndex = 5;\n    node.style.position = \"relative\";\n    if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + \"px\"; }\n  }\n}\n\nfunction widgetHeight(widget) {\n  if (widget.height != null) { return widget.height }\n  var cm = widget.doc.cm;\n  if (!cm) { return 0 }\n  if (!contains(document.body, widget.node)) {\n    var parentStyle = \"position: relative;\";\n    if (widget.coverGutter)\n      { parentStyle += \"margin-left: -\" + cm.display.gutters.offsetWidth + \"px;\"; }\n    if (widget.noHScroll)\n      { parentStyle += \"width: \" + cm.display.wrapper.clientWidth + \"px;\"; }\n    removeChildrenAndAdd(cm.display.measure, elt(\"div\", [widget.node], null, parentStyle));\n  }\n  return widget.height = widget.node.parentNode.offsetHeight\n}\n\n// Return true when the given mouse event happened in a widget\nfunction eventInWidget(display, e) {\n  for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {\n    if (!n || (n.nodeType == 1 && n.getAttribute(\"cm-ignore-events\") == \"true\") ||\n        (n.parentNode == display.sizer && n != display.mover))\n      { return true }\n  }\n}\n\n// POSITION MEASUREMENT\n\nfunction paddingTop(display) {return display.lineSpace.offsetTop}\nfunction paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight}\nfunction paddingH(display) {\n  if (display.cachedPaddingH) { return display.cachedPaddingH }\n  var e = removeChildrenAndAdd(display.measure, elt(\"pre\", \"x\"));\n  var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;\n  var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};\n  if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data; }\n  return data\n}\n\nfunction scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth }\nfunction displayWidth(cm) {\n  return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth\n}\nfunction displayHeight(cm) {\n  return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight\n}\n\n// Ensure the lineView.wrapping.heights array is populated. This is\n// an array of bottom offsets for the lines that make up a drawn\n// line. When lineWrapping is on, there might be more than one\n// height.\nfunction ensureLineHeights(cm, lineView, rect) {\n  var wrapping = cm.options.lineWrapping;\n  var curWidth = wrapping && displayWidth(cm);\n  if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {\n    var heights = lineView.measure.heights = [];\n    if (wrapping) {\n      lineView.measure.width = curWidth;\n      var rects = lineView.text.firstChild.getClientRects();\n      for (var i = 0; i < rects.length - 1; i++) {\n        var cur = rects[i], next = rects[i + 1];\n        if (Math.abs(cur.bottom - next.bottom) > 2)\n          { heights.push((cur.bottom + next.top) / 2 - rect.top); }\n      }\n    }\n    heights.push(rect.bottom - rect.top);\n  }\n}\n\n// Find a line map (mapping character offsets to text nodes) and a\n// measurement cache for the given line number. (A line view might\n// contain multiple lines when collapsed ranges are present.)\nfunction mapFromLineView(lineView, line, lineN) {\n  if (lineView.line == line)\n    { return {map: lineView.measure.map, cache: lineView.measure.cache} }\n  for (var i = 0; i < lineView.rest.length; i++)\n    { if (lineView.rest[i] == line)\n      { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } }\n  for (var i$1 = 0; i$1 < lineView.rest.length; i$1++)\n    { if (lineNo(lineView.rest[i$1]) > lineN)\n      { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } }\n}\n\n// Render a line into the hidden node display.externalMeasured. Used\n// when measurement is needed for a line that's not in the viewport.\nfunction updateExternalMeasurement(cm, line) {\n  line = visualLine(line);\n  var lineN = lineNo(line);\n  var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);\n  view.lineN = lineN;\n  var built = view.built = buildLineContent(cm, view);\n  view.text = built.pre;\n  removeChildrenAndAdd(cm.display.lineMeasure, built.pre);\n  return view\n}\n\n// Get a {top, bottom, left, right} box (in line-local coordinates)\n// for a given character.\nfunction measureChar(cm, line, ch, bias) {\n  return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias)\n}\n\n// Find a line view that corresponds to the given line number.\nfunction findViewForLine(cm, lineN) {\n  if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)\n    { return cm.display.view[findViewIndex(cm, lineN)] }\n  var ext = cm.display.externalMeasured;\n  if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)\n    { return ext }\n}\n\n// Measurement can be split in two steps, the set-up work that\n// applies to the whole line, and the measurement of the actual\n// character. Functions like coordsChar, that need to do a lot of\n// measurements in a row, can thus ensure that the set-up work is\n// only done once.\nfunction prepareMeasureForLine(cm, line) {\n  var lineN = lineNo(line);\n  var view = findViewForLine(cm, lineN);\n  if (view && !view.text) {\n    view = null;\n  } else if (view && view.changes) {\n    updateLineForChanges(cm, view, lineN, getDimensions(cm));\n    cm.curOp.forceUpdate = true;\n  }\n  if (!view)\n    { view = updateExternalMeasurement(cm, line); }\n\n  var info = mapFromLineView(view, line, lineN);\n  return {\n    line: line, view: view, rect: null,\n    map: info.map, cache: info.cache, before: info.before,\n    hasHeights: false\n  }\n}\n\n// Given a prepared measurement object, measures the position of an\n// actual character (or fetches it from the cache).\nfunction measureCharPrepared(cm, prepared, ch, bias, varHeight) {\n  if (prepared.before) { ch = -1; }\n  var key = ch + (bias || \"\"), found;\n  if (prepared.cache.hasOwnProperty(key)) {\n    found = prepared.cache[key];\n  } else {\n    if (!prepared.rect)\n      { prepared.rect = prepared.view.text.getBoundingClientRect(); }\n    if (!prepared.hasHeights) {\n      ensureLineHeights(cm, prepared.view, prepared.rect);\n      prepared.hasHeights = true;\n    }\n    found = measureCharInner(cm, prepared, ch, bias);\n    if (!found.bogus) { prepared.cache[key] = found; }\n  }\n  return {left: found.left, right: found.right,\n          top: varHeight ? found.rtop : found.top,\n          bottom: varHeight ? found.rbottom : found.bottom}\n}\n\nvar nullRect = {left: 0, right: 0, top: 0, bottom: 0};\n\nfunction nodeAndOffsetInLineMap(map$$1, ch, bias) {\n  var node, start, end, collapse, mStart, mEnd;\n  // First, search the line map for the text node corresponding to,\n  // or closest to, the target character.\n  for (var i = 0; i < map$$1.length; i += 3) {\n    mStart = map$$1[i];\n    mEnd = map$$1[i + 1];\n    if (ch < mStart) {\n      start = 0; end = 1;\n      collapse = \"left\";\n    } else if (ch < mEnd) {\n      start = ch - mStart;\n      end = start + 1;\n    } else if (i == map$$1.length - 3 || ch == mEnd && map$$1[i + 3] > ch) {\n      end = mEnd - mStart;\n      start = end - 1;\n      if (ch >= mEnd) { collapse = \"right\"; }\n    }\n    if (start != null) {\n      node = map$$1[i + 2];\n      if (mStart == mEnd && bias == (node.insertLeft ? \"left\" : \"right\"))\n        { collapse = bias; }\n      if (bias == \"left\" && start == 0)\n        { while (i && map$$1[i - 2] == map$$1[i - 3] && map$$1[i - 1].insertLeft) {\n          node = map$$1[(i -= 3) + 2];\n          collapse = \"left\";\n        } }\n      if (bias == \"right\" && start == mEnd - mStart)\n        { while (i < map$$1.length - 3 && map$$1[i + 3] == map$$1[i + 4] && !map$$1[i + 5].insertLeft) {\n          node = map$$1[(i += 3) + 2];\n          collapse = \"right\";\n        } }\n      break\n    }\n  }\n  return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}\n}\n\nfunction getUsefulRect(rects, bias) {\n  var rect = nullRect;\n  if (bias == \"left\") { for (var i = 0; i < rects.length; i++) {\n    if ((rect = rects[i]).left != rect.right) { break }\n  } } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) {\n    if ((rect = rects[i$1]).left != rect.right) { break }\n  } }\n  return rect\n}\n\nfunction measureCharInner(cm, prepared, ch, bias) {\n  var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);\n  var node = place.node, start = place.start, end = place.end, collapse = place.collapse;\n\n  var rect;\n  if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.\n    for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned\n      while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start; }\n      while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end; }\n      if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart)\n        { rect = node.parentNode.getBoundingClientRect(); }\n      else\n        { rect = getUsefulRect(range(node, start, end).getClientRects(), bias); }\n      if (rect.left || rect.right || start == 0) { break }\n      end = start;\n      start = start - 1;\n      collapse = \"right\";\n    }\n    if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect); }\n  } else { // If it is a widget, simply get the box for the whole widget.\n    if (start > 0) { collapse = bias = \"right\"; }\n    var rects;\n    if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)\n      { rect = rects[bias == \"right\" ? rects.length - 1 : 0]; }\n    else\n      { rect = node.getBoundingClientRect(); }\n  }\n  if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {\n    var rSpan = node.parentNode.getClientRects()[0];\n    if (rSpan)\n      { rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; }\n    else\n      { rect = nullRect; }\n  }\n\n  var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;\n  var mid = (rtop + rbot) / 2;\n  var heights = prepared.view.measure.heights;\n  var i = 0;\n  for (; i < heights.length - 1; i++)\n    { if (mid < heights[i]) { break } }\n  var top = i ? heights[i - 1] : 0, bot = heights[i];\n  var result = {left: (collapse == \"right\" ? rect.right : rect.left) - prepared.rect.left,\n                right: (collapse == \"left\" ? rect.left : rect.right) - prepared.rect.left,\n                top: top, bottom: bot};\n  if (!rect.left && !rect.right) { result.bogus = true; }\n  if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }\n\n  return result\n}\n\n// Work around problem with bounding client rects on ranges being\n// returned incorrectly when zoomed on IE10 and below.\nfunction maybeUpdateRectForZooming(measure, rect) {\n  if (!window.screen || screen.logicalXDPI == null ||\n      screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))\n    { return rect }\n  var scaleX = screen.logicalXDPI / screen.deviceXDPI;\n  var scaleY = screen.logicalYDPI / screen.deviceYDPI;\n  return {left: rect.left * scaleX, right: rect.right * scaleX,\n          top: rect.top * scaleY, bottom: rect.bottom * scaleY}\n}\n\nfunction clearLineMeasurementCacheFor(lineView) {\n  if (lineView.measure) {\n    lineView.measure.cache = {};\n    lineView.measure.heights = null;\n    if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)\n      { lineView.measure.caches[i] = {}; } }\n  }\n}\n\nfunction clearLineMeasurementCache(cm) {\n  cm.display.externalMeasure = null;\n  removeChildren(cm.display.lineMeasure);\n  for (var i = 0; i < cm.display.view.length; i++)\n    { clearLineMeasurementCacheFor(cm.display.view[i]); }\n}\n\nfunction clearCaches(cm) {\n  clearLineMeasurementCache(cm);\n  cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;\n  if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true; }\n  cm.display.lineNumChars = null;\n}\n\nfunction pageScrollX() {\n  // Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206\n  // which causes page_Offset and bounding client rects to use\n  // different reference viewports and invalidate our calculations.\n  if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) }\n  return window.pageXOffset || (document.documentElement || document.body).scrollLeft\n}\nfunction pageScrollY() {\n  if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) }\n  return window.pageYOffset || (document.documentElement || document.body).scrollTop\n}\n\n// Converts a {top, bottom, left, right} box from line-local\n// coordinates into another coordinate system. Context may be one of\n// \"line\", \"div\" (display.lineDiv), \"local\"./null (editor), \"window\",\n// or \"page\".\nfunction intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {\n  if (!includeWidgets && lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above) {\n    var size = widgetHeight(lineObj.widgets[i]);\n    rect.top += size; rect.bottom += size;\n  } } }\n  if (context == \"line\") { return rect }\n  if (!context) { context = \"local\"; }\n  var yOff = heightAtLine(lineObj);\n  if (context == \"local\") { yOff += paddingTop(cm.display); }\n  else { yOff -= cm.display.viewOffset; }\n  if (context == \"page\" || context == \"window\") {\n    var lOff = cm.display.lineSpace.getBoundingClientRect();\n    yOff += lOff.top + (context == \"window\" ? 0 : pageScrollY());\n    var xOff = lOff.left + (context == \"window\" ? 0 : pageScrollX());\n    rect.left += xOff; rect.right += xOff;\n  }\n  rect.top += yOff; rect.bottom += yOff;\n  return rect\n}\n\n// Coverts a box from \"div\" coords to another coordinate system.\n// Context may be \"window\", \"page\", \"div\", or \"local\"./null.\nfunction fromCoordSystem(cm, coords, context) {\n  if (context == \"div\") { return coords }\n  var left = coords.left, top = coords.top;\n  // First move into \"page\" coordinate system\n  if (context == \"page\") {\n    left -= pageScrollX();\n    top -= pageScrollY();\n  } else if (context == \"local\" || !context) {\n    var localBox = cm.display.sizer.getBoundingClientRect();\n    left += localBox.left;\n    top += localBox.top;\n  }\n\n  var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();\n  return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}\n}\n\nfunction charCoords(cm, pos, context, lineObj, bias) {\n  if (!lineObj) { lineObj = getLine(cm.doc, pos.line); }\n  return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context)\n}\n\n// Returns a box for a given cursor position, which may have an\n// 'other' property containing the position of the secondary cursor\n// on a bidi boundary.\n// A cursor Pos(line, char, \"before\") is on the same visual line as `char - 1`\n// and after `char - 1` in writing order of `char - 1`\n// A cursor Pos(line, char, \"after\") is on the same visual line as `char`\n// and before `char` in writing order of `char`\n// Examples (upper-case letters are RTL, lower-case are LTR):\n//     Pos(0, 1, ...)\n//     before   after\n// ab     a|b     a|b\n// aB     a|B     aB|\n// Ab     |Ab     A|b\n// AB     B|A     B|A\n// Every position after the last character on a line is considered to stick\n// to the last character on the line.\nfunction cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {\n  lineObj = lineObj || getLine(cm.doc, pos.line);\n  if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }\n  function get(ch, right) {\n    var m = measureCharPrepared(cm, preparedMeasure, ch, right ? \"right\" : \"left\", varHeight);\n    if (right) { m.left = m.right; } else { m.right = m.left; }\n    return intoCoordSystem(cm, lineObj, m, context)\n  }\n  var order = getOrder(lineObj, cm.doc.direction), ch = pos.ch, sticky = pos.sticky;\n  if (ch >= lineObj.text.length) {\n    ch = lineObj.text.length;\n    sticky = \"before\";\n  } else if (ch <= 0) {\n    ch = 0;\n    sticky = \"after\";\n  }\n  if (!order) { return get(sticky == \"before\" ? ch - 1 : ch, sticky == \"before\") }\n\n  function getBidi(ch, partPos, invert) {\n    var part = order[partPos], right = (part.level % 2) != 0;\n    return get(invert ? ch - 1 : ch, right != invert)\n  }\n  var partPos = getBidiPartAt(order, ch, sticky);\n  var other = bidiOther;\n  var val = getBidi(ch, partPos, sticky == \"before\");\n  if (other != null) { val.other = getBidi(ch, other, sticky != \"before\"); }\n  return val\n}\n\n// Used to cheaply estimate the coordinates for a position. Used for\n// intermediate scroll updates.\nfunction estimateCoords(cm, pos) {\n  var left = 0;\n  pos = clipPos(cm.doc, pos);\n  if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch; }\n  var lineObj = getLine(cm.doc, pos.line);\n  var top = heightAtLine(lineObj) + paddingTop(cm.display);\n  return {left: left, right: left, top: top, bottom: top + lineObj.height}\n}\n\n// Positions returned by coordsChar contain some extra information.\n// xRel is the relative x position of the input coordinates compared\n// to the found position (so xRel > 0 means the coordinates are to\n// the right of the character position, for example). When outside\n// is true, that means the coordinates lie outside the line's\n// vertical range.\nfunction PosWithInfo(line, ch, sticky, outside, xRel) {\n  var pos = Pos(line, ch, sticky);\n  pos.xRel = xRel;\n  if (outside) { pos.outside = true; }\n  return pos\n}\n\n// Compute the character position closest to the given coordinates.\n// Input must be lineSpace-local (\"div\" coordinate system).\nfunction coordsChar(cm, x, y) {\n  var doc = cm.doc;\n  y += cm.display.viewOffset;\n  if (y < 0) { return PosWithInfo(doc.first, 0, null, true, -1) }\n  var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;\n  if (lineN > last)\n    { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, true, 1) }\n  if (x < 0) { x = 0; }\n\n  var lineObj = getLine(doc, lineN);\n  for (;;) {\n    var found = coordsCharInner(cm, lineObj, lineN, x, y);\n    var merged = collapsedSpanAtEnd(lineObj);\n    var mergedPos = merged && merged.find(0, true);\n    if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))\n      { lineN = lineNo(lineObj = mergedPos.to.line); }\n    else\n      { return found }\n  }\n}\n\nfunction wrappedLineExtent(cm, lineObj, preparedMeasure, y) {\n  var measure = function (ch) { return intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, ch), \"line\"); };\n  var end = lineObj.text.length;\n  var begin = findFirst(function (ch) { return measure(ch - 1).bottom <= y; }, end, 0);\n  end = findFirst(function (ch) { return measure(ch).top > y; }, begin, end);\n  return {begin: begin, end: end}\n}\n\nfunction wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {\n  var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), \"line\").top;\n  return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop)\n}\n\nfunction coordsCharInner(cm, lineObj, lineNo$$1, x, y) {\n  y -= heightAtLine(lineObj);\n  var begin = 0, end = lineObj.text.length;\n  var preparedMeasure = prepareMeasureForLine(cm, lineObj);\n  var pos;\n  var order = getOrder(lineObj, cm.doc.direction);\n  if (order) {\n    if (cm.options.lineWrapping) {\n      var assign;\n      ((assign = wrappedLineExtent(cm, lineObj, preparedMeasure, y), begin = assign.begin, end = assign.end));\n    }\n    pos = new Pos(lineNo$$1, Math.floor(begin + (end - begin) / 2));\n    var beginLeft = cursorCoords(cm, pos, \"line\", lineObj, preparedMeasure).left;\n    var dir = beginLeft < x ? 1 : -1;\n    var prevDiff, diff = beginLeft - x, prevPos;\n    var steps = Math.ceil((end - begin) / 4);\n    outer: do {\n      prevDiff = diff;\n      prevPos = pos;\n      var i = 0;\n      for (; i < steps; ++i) {\n        var prevPos$1 = pos;\n        pos = moveVisually(cm, lineObj, pos, dir);\n        if (pos == null || pos.ch < begin || end <= (pos.sticky == \"before\" ? pos.ch - 1 : pos.ch)) {\n          pos = prevPos$1;\n          break outer\n        }\n      }\n      diff = cursorCoords(cm, pos, \"line\", lineObj, preparedMeasure).left - x;\n      if (steps > 1) {\n        var diff_change_per_step = Math.abs(diff - prevDiff) / steps;\n        steps = Math.min(steps, Math.ceil(Math.abs(diff) / diff_change_per_step));\n        dir = diff < 0 ? 1 : -1;\n      }\n    } while (diff != 0 && (steps > 1 || ((dir < 0) != (diff < 0) && (Math.abs(diff) <= Math.abs(prevDiff)))))\n    if (Math.abs(diff) > Math.abs(prevDiff)) {\n      if ((diff < 0) == (prevDiff < 0)) { throw new Error(\"Broke out of infinite loop in coordsCharInner\") }\n      pos = prevPos;\n    }\n  } else {\n    var ch = findFirst(function (ch) {\n      var box = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, ch), \"line\");\n      if (box.top > y) {\n        // For the cursor stickiness\n        end = Math.min(ch, end);\n        return true\n      }\n      else if (box.bottom <= y) { return false }\n      else if (box.left > x) { return true }\n      else if (box.right < x) { return false }\n      else { return (x - box.left < box.right - x) }\n    }, begin, end);\n    ch = skipExtendingChars(lineObj.text, ch, 1);\n    pos = new Pos(lineNo$$1, ch, ch == end ? \"before\" : \"after\");\n  }\n  var coords = cursorCoords(cm, pos, \"line\", lineObj, preparedMeasure);\n  if (y < coords.top || coords.bottom < y) { pos.outside = true; }\n  pos.xRel = x < coords.left ? -1 : (x > coords.right ? 1 : 0);\n  return pos\n}\n\nvar measureText;\n// Compute the default text height.\nfunction textHeight(display) {\n  if (display.cachedTextHeight != null) { return display.cachedTextHeight }\n  if (measureText == null) {\n    measureText = elt(\"pre\");\n    // Measure a bunch of lines, for browsers that compute\n    // fractional heights.\n    for (var i = 0; i < 49; ++i) {\n      measureText.appendChild(document.createTextNode(\"x\"));\n      measureText.appendChild(elt(\"br\"));\n    }\n    measureText.appendChild(document.createTextNode(\"x\"));\n  }\n  removeChildrenAndAdd(display.measure, measureText);\n  var height = measureText.offsetHeight / 50;\n  if (height > 3) { display.cachedTextHeight = height; }\n  removeChildren(display.measure);\n  return height || 1\n}\n\n// Compute the default character width.\nfunction charWidth(display) {\n  if (display.cachedCharWidth != null) { return display.cachedCharWidth }\n  var anchor = elt(\"span\", \"xxxxxxxxxx\");\n  var pre = elt(\"pre\", [anchor]);\n  removeChildrenAndAdd(display.measure, pre);\n  var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;\n  if (width > 2) { display.cachedCharWidth = width; }\n  return width || 10\n}\n\n// Do a bulk-read of the DOM positions and sizes needed to draw the\n// view, so that we don't interleave reading and writing to the DOM.\nfunction getDimensions(cm) {\n  var d = cm.display, left = {}, width = {};\n  var gutterLeft = d.gutters.clientLeft;\n  for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {\n    left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;\n    width[cm.options.gutters[i]] = n.clientWidth;\n  }\n  return {fixedPos: compensateForHScroll(d),\n          gutterTotalWidth: d.gutters.offsetWidth,\n          gutterLeft: left,\n          gutterWidth: width,\n          wrapperWidth: d.wrapper.clientWidth}\n}\n\n// Computes display.scroller.scrollLeft + display.gutters.offsetWidth,\n// but using getBoundingClientRect to get a sub-pixel-accurate\n// result.\nfunction compensateForHScroll(display) {\n  return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left\n}\n\n// Returns a function that estimates the height of a line, to use as\n// first approximation until the line becomes visible (and is thus\n// properly measurable).\nfunction estimateHeight(cm) {\n  var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;\n  var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);\n  return function (line) {\n    if (lineIsHidden(cm.doc, line)) { return 0 }\n\n    var widgetsHeight = 0;\n    if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) {\n      if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height; }\n    } }\n\n    if (wrapping)\n      { return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th }\n    else\n      { return widgetsHeight + th }\n  }\n}\n\nfunction estimateLineHeights(cm) {\n  var doc = cm.doc, est = estimateHeight(cm);\n  doc.iter(function (line) {\n    var estHeight = est(line);\n    if (estHeight != line.height) { updateLineHeight(line, estHeight); }\n  });\n}\n\n// Given a mouse event, find the corresponding position. If liberal\n// is false, it checks whether a gutter or scrollbar was clicked,\n// and returns null if it was. forRect is used by rectangular\n// selections, and tries to estimate a character position even for\n// coordinates beyond the right of the text.\nfunction posFromMouse(cm, e, liberal, forRect) {\n  var display = cm.display;\n  if (!liberal && e_target(e).getAttribute(\"cm-not-content\") == \"true\") { return null }\n\n  var x, y, space = display.lineSpace.getBoundingClientRect();\n  // Fails unpredictably on IE[67] when mouse is dragged around quickly.\n  try { x = e.clientX - space.left; y = e.clientY - space.top; }\n  catch (e) { return null }\n  var coords = coordsChar(cm, x, y), line;\n  if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {\n    var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;\n    coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));\n  }\n  return coords\n}\n\n// Find the view element corresponding to a given line. Return null\n// when the line isn't visible.\nfunction findViewIndex(cm, n) {\n  if (n >= cm.display.viewTo) { return null }\n  n -= cm.display.viewFrom;\n  if (n < 0) { return null }\n  var view = cm.display.view;\n  for (var i = 0; i < view.length; i++) {\n    n -= view[i].size;\n    if (n < 0) { return i }\n  }\n}\n\nfunction updateSelection(cm) {\n  cm.display.input.showSelection(cm.display.input.prepareSelection());\n}\n\nfunction prepareSelection(cm, primary) {\n  var doc = cm.doc, result = {};\n  var curFragment = result.cursors = document.createDocumentFragment();\n  var selFragment = result.selection = document.createDocumentFragment();\n\n  for (var i = 0; i < doc.sel.ranges.length; i++) {\n    if (primary === false && i == doc.sel.primIndex) { continue }\n    var range$$1 = doc.sel.ranges[i];\n    if (range$$1.from().line >= cm.display.viewTo || range$$1.to().line < cm.display.viewFrom) { continue }\n    var collapsed = range$$1.empty();\n    if (collapsed || cm.options.showCursorWhenSelecting)\n      { drawSelectionCursor(cm, range$$1.head, curFragment); }\n    if (!collapsed)\n      { drawSelectionRange(cm, range$$1, selFragment); }\n  }\n  return result\n}\n\n// Draws a cursor for the given range\nfunction drawSelectionCursor(cm, head, output) {\n  var pos = cursorCoords(cm, head, \"div\", null, null, !cm.options.singleCursorHeightPerLine);\n\n  var cursor = output.appendChild(elt(\"div\", \"\\u00a0\", \"CodeMirror-cursor\"));\n  cursor.style.left = pos.left + \"px\";\n  cursor.style.top = pos.top + \"px\";\n  cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + \"px\";\n\n  if (pos.other) {\n    // Secondary cursor, shown when on a 'jump' in bi-directional text\n    var otherCursor = output.appendChild(elt(\"div\", \"\\u00a0\", \"CodeMirror-cursor CodeMirror-secondarycursor\"));\n    otherCursor.style.display = \"\";\n    otherCursor.style.left = pos.other.left + \"px\";\n    otherCursor.style.top = pos.other.top + \"px\";\n    otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + \"px\";\n  }\n}\n\n// Draws the given range as a highlighted selection\nfunction drawSelectionRange(cm, range$$1, output) {\n  var display = cm.display, doc = cm.doc;\n  var fragment = document.createDocumentFragment();\n  var padding = paddingH(cm.display), leftSide = padding.left;\n  var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;\n\n  function add(left, top, width, bottom) {\n    if (top < 0) { top = 0; }\n    top = Math.round(top);\n    bottom = Math.round(bottom);\n    fragment.appendChild(elt(\"div\", null, \"CodeMirror-selected\", (\"position: absolute; left: \" + left + \"px;\\n                             top: \" + top + \"px; width: \" + (width == null ? rightSide - left : width) + \"px;\\n                             height: \" + (bottom - top) + \"px\")));\n  }\n\n  function drawForLine(line, fromArg, toArg) {\n    var lineObj = getLine(doc, line);\n    var lineLen = lineObj.text.length;\n    var start, end;\n    function coords(ch, bias) {\n      return charCoords(cm, Pos(line, ch), \"div\", lineObj, bias)\n    }\n\n    iterateBidiSections(getOrder(lineObj, doc.direction), fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir) {\n      var leftPos = coords(from, \"left\"), rightPos, left, right;\n      if (from == to) {\n        rightPos = leftPos;\n        left = right = leftPos.left;\n      } else {\n        rightPos = coords(to - 1, \"right\");\n        if (dir == \"rtl\") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; }\n        left = leftPos.left;\n        right = rightPos.right;\n      }\n      if (fromArg == null && from == 0) { left = leftSide; }\n      if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part\n        add(left, leftPos.top, null, leftPos.bottom);\n        left = leftSide;\n        if (leftPos.bottom < rightPos.top) { add(left, leftPos.bottom, null, rightPos.top); }\n      }\n      if (toArg == null && to == lineLen) { right = rightSide; }\n      if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)\n        { start = leftPos; }\n      if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)\n        { end = rightPos; }\n      if (left < leftSide + 1) { left = leftSide; }\n      add(left, rightPos.top, right - left, rightPos.bottom);\n    });\n    return {start: start, end: end}\n  }\n\n  var sFrom = range$$1.from(), sTo = range$$1.to();\n  if (sFrom.line == sTo.line) {\n    drawForLine(sFrom.line, sFrom.ch, sTo.ch);\n  } else {\n    var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);\n    var singleVLine = visualLine(fromLine) == visualLine(toLine);\n    var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;\n    var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;\n    if (singleVLine) {\n      if (leftEnd.top < rightStart.top - 2) {\n        add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);\n        add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);\n      } else {\n        add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);\n      }\n    }\n    if (leftEnd.bottom < rightStart.top)\n      { add(leftSide, leftEnd.bottom, null, rightStart.top); }\n  }\n\n  output.appendChild(fragment);\n}\n\n// Cursor-blinking\nfunction restartBlink(cm) {\n  if (!cm.state.focused) { return }\n  var display = cm.display;\n  clearInterval(display.blinker);\n  var on = true;\n  display.cursorDiv.style.visibility = \"\";\n  if (cm.options.cursorBlinkRate > 0)\n    { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? \"\" : \"hidden\"; },\n      cm.options.cursorBlinkRate); }\n  else if (cm.options.cursorBlinkRate < 0)\n    { display.cursorDiv.style.visibility = \"hidden\"; }\n}\n\nfunction ensureFocus(cm) {\n  if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }\n}\n\nfunction delayBlurEvent(cm) {\n  cm.state.delayingBlurEvent = true;\n  setTimeout(function () { if (cm.state.delayingBlurEvent) {\n    cm.state.delayingBlurEvent = false;\n    onBlur(cm);\n  } }, 100);\n}\n\nfunction onFocus(cm, e) {\n  if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; }\n\n  if (cm.options.readOnly == \"nocursor\") { return }\n  if (!cm.state.focused) {\n    signal(cm, \"focus\", cm, e);\n    cm.state.focused = true;\n    addClass(cm.display.wrapper, \"CodeMirror-focused\");\n    // This test prevents this from firing when a context\n    // menu is closed (since the input reset would kill the\n    // select-all detection hack)\n    if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {\n      cm.display.input.reset();\n      if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20); } // Issue #1730\n    }\n    cm.display.input.receivedFocus();\n  }\n  restartBlink(cm);\n}\nfunction onBlur(cm, e) {\n  if (cm.state.delayingBlurEvent) { return }\n\n  if (cm.state.focused) {\n    signal(cm, \"blur\", cm, e);\n    cm.state.focused = false;\n    rmClass(cm.display.wrapper, \"CodeMirror-focused\");\n  }\n  clearInterval(cm.display.blinker);\n  setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false; } }, 150);\n}\n\n// Read the actual heights of the rendered lines, and update their\n// stored heights to match.\nfunction updateHeightsInViewport(cm) {\n  var display = cm.display;\n  var prevBottom = display.lineDiv.offsetTop;\n  for (var i = 0; i < display.view.length; i++) {\n    var cur = display.view[i], height = (void 0);\n    if (cur.hidden) { continue }\n    if (ie && ie_version < 8) {\n      var bot = cur.node.offsetTop + cur.node.offsetHeight;\n      height = bot - prevBottom;\n      prevBottom = bot;\n    } else {\n      var box = cur.node.getBoundingClientRect();\n      height = box.bottom - box.top;\n    }\n    var diff = cur.line.height - height;\n    if (height < 2) { height = textHeight(display); }\n    if (diff > .005 || diff < -.005) {\n      updateLineHeight(cur.line, height);\n      updateWidgetHeight(cur.line);\n      if (cur.rest) { for (var j = 0; j < cur.rest.length; j++)\n        { updateWidgetHeight(cur.rest[j]); } }\n    }\n  }\n}\n\n// Read and store the height of line widgets associated with the\n// given line.\nfunction updateWidgetHeight(line) {\n  if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i)\n    { line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight; } }\n}\n\n// Compute the lines that are visible in a given viewport (defaults\n// the the current scroll position). viewport may contain top,\n// height, and ensure (see op.scrollToPos) properties.\nfunction visibleLines(display, doc, viewport) {\n  var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;\n  top = Math.floor(top - paddingTop(display));\n  var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;\n\n  var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);\n  // Ensure is a {from: {line, ch}, to: {line, ch}} object, and\n  // forces those lines into the viewport (if possible).\n  if (viewport && viewport.ensure) {\n    var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;\n    if (ensureFrom < from) {\n      from = ensureFrom;\n      to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);\n    } else if (Math.min(ensureTo, doc.lastLine()) >= to) {\n      from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);\n      to = ensureTo;\n    }\n  }\n  return {from: from, to: Math.max(to, from + 1)}\n}\n\n// Re-align line numbers and gutter marks to compensate for\n// horizontal scrolling.\nfunction alignHorizontally(cm) {\n  var display = cm.display, view = display.view;\n  if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return }\n  var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;\n  var gutterW = display.gutters.offsetWidth, left = comp + \"px\";\n  for (var i = 0; i < view.length; i++) { if (!view[i].hidden) {\n    if (cm.options.fixedGutter) {\n      if (view[i].gutter)\n        { view[i].gutter.style.left = left; }\n      if (view[i].gutterBackground)\n        { view[i].gutterBackground.style.left = left; }\n    }\n    var align = view[i].alignable;\n    if (align) { for (var j = 0; j < align.length; j++)\n      { align[j].style.left = left; } }\n  } }\n  if (cm.options.fixedGutter)\n    { display.gutters.style.left = (comp + gutterW) + \"px\"; }\n}\n\n// Used to ensure that the line number gutter is still the right\n// size for the current document size. Returns true when an update\n// is needed.\nfunction maybeUpdateLineNumberWidth(cm) {\n  if (!cm.options.lineNumbers) { return false }\n  var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;\n  if (last.length != display.lineNumChars) {\n    var test = display.measure.appendChild(elt(\"div\", [elt(\"div\", last)],\n                                               \"CodeMirror-linenumber CodeMirror-gutter-elt\"));\n    var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;\n    display.lineGutter.style.width = \"\";\n    display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;\n    display.lineNumWidth = display.lineNumInnerWidth + padding;\n    display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;\n    display.lineGutter.style.width = display.lineNumWidth + \"px\";\n    updateGutterSpace(cm);\n    return true\n  }\n  return false\n}\n\n// SCROLLING THINGS INTO VIEW\n\n// If an editor sits on the top or bottom of the window, partially\n// scrolled out of view, this ensures that the cursor is visible.\nfunction maybeScrollWindow(cm, rect) {\n  if (signalDOMEvent(cm, \"scrollCursorIntoView\")) { return }\n\n  var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;\n  if (rect.top + box.top < 0) { doScroll = true; }\n  else if (rect.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false; }\n  if (doScroll != null && !phantom) {\n    var scrollNode = elt(\"div\", \"\\u200b\", null, (\"position: absolute;\\n                         top: \" + (rect.top - display.viewOffset - paddingTop(cm.display)) + \"px;\\n                         height: \" + (rect.bottom - rect.top + scrollGap(cm) + display.barHeight) + \"px;\\n                         left: \" + (rect.left) + \"px; width: \" + (Math.max(2, rect.right - rect.left)) + \"px;\"));\n    cm.display.lineSpace.appendChild(scrollNode);\n    scrollNode.scrollIntoView(doScroll);\n    cm.display.lineSpace.removeChild(scrollNode);\n  }\n}\n\n// Scroll a given position into view (immediately), verifying that\n// it actually became visible (as line heights are accurately\n// measured, the position of something may 'drift' during drawing).\nfunction scrollPosIntoView(cm, pos, end, margin) {\n  if (margin == null) { margin = 0; }\n  var rect;\n  if (!cm.options.lineWrapping && pos == end) {\n    // Set pos and end to the cursor positions around the character pos sticks to\n    // If pos.sticky == \"before\", that is around pos.ch - 1, otherwise around pos.ch\n    // If pos == Pos(_, 0, \"before\"), pos and end are unchanged\n    pos = pos.ch ? Pos(pos.line, pos.sticky == \"before\" ? pos.ch - 1 : pos.ch, \"after\") : pos;\n    end = pos.sticky == \"before\" ? Pos(pos.line, pos.ch + 1, \"before\") : pos;\n  }\n  for (var limit = 0; limit < 5; limit++) {\n    var changed = false;\n    var coords = cursorCoords(cm, pos);\n    var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);\n    rect = {left: Math.min(coords.left, endCoords.left),\n            top: Math.min(coords.top, endCoords.top) - margin,\n            right: Math.max(coords.left, endCoords.left),\n            bottom: Math.max(coords.bottom, endCoords.bottom) + margin};\n    var scrollPos = calculateScrollPos(cm, rect);\n    var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;\n    if (scrollPos.scrollTop != null) {\n      updateScrollTop(cm, scrollPos.scrollTop);\n      if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true; }\n    }\n    if (scrollPos.scrollLeft != null) {\n      setScrollLeft(cm, scrollPos.scrollLeft);\n      if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true; }\n    }\n    if (!changed) { break }\n  }\n  return rect\n}\n\n// Scroll a given set of coordinates into view (immediately).\nfunction scrollIntoView(cm, rect) {\n  var scrollPos = calculateScrollPos(cm, rect);\n  if (scrollPos.scrollTop != null) { updateScrollTop(cm, scrollPos.scrollTop); }\n  if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft); }\n}\n\n// Calculate a new scroll position needed to scroll the given\n// rectangle into view. Returns an object with scrollTop and\n// scrollLeft properties. When these are undefined, the\n// vertical/horizontal position does not need to be adjusted.\nfunction calculateScrollPos(cm, rect) {\n  var display = cm.display, snapMargin = textHeight(cm.display);\n  if (rect.top < 0) { rect.top = 0; }\n  var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;\n  var screen = displayHeight(cm), result = {};\n  if (rect.bottom - rect.top > screen) { rect.bottom = rect.top + screen; }\n  var docBottom = cm.doc.height + paddingVert(display);\n  var atTop = rect.top < snapMargin, atBottom = rect.bottom > docBottom - snapMargin;\n  if (rect.top < screentop) {\n    result.scrollTop = atTop ? 0 : rect.top;\n  } else if (rect.bottom > screentop + screen) {\n    var newTop = Math.min(rect.top, (atBottom ? docBottom : rect.bottom) - screen);\n    if (newTop != screentop) { result.scrollTop = newTop; }\n  }\n\n  var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;\n  var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);\n  var tooWide = rect.right - rect.left > screenw;\n  if (tooWide) { rect.right = rect.left + screenw; }\n  if (rect.left < 10)\n    { result.scrollLeft = 0; }\n  else if (rect.left < screenleft)\n    { result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)); }\n  else if (rect.right > screenw + screenleft - 3)\n    { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw; }\n  return result\n}\n\n// Store a relative adjustment to the scroll position in the current\n// operation (to be applied when the operation finishes).\nfunction addToScrollTop(cm, top) {\n  if (top == null) { return }\n  resolveScrollToPos(cm);\n  cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;\n}\n\n// Make sure that at the end of the operation the current cursor is\n// shown.\nfunction ensureCursorVisible(cm) {\n  resolveScrollToPos(cm);\n  var cur = cm.getCursor();\n  cm.curOp.scrollToPos = {from: cur, to: cur, margin: cm.options.cursorScrollMargin};\n}\n\nfunction scrollToCoords(cm, x, y) {\n  if (x != null || y != null) { resolveScrollToPos(cm); }\n  if (x != null) { cm.curOp.scrollLeft = x; }\n  if (y != null) { cm.curOp.scrollTop = y; }\n}\n\nfunction scrollToRange(cm, range$$1) {\n  resolveScrollToPos(cm);\n  cm.curOp.scrollToPos = range$$1;\n}\n\n// When an operation has its scrollToPos property set, and another\n// scroll action is applied before the end of the operation, this\n// 'simulates' scrolling that position into view in a cheap way, so\n// that the effect of intermediate scroll commands is not ignored.\nfunction resolveScrollToPos(cm) {\n  var range$$1 = cm.curOp.scrollToPos;\n  if (range$$1) {\n    cm.curOp.scrollToPos = null;\n    var from = estimateCoords(cm, range$$1.from), to = estimateCoords(cm, range$$1.to);\n    scrollToCoordsRange(cm, from, to, range$$1.margin);\n  }\n}\n\nfunction scrollToCoordsRange(cm, from, to, margin) {\n  var sPos = calculateScrollPos(cm, {\n    left: Math.min(from.left, to.left),\n    top: Math.min(from.top, to.top) - margin,\n    right: Math.max(from.right, to.right),\n    bottom: Math.max(from.bottom, to.bottom) + margin\n  });\n  scrollToCoords(cm, sPos.scrollLeft, sPos.scrollTop);\n}\n\n// Sync the scrollable area and scrollbars, ensure the viewport\n// covers the visible area.\nfunction updateScrollTop(cm, val) {\n  if (Math.abs(cm.doc.scrollTop - val) < 2) { return }\n  if (!gecko) { updateDisplaySimple(cm, {top: val}); }\n  setScrollTop(cm, val, true);\n  if (gecko) { updateDisplaySimple(cm); }\n  startWorker(cm, 100);\n}\n\nfunction setScrollTop(cm, val, forceScroll) {\n  val = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val);\n  if (cm.display.scroller.scrollTop == val && !forceScroll) { return }\n  cm.doc.scrollTop = val;\n  cm.display.scrollbars.setScrollTop(val);\n  if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val; }\n}\n\n// Sync scroller and scrollbar, ensure the gutter elements are\n// aligned.\nfunction setScrollLeft(cm, val, isScroller, forceScroll) {\n  val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);\n  if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return }\n  cm.doc.scrollLeft = val;\n  alignHorizontally(cm);\n  if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val; }\n  cm.display.scrollbars.setScrollLeft(val);\n}\n\n// SCROLLBARS\n\n// Prepare DOM reads needed to update the scrollbars. Done in one\n// shot to minimize update/measure roundtrips.\nfunction measureForScrollbars(cm) {\n  var d = cm.display, gutterW = d.gutters.offsetWidth;\n  var docH = Math.round(cm.doc.height + paddingVert(cm.display));\n  return {\n    clientHeight: d.scroller.clientHeight,\n    viewHeight: d.wrapper.clientHeight,\n    scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,\n    viewWidth: d.wrapper.clientWidth,\n    barLeft: cm.options.fixedGutter ? gutterW : 0,\n    docHeight: docH,\n    scrollHeight: docH + scrollGap(cm) + d.barHeight,\n    nativeBarWidth: d.nativeBarWidth,\n    gutterWidth: gutterW\n  }\n}\n\nvar NativeScrollbars = function(place, scroll, cm) {\n  this.cm = cm;\n  var vert = this.vert = elt(\"div\", [elt(\"div\", null, null, \"min-width: 1px\")], \"CodeMirror-vscrollbar\");\n  var horiz = this.horiz = elt(\"div\", [elt(\"div\", null, null, \"height: 100%; min-height: 1px\")], \"CodeMirror-hscrollbar\");\n  place(vert); place(horiz);\n\n  on(vert, \"scroll\", function () {\n    if (vert.clientHeight) { scroll(vert.scrollTop, \"vertical\"); }\n  });\n  on(horiz, \"scroll\", function () {\n    if (horiz.clientWidth) { scroll(horiz.scrollLeft, \"horizontal\"); }\n  });\n\n  this.checkedZeroWidth = false;\n  // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).\n  if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = \"18px\"; }\n};\n\nNativeScrollbars.prototype.update = function (measure) {\n  var needsH = measure.scrollWidth > measure.clientWidth + 1;\n  var needsV = measure.scrollHeight > measure.clientHeight + 1;\n  var sWidth = measure.nativeBarWidth;\n\n  if (needsV) {\n    this.vert.style.display = \"block\";\n    this.vert.style.bottom = needsH ? sWidth + \"px\" : \"0\";\n    var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);\n    // A bug in IE8 can cause this value to be negative, so guard it.\n    this.vert.firstChild.style.height =\n      Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + \"px\";\n  } else {\n    this.vert.style.display = \"\";\n    this.vert.firstChild.style.height = \"0\";\n  }\n\n  if (needsH) {\n    this.horiz.style.display = \"block\";\n    this.horiz.style.right = needsV ? sWidth + \"px\" : \"0\";\n    this.horiz.style.left = measure.barLeft + \"px\";\n    var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);\n    this.horiz.firstChild.style.width =\n      Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + \"px\";\n  } else {\n    this.horiz.style.display = \"\";\n    this.horiz.firstChild.style.width = \"0\";\n  }\n\n  if (!this.checkedZeroWidth && measure.clientHeight > 0) {\n    if (sWidth == 0) { this.zeroWidthHack(); }\n    this.checkedZeroWidth = true;\n  }\n\n  return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}\n};\n\nNativeScrollbars.prototype.setScrollLeft = function (pos) {\n  if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos; }\n  if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz, \"horiz\"); }\n};\n\nNativeScrollbars.prototype.setScrollTop = function (pos) {\n  if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos; }\n  if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert, \"vert\"); }\n};\n\nNativeScrollbars.prototype.zeroWidthHack = function () {\n  var w = mac && !mac_geMountainLion ? \"12px\" : \"18px\";\n  this.horiz.style.height = this.vert.style.width = w;\n  this.horiz.style.pointerEvents = this.vert.style.pointerEvents = \"none\";\n  this.disableHoriz = new Delayed;\n  this.disableVert = new Delayed;\n};\n\nNativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay, type) {\n  bar.style.pointerEvents = \"auto\";\n  function maybeDisable() {\n    // To find out whether the scrollbar is still visible, we\n    // check whether the element under the pixel in the bottom\n    // right corner of the scrollbar box is the scrollbar box\n    // itself (when the bar is still visible) or its filler child\n    // (when the bar is hidden). If it is still visible, we keep\n    // it enabled, if it's hidden, we disable pointer events.\n    var box = bar.getBoundingClientRect();\n    var elt$$1 = type == \"vert\" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2)\n        : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1);\n    if (elt$$1 != bar) { bar.style.pointerEvents = \"none\"; }\n    else { delay.set(1000, maybeDisable); }\n  }\n  delay.set(1000, maybeDisable);\n};\n\nNativeScrollbars.prototype.clear = function () {\n  var parent = this.horiz.parentNode;\n  parent.removeChild(this.horiz);\n  parent.removeChild(this.vert);\n};\n\nvar NullScrollbars = function () {};\n\nNullScrollbars.prototype.update = function () { return {bottom: 0, right: 0} };\nNullScrollbars.prototype.setScrollLeft = function () {};\nNullScrollbars.prototype.setScrollTop = function () {};\nNullScrollbars.prototype.clear = function () {};\n\nfunction updateScrollbars(cm, measure) {\n  if (!measure) { measure = measureForScrollbars(cm); }\n  var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;\n  updateScrollbarsInner(cm, measure);\n  for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {\n    if (startWidth != cm.display.barWidth && cm.options.lineWrapping)\n      { updateHeightsInViewport(cm); }\n    updateScrollbarsInner(cm, measureForScrollbars(cm));\n    startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;\n  }\n}\n\n// Re-synchronize the fake scrollbars with the actual size of the\n// content.\nfunction updateScrollbarsInner(cm, measure) {\n  var d = cm.display;\n  var sizes = d.scrollbars.update(measure);\n\n  d.sizer.style.paddingRight = (d.barWidth = sizes.right) + \"px\";\n  d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + \"px\";\n  d.heightForcer.style.borderBottom = sizes.bottom + \"px solid transparent\";\n\n  if (sizes.right && sizes.bottom) {\n    d.scrollbarFiller.style.display = \"block\";\n    d.scrollbarFiller.style.height = sizes.bottom + \"px\";\n    d.scrollbarFiller.style.width = sizes.right + \"px\";\n  } else { d.scrollbarFiller.style.display = \"\"; }\n  if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {\n    d.gutterFiller.style.display = \"block\";\n    d.gutterFiller.style.height = sizes.bottom + \"px\";\n    d.gutterFiller.style.width = measure.gutterWidth + \"px\";\n  } else { d.gutterFiller.style.display = \"\"; }\n}\n\nvar scrollbarModel = {\"native\": NativeScrollbars, \"null\": NullScrollbars};\n\nfunction initScrollbars(cm) {\n  if (cm.display.scrollbars) {\n    cm.display.scrollbars.clear();\n    if (cm.display.scrollbars.addClass)\n      { rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); }\n  }\n\n  cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) {\n    cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);\n    // Prevent clicks in the scrollbars from killing focus\n    on(node, \"mousedown\", function () {\n      if (cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0); }\n    });\n    node.setAttribute(\"cm-not-content\", \"true\");\n  }, function (pos, axis) {\n    if (axis == \"horizontal\") { setScrollLeft(cm, pos); }\n    else { updateScrollTop(cm, pos); }\n  }, cm);\n  if (cm.display.scrollbars.addClass)\n    { addClass(cm.display.wrapper, cm.display.scrollbars.addClass); }\n}\n\n// Operations are used to wrap a series of changes to the editor\n// state in such a way that each change won't have to update the\n// cursor and display (which would be awkward, slow, and\n// error-prone). Instead, display updates are batched and then all\n// combined and executed at once.\n\nvar nextOpId = 0;\n// Start a new operation.\nfunction startOperation(cm) {\n  cm.curOp = {\n    cm: cm,\n    viewChanged: false,      // Flag that indicates that lines might need to be redrawn\n    startHeight: cm.doc.height, // Used to detect need to update scrollbar\n    forceUpdate: false,      // Used to force a redraw\n    updateInput: null,       // Whether to reset the input textarea\n    typing: false,           // Whether this reset should be careful to leave existing text (for compositing)\n    changeObjs: null,        // Accumulated changes, for firing change events\n    cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on\n    cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already\n    selectionChanged: false, // Whether the selection needs to be redrawn\n    updateMaxLine: false,    // Set when the widest line needs to be determined anew\n    scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet\n    scrollToPos: null,       // Used to scroll to a specific position\n    focus: false,\n    id: ++nextOpId           // Unique ID\n  };\n  pushOperation(cm.curOp);\n}\n\n// Finish an operation, updating the display and signalling delayed events\nfunction endOperation(cm) {\n  var op = cm.curOp;\n  finishOperation(op, function (group) {\n    for (var i = 0; i < group.ops.length; i++)\n      { group.ops[i].cm.curOp = null; }\n    endOperations(group);\n  });\n}\n\n// The DOM updates done when an operation finishes are batched so\n// that the minimum number of relayouts are required.\nfunction endOperations(group) {\n  var ops = group.ops;\n  for (var i = 0; i < ops.length; i++) // Read DOM\n    { endOperation_R1(ops[i]); }\n  for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe)\n    { endOperation_W1(ops[i$1]); }\n  for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM\n    { endOperation_R2(ops[i$2]); }\n  for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe)\n    { endOperation_W2(ops[i$3]); }\n  for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM\n    { endOperation_finish(ops[i$4]); }\n}\n\nfunction endOperation_R1(op) {\n  var cm = op.cm, display = cm.display;\n  maybeClipScrollbars(cm);\n  if (op.updateMaxLine) { findMaxLine(cm); }\n\n  op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||\n    op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||\n                       op.scrollToPos.to.line >= display.viewTo) ||\n    display.maxLineChanged && cm.options.lineWrapping;\n  op.update = op.mustUpdate &&\n    new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);\n}\n\nfunction endOperation_W1(op) {\n  op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);\n}\n\nfunction endOperation_R2(op) {\n  var cm = op.cm, display = cm.display;\n  if (op.updatedDisplay) { updateHeightsInViewport(cm); }\n\n  op.barMeasure = measureForScrollbars(cm);\n\n  // If the max line changed since it was last measured, measure it,\n  // and ensure the document's width matches it.\n  // updateDisplay_W2 will use these properties to do the actual resizing\n  if (display.maxLineChanged && !cm.options.lineWrapping) {\n    op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;\n    cm.display.sizerWidth = op.adjustWidthTo;\n    op.barMeasure.scrollWidth =\n      Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);\n    op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));\n  }\n\n  if (op.updatedDisplay || op.selectionChanged)\n    { op.preparedSelection = display.input.prepareSelection(op.focus); }\n}\n\nfunction endOperation_W2(op) {\n  var cm = op.cm;\n\n  if (op.adjustWidthTo != null) {\n    cm.display.sizer.style.minWidth = op.adjustWidthTo + \"px\";\n    if (op.maxScrollLeft < cm.doc.scrollLeft)\n      { setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); }\n    cm.display.maxLineChanged = false;\n  }\n\n  var takeFocus = op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus());\n  if (op.preparedSelection)\n    { cm.display.input.showSelection(op.preparedSelection, takeFocus); }\n  if (op.updatedDisplay || op.startHeight != cm.doc.height)\n    { updateScrollbars(cm, op.barMeasure); }\n  if (op.updatedDisplay)\n    { setDocumentHeight(cm, op.barMeasure); }\n\n  if (op.selectionChanged) { restartBlink(cm); }\n\n  if (cm.state.focused && op.updateInput)\n    { cm.display.input.reset(op.typing); }\n  if (takeFocus) { ensureFocus(op.cm); }\n}\n\nfunction endOperation_finish(op) {\n  var cm = op.cm, display = cm.display, doc = cm.doc;\n\n  if (op.updatedDisplay) { postUpdateDisplay(cm, op.update); }\n\n  // Abort mouse wheel delta measurement, when scrolling explicitly\n  if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))\n    { display.wheelStartX = display.wheelStartY = null; }\n\n  // Propagate the scroll position to the actual DOM scroller\n  if (op.scrollTop != null) { setScrollTop(cm, op.scrollTop, op.forceScroll); }\n\n  if (op.scrollLeft != null) { setScrollLeft(cm, op.scrollLeft, true, true); }\n  // If we need to scroll a specific position into view, do so.\n  if (op.scrollToPos) {\n    var rect = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),\n                                 clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);\n    maybeScrollWindow(cm, rect);\n  }\n\n  // Fire events for markers that are hidden/unidden by editing or\n  // undoing\n  var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;\n  if (hidden) { for (var i = 0; i < hidden.length; ++i)\n    { if (!hidden[i].lines.length) { signal(hidden[i], \"hide\"); } } }\n  if (unhidden) { for (var i$1 = 0; i$1 < unhidden.length; ++i$1)\n    { if (unhidden[i$1].lines.length) { signal(unhidden[i$1], \"unhide\"); } } }\n\n  if (display.wrapper.offsetHeight)\n    { doc.scrollTop = cm.display.scroller.scrollTop; }\n\n  // Fire change events, and delayed event handlers\n  if (op.changeObjs)\n    { signal(cm, \"changes\", cm, op.changeObjs); }\n  if (op.update)\n    { op.update.finish(); }\n}\n\n// Run the given function in an operation\nfunction runInOp(cm, f) {\n  if (cm.curOp) { return f() }\n  startOperation(cm);\n  try { return f() }\n  finally { endOperation(cm); }\n}\n// Wraps a function in an operation. Returns the wrapped function.\nfunction operation(cm, f) {\n  return function() {\n    if (cm.curOp) { return f.apply(cm, arguments) }\n    startOperation(cm);\n    try { return f.apply(cm, arguments) }\n    finally { endOperation(cm); }\n  }\n}\n// Used to add methods to editor and doc instances, wrapping them in\n// operations.\nfunction methodOp(f) {\n  return function() {\n    if (this.curOp) { return f.apply(this, arguments) }\n    startOperation(this);\n    try { return f.apply(this, arguments) }\n    finally { endOperation(this); }\n  }\n}\nfunction docMethodOp(f) {\n  return function() {\n    var cm = this.cm;\n    if (!cm || cm.curOp) { return f.apply(this, arguments) }\n    startOperation(cm);\n    try { return f.apply(this, arguments) }\n    finally { endOperation(cm); }\n  }\n}\n\n// Updates the display.view data structure for a given change to the\n// document. From and to are in pre-change coordinates. Lendiff is\n// the amount of lines added or subtracted by the change. This is\n// used for changes that span multiple lines, or change the way\n// lines are divided into visual lines. regLineChange (below)\n// registers single-line changes.\nfunction regChange(cm, from, to, lendiff) {\n  if (from == null) { from = cm.doc.first; }\n  if (to == null) { to = cm.doc.first + cm.doc.size; }\n  if (!lendiff) { lendiff = 0; }\n\n  var display = cm.display;\n  if (lendiff && to < display.viewTo &&\n      (display.updateLineNumbers == null || display.updateLineNumbers > from))\n    { display.updateLineNumbers = from; }\n\n  cm.curOp.viewChanged = true;\n\n  if (from >= display.viewTo) { // Change after\n    if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)\n      { resetView(cm); }\n  } else if (to <= display.viewFrom) { // Change before\n    if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {\n      resetView(cm);\n    } else {\n      display.viewFrom += lendiff;\n      display.viewTo += lendiff;\n    }\n  } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap\n    resetView(cm);\n  } else if (from <= display.viewFrom) { // Top overlap\n    var cut = viewCuttingPoint(cm, to, to + lendiff, 1);\n    if (cut) {\n      display.view = display.view.slice(cut.index);\n      display.viewFrom = cut.lineN;\n      display.viewTo += lendiff;\n    } else {\n      resetView(cm);\n    }\n  } else if (to >= display.viewTo) { // Bottom overlap\n    var cut$1 = viewCuttingPoint(cm, from, from, -1);\n    if (cut$1) {\n      display.view = display.view.slice(0, cut$1.index);\n      display.viewTo = cut$1.lineN;\n    } else {\n      resetView(cm);\n    }\n  } else { // Gap in the middle\n    var cutTop = viewCuttingPoint(cm, from, from, -1);\n    var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);\n    if (cutTop && cutBot) {\n      display.view = display.view.slice(0, cutTop.index)\n        .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))\n        .concat(display.view.slice(cutBot.index));\n      display.viewTo += lendiff;\n    } else {\n      resetView(cm);\n    }\n  }\n\n  var ext = display.externalMeasured;\n  if (ext) {\n    if (to < ext.lineN)\n      { ext.lineN += lendiff; }\n    else if (from < ext.lineN + ext.size)\n      { display.externalMeasured = null; }\n  }\n}\n\n// Register a change to a single line. Type must be one of \"text\",\n// \"gutter\", \"class\", \"widget\"\nfunction regLineChange(cm, line, type) {\n  cm.curOp.viewChanged = true;\n  var display = cm.display, ext = cm.display.externalMeasured;\n  if (ext && line >= ext.lineN && line < ext.lineN + ext.size)\n    { display.externalMeasured = null; }\n\n  if (line < display.viewFrom || line >= display.viewTo) { return }\n  var lineView = display.view[findViewIndex(cm, line)];\n  if (lineView.node == null) { return }\n  var arr = lineView.changes || (lineView.changes = []);\n  if (indexOf(arr, type) == -1) { arr.push(type); }\n}\n\n// Clear the view.\nfunction resetView(cm) {\n  cm.display.viewFrom = cm.display.viewTo = cm.doc.first;\n  cm.display.view = [];\n  cm.display.viewOffset = 0;\n}\n\nfunction viewCuttingPoint(cm, oldN, newN, dir) {\n  var index = findViewIndex(cm, oldN), diff, view = cm.display.view;\n  if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)\n    { return {index: index, lineN: newN} }\n  var n = cm.display.viewFrom;\n  for (var i = 0; i < index; i++)\n    { n += view[i].size; }\n  if (n != oldN) {\n    if (dir > 0) {\n      if (index == view.length - 1) { return null }\n      diff = (n + view[index].size) - oldN;\n      index++;\n    } else {\n      diff = n - oldN;\n    }\n    oldN += diff; newN += diff;\n  }\n  while (visualLineNo(cm.doc, newN) != newN) {\n    if (index == (dir < 0 ? 0 : view.length - 1)) { return null }\n    newN += dir * view[index - (dir < 0 ? 1 : 0)].size;\n    index += dir;\n  }\n  return {index: index, lineN: newN}\n}\n\n// Force the view to cover a given range, adding empty view element\n// or clipping off existing ones as needed.\nfunction adjustView(cm, from, to) {\n  var display = cm.display, view = display.view;\n  if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {\n    display.view = buildViewArray(cm, from, to);\n    display.viewFrom = from;\n  } else {\n    if (display.viewFrom > from)\n      { display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); }\n    else if (display.viewFrom < from)\n      { display.view = display.view.slice(findViewIndex(cm, from)); }\n    display.viewFrom = from;\n    if (display.viewTo < to)\n      { display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); }\n    else if (display.viewTo > to)\n      { display.view = display.view.slice(0, findViewIndex(cm, to)); }\n  }\n  display.viewTo = to;\n}\n\n// Count the number of lines in the view whose DOM representation is\n// out of date (or nonexistent).\nfunction countDirtyView(cm) {\n  var view = cm.display.view, dirty = 0;\n  for (var i = 0; i < view.length; i++) {\n    var lineView = view[i];\n    if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty; }\n  }\n  return dirty\n}\n\n// HIGHLIGHT WORKER\n\nfunction startWorker(cm, time) {\n  if (cm.doc.highlightFrontier < cm.display.viewTo)\n    { cm.state.highlight.set(time, bind(highlightWorker, cm)); }\n}\n\nfunction highlightWorker(cm) {\n  var doc = cm.doc;\n  if (doc.highlightFrontier >= cm.display.viewTo) { return }\n  var end = +new Date + cm.options.workTime;\n  var context = getContextBefore(cm, doc.highlightFrontier);\n  var changedLines = [];\n\n  doc.iter(context.line, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) {\n    if (context.line >= cm.display.viewFrom) { // Visible\n      var oldStyles = line.styles;\n      var resetState = line.text.length > cm.options.maxHighlightLength ? copyState(doc.mode, context.state) : null;\n      var highlighted = highlightLine(cm, line, context, true);\n      if (resetState) { context.state = resetState; }\n      line.styles = highlighted.styles;\n      var oldCls = line.styleClasses, newCls = highlighted.classes;\n      if (newCls) { line.styleClasses = newCls; }\n      else if (oldCls) { line.styleClasses = null; }\n      var ischange = !oldStyles || oldStyles.length != line.styles.length ||\n        oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);\n      for (var i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i]; }\n      if (ischange) { changedLines.push(context.line); }\n      line.stateAfter = context.save();\n      context.nextLine();\n    } else {\n      if (line.text.length <= cm.options.maxHighlightLength)\n        { processLine(cm, line.text, context); }\n      line.stateAfter = context.line % 5 == 0 ? context.save() : null;\n      context.nextLine();\n    }\n    if (+new Date > end) {\n      startWorker(cm, cm.options.workDelay);\n      return true\n    }\n  });\n  doc.highlightFrontier = context.line;\n  doc.modeFrontier = Math.max(doc.modeFrontier, context.line);\n  if (changedLines.length) { runInOp(cm, function () {\n    for (var i = 0; i < changedLines.length; i++)\n      { regLineChange(cm, changedLines[i], \"text\"); }\n  }); }\n}\n\n// DISPLAY DRAWING\n\nvar DisplayUpdate = function(cm, viewport, force) {\n  var display = cm.display;\n\n  this.viewport = viewport;\n  // Store some values that we'll need later (but don't want to force a relayout for)\n  this.visible = visibleLines(display, cm.doc, viewport);\n  this.editorIsHidden = !display.wrapper.offsetWidth;\n  this.wrapperHeight = display.wrapper.clientHeight;\n  this.wrapperWidth = display.wrapper.clientWidth;\n  this.oldDisplayWidth = displayWidth(cm);\n  this.force = force;\n  this.dims = getDimensions(cm);\n  this.events = [];\n};\n\nDisplayUpdate.prototype.signal = function (emitter, type) {\n  if (hasHandler(emitter, type))\n    { this.events.push(arguments); }\n};\nDisplayUpdate.prototype.finish = function () {\n    var this$1 = this;\n\n  for (var i = 0; i < this.events.length; i++)\n    { signal.apply(null, this$1.events[i]); }\n};\n\nfunction maybeClipScrollbars(cm) {\n  var display = cm.display;\n  if (!display.scrollbarsClipped && display.scroller.offsetWidth) {\n    display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;\n    display.heightForcer.style.height = scrollGap(cm) + \"px\";\n    display.sizer.style.marginBottom = -display.nativeBarWidth + \"px\";\n    display.sizer.style.borderRightWidth = scrollGap(cm) + \"px\";\n    display.scrollbarsClipped = true;\n  }\n}\n\nfunction selectionSnapshot(cm) {\n  if (cm.hasFocus()) { return null }\n  var active = activeElt();\n  if (!active || !contains(cm.display.lineDiv, active)) { return null }\n  var result = {activeElt: active};\n  if (window.getSelection) {\n    var sel = window.getSelection();\n    if (sel.anchorNode && sel.extend && contains(cm.display.lineDiv, sel.anchorNode)) {\n      result.anchorNode = sel.anchorNode;\n      result.anchorOffset = sel.anchorOffset;\n      result.focusNode = sel.focusNode;\n      result.focusOffset = sel.focusOffset;\n    }\n  }\n  return result\n}\n\nfunction restoreSelection(snapshot) {\n  if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return }\n  snapshot.activeElt.focus();\n  if (snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) {\n    var sel = window.getSelection(), range$$1 = document.createRange();\n    range$$1.setEnd(snapshot.anchorNode, snapshot.anchorOffset);\n    range$$1.collapse(false);\n    sel.removeAllRanges();\n    sel.addRange(range$$1);\n    sel.extend(snapshot.focusNode, snapshot.focusOffset);\n  }\n}\n\n// Does the actual updating of the line display. Bails out\n// (returning false) when there is nothing to be done and forced is\n// false.\nfunction updateDisplayIfNeeded(cm, update) {\n  var display = cm.display, doc = cm.doc;\n\n  if (update.editorIsHidden) {\n    resetView(cm);\n    return false\n  }\n\n  // Bail out if the visible area is already rendered and nothing changed.\n  if (!update.force &&\n      update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&\n      (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&\n      display.renderedView == display.view && countDirtyView(cm) == 0)\n    { return false }\n\n  if (maybeUpdateLineNumberWidth(cm)) {\n    resetView(cm);\n    update.dims = getDimensions(cm);\n  }\n\n  // Compute a suitable new viewport (from & to)\n  var end = doc.first + doc.size;\n  var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);\n  var to = Math.min(end, update.visible.to + cm.options.viewportMargin);\n  if (display.viewFrom < from && from - display.viewFrom < 20) { from = Math.max(doc.first, display.viewFrom); }\n  if (display.viewTo > to && display.viewTo - to < 20) { to = Math.min(end, display.viewTo); }\n  if (sawCollapsedSpans) {\n    from = visualLineNo(cm.doc, from);\n    to = visualLineEndNo(cm.doc, to);\n  }\n\n  var different = from != display.viewFrom || to != display.viewTo ||\n    display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;\n  adjustView(cm, from, to);\n\n  display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));\n  // Position the mover div to align with the current scroll position\n  cm.display.mover.style.top = display.viewOffset + \"px\";\n\n  var toUpdate = countDirtyView(cm);\n  if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&\n      (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))\n    { return false }\n\n  // For big changes, we hide the enclosing element during the\n  // update, since that speeds up the operations on most browsers.\n  var selSnapshot = selectionSnapshot(cm);\n  if (toUpdate > 4) { display.lineDiv.style.display = \"none\"; }\n  patchDisplay(cm, display.updateLineNumbers, update.dims);\n  if (toUpdate > 4) { display.lineDiv.style.display = \"\"; }\n  display.renderedView = display.view;\n  // There might have been a widget with a focused element that got\n  // hidden or updated, if so re-focus it.\n  restoreSelection(selSnapshot);\n\n  // Prevent selection and cursors from interfering with the scroll\n  // width and height.\n  removeChildren(display.cursorDiv);\n  removeChildren(display.selectionDiv);\n  display.gutters.style.height = display.sizer.style.minHeight = 0;\n\n  if (different) {\n    display.lastWrapHeight = update.wrapperHeight;\n    display.lastWrapWidth = update.wrapperWidth;\n    startWorker(cm, 400);\n  }\n\n  display.updateLineNumbers = null;\n\n  return true\n}\n\nfunction postUpdateDisplay(cm, update) {\n  var viewport = update.viewport;\n\n  for (var first = true;; first = false) {\n    if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {\n      // Clip forced viewport to actual scrollable area.\n      if (viewport && viewport.top != null)\n        { viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; }\n      // Updated line heights might result in the drawn area not\n      // actually covering the viewport. Keep looping until it does.\n      update.visible = visibleLines(cm.display, cm.doc, viewport);\n      if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)\n        { break }\n    }\n    if (!updateDisplayIfNeeded(cm, update)) { break }\n    updateHeightsInViewport(cm);\n    var barMeasure = measureForScrollbars(cm);\n    updateSelection(cm);\n    updateScrollbars(cm, barMeasure);\n    setDocumentHeight(cm, barMeasure);\n    update.force = false;\n  }\n\n  update.signal(cm, \"update\", cm);\n  if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {\n    update.signal(cm, \"viewportChange\", cm, cm.display.viewFrom, cm.display.viewTo);\n    cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;\n  }\n}\n\nfunction updateDisplaySimple(cm, viewport) {\n  var update = new DisplayUpdate(cm, viewport);\n  if (updateDisplayIfNeeded(cm, update)) {\n    updateHeightsInViewport(cm);\n    postUpdateDisplay(cm, update);\n    var barMeasure = measureForScrollbars(cm);\n    updateSelection(cm);\n    updateScrollbars(cm, barMeasure);\n    setDocumentHeight(cm, barMeasure);\n    update.finish();\n  }\n}\n\n// Sync the actual display DOM structure with display.view, removing\n// nodes for lines that are no longer in view, and creating the ones\n// that are not there yet, and updating the ones that are out of\n// date.\nfunction patchDisplay(cm, updateNumbersFrom, dims) {\n  var display = cm.display, lineNumbers = cm.options.lineNumbers;\n  var container = display.lineDiv, cur = container.firstChild;\n\n  function rm(node) {\n    var next = node.nextSibling;\n    // Works around a throw-scroll bug in OS X Webkit\n    if (webkit && mac && cm.display.currentWheelTarget == node)\n      { node.style.display = \"none\"; }\n    else\n      { node.parentNode.removeChild(node); }\n    return next\n  }\n\n  var view = display.view, lineN = display.viewFrom;\n  // Loop over the elements in the view, syncing cur (the DOM nodes\n  // in display.lineDiv) with the view as we go.\n  for (var i = 0; i < view.length; i++) {\n    var lineView = view[i];\n    if (lineView.hidden) {\n    } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet\n      var node = buildLineElement(cm, lineView, lineN, dims);\n      container.insertBefore(node, cur);\n    } else { // Already drawn\n      while (cur != lineView.node) { cur = rm(cur); }\n      var updateNumber = lineNumbers && updateNumbersFrom != null &&\n        updateNumbersFrom <= lineN && lineView.lineNumber;\n      if (lineView.changes) {\n        if (indexOf(lineView.changes, \"gutter\") > -1) { updateNumber = false; }\n        updateLineForChanges(cm, lineView, lineN, dims);\n      }\n      if (updateNumber) {\n        removeChildren(lineView.lineNumber);\n        lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));\n      }\n      cur = lineView.node.nextSibling;\n    }\n    lineN += lineView.size;\n  }\n  while (cur) { cur = rm(cur); }\n}\n\nfunction updateGutterSpace(cm) {\n  var width = cm.display.gutters.offsetWidth;\n  cm.display.sizer.style.marginLeft = width + \"px\";\n}\n\nfunction setDocumentHeight(cm, measure) {\n  cm.display.sizer.style.minHeight = measure.docHeight + \"px\";\n  cm.display.heightForcer.style.top = measure.docHeight + \"px\";\n  cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + \"px\";\n}\n\n// Rebuild the gutter elements, ensure the margin to the left of the\n// code matches their width.\nfunction updateGutters(cm) {\n  var gutters = cm.display.gutters, specs = cm.options.gutters;\n  removeChildren(gutters);\n  var i = 0;\n  for (; i < specs.length; ++i) {\n    var gutterClass = specs[i];\n    var gElt = gutters.appendChild(elt(\"div\", null, \"CodeMirror-gutter \" + gutterClass));\n    if (gutterClass == \"CodeMirror-linenumbers\") {\n      cm.display.lineGutter = gElt;\n      gElt.style.width = (cm.display.lineNumWidth || 1) + \"px\";\n    }\n  }\n  gutters.style.display = i ? \"\" : \"none\";\n  updateGutterSpace(cm);\n}\n\n// Make sure the gutters options contains the element\n// \"CodeMirror-linenumbers\" when the lineNumbers option is true.\nfunction setGuttersForLineNumbers(options) {\n  var found = indexOf(options.gutters, \"CodeMirror-linenumbers\");\n  if (found == -1 && options.lineNumbers) {\n    options.gutters = options.gutters.concat([\"CodeMirror-linenumbers\"]);\n  } else if (found > -1 && !options.lineNumbers) {\n    options.gutters = options.gutters.slice(0);\n    options.gutters.splice(found, 1);\n  }\n}\n\n// Since the delta values reported on mouse wheel events are\n// unstandardized between browsers and even browser versions, and\n// generally horribly unpredictable, this code starts by measuring\n// the scroll effect that the first few mouse wheel events have,\n// and, from that, detects the way it can convert deltas to pixel\n// offsets afterwards.\n//\n// The reason we want to know the amount a wheel event will scroll\n// is that it gives us a chance to update the display before the\n// actual scrolling happens, reducing flickering.\n\nvar wheelSamples = 0;\nvar wheelPixelsPerUnit = null;\n// Fill in a browser-detected starting value on browsers where we\n// know one. These don't have to be accurate -- the result of them\n// being wrong would just be a slight flicker on the first wheel\n// scroll (if it is large enough).\nif (ie) { wheelPixelsPerUnit = -.53; }\nelse if (gecko) { wheelPixelsPerUnit = 15; }\nelse if (chrome) { wheelPixelsPerUnit = -.7; }\nelse if (safari) { wheelPixelsPerUnit = -1/3; }\n\nfunction wheelEventDelta(e) {\n  var dx = e.wheelDeltaX, dy = e.wheelDeltaY;\n  if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) { dx = e.detail; }\n  if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) { dy = e.detail; }\n  else if (dy == null) { dy = e.wheelDelta; }\n  return {x: dx, y: dy}\n}\nfunction wheelEventPixels(e) {\n  var delta = wheelEventDelta(e);\n  delta.x *= wheelPixelsPerUnit;\n  delta.y *= wheelPixelsPerUnit;\n  return delta\n}\n\nfunction onScrollWheel(cm, e) {\n  var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;\n\n  var display = cm.display, scroll = display.scroller;\n  // Quit if there's nothing to scroll here\n  var canScrollX = scroll.scrollWidth > scroll.clientWidth;\n  var canScrollY = scroll.scrollHeight > scroll.clientHeight;\n  if (!(dx && canScrollX || dy && canScrollY)) { return }\n\n  // Webkit browsers on OS X abort momentum scrolls when the target\n  // of the scroll event is removed from the scrollable element.\n  // This hack (see related code in patchDisplay) makes sure the\n  // element is kept around.\n  if (dy && mac && webkit) {\n    outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {\n      for (var i = 0; i < view.length; i++) {\n        if (view[i].node == cur) {\n          cm.display.currentWheelTarget = cur;\n          break outer\n        }\n      }\n    }\n  }\n\n  // On some browsers, horizontal scrolling will cause redraws to\n  // happen before the gutter has been realigned, causing it to\n  // wriggle around in a most unseemly way. When we have an\n  // estimated pixels/delta value, we just handle horizontal\n  // scrolling entirely here. It'll be slightly off from native, but\n  // better than glitching out.\n  if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {\n    if (dy && canScrollY)\n      { updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * wheelPixelsPerUnit)); }\n    setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * wheelPixelsPerUnit));\n    // Only prevent default scrolling if vertical scrolling is\n    // actually possible. Otherwise, it causes vertical scroll\n    // jitter on OSX trackpads when deltaX is small and deltaY\n    // is large (issue #3579)\n    if (!dy || (dy && canScrollY))\n      { e_preventDefault(e); }\n    display.wheelStartX = null; // Abort measurement, if in progress\n    return\n  }\n\n  // 'Project' the visible viewport to cover the area that is being\n  // scrolled into view (if we know enough to estimate it).\n  if (dy && wheelPixelsPerUnit != null) {\n    var pixels = dy * wheelPixelsPerUnit;\n    var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;\n    if (pixels < 0) { top = Math.max(0, top + pixels - 50); }\n    else { bot = Math.min(cm.doc.height, bot + pixels + 50); }\n    updateDisplaySimple(cm, {top: top, bottom: bot});\n  }\n\n  if (wheelSamples < 20) {\n    if (display.wheelStartX == null) {\n      display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;\n      display.wheelDX = dx; display.wheelDY = dy;\n      setTimeout(function () {\n        if (display.wheelStartX == null) { return }\n        var movedX = scroll.scrollLeft - display.wheelStartX;\n        var movedY = scroll.scrollTop - display.wheelStartY;\n        var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||\n          (movedX && display.wheelDX && movedX / display.wheelDX);\n        display.wheelStartX = display.wheelStartY = null;\n        if (!sample) { return }\n        wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);\n        ++wheelSamples;\n      }, 200);\n    } else {\n      display.wheelDX += dx; display.wheelDY += dy;\n    }\n  }\n}\n\n// Selection objects are immutable. A new one is created every time\n// the selection changes. A selection is one or more non-overlapping\n// (and non-touching) ranges, sorted, and an integer that indicates\n// which one is the primary selection (the one that's scrolled into\n// view, that getCursor returns, etc).\nvar Selection = function(ranges, primIndex) {\n  this.ranges = ranges;\n  this.primIndex = primIndex;\n};\n\nSelection.prototype.primary = function () { return this.ranges[this.primIndex] };\n\nSelection.prototype.equals = function (other) {\n    var this$1 = this;\n\n  if (other == this) { return true }\n  if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false }\n  for (var i = 0; i < this.ranges.length; i++) {\n    var here = this$1.ranges[i], there = other.ranges[i];\n    if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false }\n  }\n  return true\n};\n\nSelection.prototype.deepCopy = function () {\n    var this$1 = this;\n\n  var out = [];\n  for (var i = 0; i < this.ranges.length; i++)\n    { out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)); }\n  return new Selection(out, this.primIndex)\n};\n\nSelection.prototype.somethingSelected = function () {\n    var this$1 = this;\n\n  for (var i = 0; i < this.ranges.length; i++)\n    { if (!this$1.ranges[i].empty()) { return true } }\n  return false\n};\n\nSelection.prototype.contains = function (pos, end) {\n    var this$1 = this;\n\n  if (!end) { end = pos; }\n  for (var i = 0; i < this.ranges.length; i++) {\n    var range = this$1.ranges[i];\n    if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)\n      { return i }\n  }\n  return -1\n};\n\nvar Range = function(anchor, head) {\n  this.anchor = anchor; this.head = head;\n};\n\nRange.prototype.from = function () { return minPos(this.anchor, this.head) };\nRange.prototype.to = function () { return maxPos(this.anchor, this.head) };\nRange.prototype.empty = function () { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch };\n\n// Take an unsorted, potentially overlapping set of ranges, and\n// build a selection out of it. 'Consumes' ranges array (modifying\n// it).\nfunction normalizeSelection(ranges, primIndex) {\n  var prim = ranges[primIndex];\n  ranges.sort(function (a, b) { return cmp(a.from(), b.from()); });\n  primIndex = indexOf(ranges, prim);\n  for (var i = 1; i < ranges.length; i++) {\n    var cur = ranges[i], prev = ranges[i - 1];\n    if (cmp(prev.to(), cur.from()) >= 0) {\n      var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());\n      var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;\n      if (i <= primIndex) { --primIndex; }\n      ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));\n    }\n  }\n  return new Selection(ranges, primIndex)\n}\n\nfunction simpleSelection(anchor, head) {\n  return new Selection([new Range(anchor, head || anchor)], 0)\n}\n\n// Compute the position of the end of a change (its 'to' property\n// refers to the pre-change end).\nfunction changeEnd(change) {\n  if (!change.text) { return change.to }\n  return Pos(change.from.line + change.text.length - 1,\n             lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0))\n}\n\n// Adjust a position to refer to the post-change position of the\n// same text, or the end of the change if the change covers it.\nfunction adjustForChange(pos, change) {\n  if (cmp(pos, change.from) < 0) { return pos }\n  if (cmp(pos, change.to) <= 0) { return changeEnd(change) }\n\n  var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;\n  if (pos.line == change.to.line) { ch += changeEnd(change).ch - change.to.ch; }\n  return Pos(line, ch)\n}\n\nfunction computeSelAfterChange(doc, change) {\n  var out = [];\n  for (var i = 0; i < doc.sel.ranges.length; i++) {\n    var range = doc.sel.ranges[i];\n    out.push(new Range(adjustForChange(range.anchor, change),\n                       adjustForChange(range.head, change)));\n  }\n  return normalizeSelection(out, doc.sel.primIndex)\n}\n\nfunction offsetPos(pos, old, nw) {\n  if (pos.line == old.line)\n    { return Pos(nw.line, pos.ch - old.ch + nw.ch) }\n  else\n    { return Pos(nw.line + (pos.line - old.line), pos.ch) }\n}\n\n// Used by replaceSelections to allow moving the selection to the\n// start or around the replaced test. Hint may be \"start\" or \"around\".\nfunction computeReplacedSel(doc, changes, hint) {\n  var out = [];\n  var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;\n  for (var i = 0; i < changes.length; i++) {\n    var change = changes[i];\n    var from = offsetPos(change.from, oldPrev, newPrev);\n    var to = offsetPos(changeEnd(change), oldPrev, newPrev);\n    oldPrev = change.to;\n    newPrev = to;\n    if (hint == \"around\") {\n      var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;\n      out[i] = new Range(inv ? to : from, inv ? from : to);\n    } else {\n      out[i] = new Range(from, from);\n    }\n  }\n  return new Selection(out, doc.sel.primIndex)\n}\n\n// Used to get the editor into a consistent state again when options change.\n\nfunction loadMode(cm) {\n  cm.doc.mode = getMode(cm.options, cm.doc.modeOption);\n  resetModeState(cm);\n}\n\nfunction resetModeState(cm) {\n  cm.doc.iter(function (line) {\n    if (line.stateAfter) { line.stateAfter = null; }\n    if (line.styles) { line.styles = null; }\n  });\n  cm.doc.modeFrontier = cm.doc.highlightFrontier = cm.doc.first;\n  startWorker(cm, 100);\n  cm.state.modeGen++;\n  if (cm.curOp) { regChange(cm); }\n}\n\n// DOCUMENT DATA STRUCTURE\n\n// By default, updates that start and end at the beginning of a line\n// are treated specially, in order to make the association of line\n// widgets and marker elements with the text behave more intuitive.\nfunction isWholeLineUpdate(doc, change) {\n  return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == \"\" &&\n    (!doc.cm || doc.cm.options.wholeLineUpdateBefore)\n}\n\n// Perform a change on the document data structure.\nfunction updateDoc(doc, change, markedSpans, estimateHeight$$1) {\n  function spansFor(n) {return markedSpans ? markedSpans[n] : null}\n  function update(line, text, spans) {\n    updateLine(line, text, spans, estimateHeight$$1);\n    signalLater(line, \"change\", line, change);\n  }\n  function linesFor(start, end) {\n    var result = [];\n    for (var i = start; i < end; ++i)\n      { result.push(new Line(text[i], spansFor(i), estimateHeight$$1)); }\n    return result\n  }\n\n  var from = change.from, to = change.to, text = change.text;\n  var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);\n  var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;\n\n  // Adjust the line structure\n  if (change.full) {\n    doc.insert(0, linesFor(0, text.length));\n    doc.remove(text.length, doc.size - text.length);\n  } else if (isWholeLineUpdate(doc, change)) {\n    // This is a whole-line replace. Treated specially to make\n    // sure line objects move the way they are supposed to.\n    var added = linesFor(0, text.length - 1);\n    update(lastLine, lastLine.text, lastSpans);\n    if (nlines) { doc.remove(from.line, nlines); }\n    if (added.length) { doc.insert(from.line, added); }\n  } else if (firstLine == lastLine) {\n    if (text.length == 1) {\n      update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);\n    } else {\n      var added$1 = linesFor(1, text.length - 1);\n      added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight$$1));\n      update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));\n      doc.insert(from.line + 1, added$1);\n    }\n  } else if (text.length == 1) {\n    update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));\n    doc.remove(from.line + 1, nlines);\n  } else {\n    update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));\n    update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);\n    var added$2 = linesFor(1, text.length - 1);\n    if (nlines > 1) { doc.remove(from.line + 1, nlines - 1); }\n    doc.insert(from.line + 1, added$2);\n  }\n\n  signalLater(doc, \"change\", doc, change);\n}\n\n// Call f for all linked documents.\nfunction linkedDocs(doc, f, sharedHistOnly) {\n  function propagate(doc, skip, sharedHist) {\n    if (doc.linked) { for (var i = 0; i < doc.linked.length; ++i) {\n      var rel = doc.linked[i];\n      if (rel.doc == skip) { continue }\n      var shared = sharedHist && rel.sharedHist;\n      if (sharedHistOnly && !shared) { continue }\n      f(rel.doc, shared);\n      propagate(rel.doc, doc, shared);\n    } }\n  }\n  propagate(doc, null, true);\n}\n\n// Attach a document to an editor.\nfunction attachDoc(cm, doc) {\n  if (doc.cm) { throw new Error(\"This document is already in use.\") }\n  cm.doc = doc;\n  doc.cm = cm;\n  estimateLineHeights(cm);\n  loadMode(cm);\n  setDirectionClass(cm);\n  if (!cm.options.lineWrapping) { findMaxLine(cm); }\n  cm.options.mode = doc.modeOption;\n  regChange(cm);\n}\n\nfunction setDirectionClass(cm) {\n  (cm.doc.direction == \"rtl\" ? addClass : rmClass)(cm.display.lineDiv, \"CodeMirror-rtl\");\n}\n\nfunction directionChanged(cm) {\n  runInOp(cm, function () {\n    setDirectionClass(cm);\n    regChange(cm);\n  });\n}\n\nfunction History(startGen) {\n  // Arrays of change events and selections. Doing something adds an\n  // event to done and clears undo. Undoing moves events from done\n  // to undone, redoing moves them in the other direction.\n  this.done = []; this.undone = [];\n  this.undoDepth = Infinity;\n  // Used to track when changes can be merged into a single undo\n  // event\n  this.lastModTime = this.lastSelTime = 0;\n  this.lastOp = this.lastSelOp = null;\n  this.lastOrigin = this.lastSelOrigin = null;\n  // Used by the isClean() method\n  this.generation = this.maxGeneration = startGen || 1;\n}\n\n// Create a history change event from an updateDoc-style change\n// object.\nfunction historyChangeFromChange(doc, change) {\n  var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};\n  attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);\n  linkedDocs(doc, function (doc) { return attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true);\n  return histChange\n}\n\n// Pop all selection events off the end of a history array. Stop at\n// a change event.\nfunction clearSelectionEvents(array) {\n  while (array.length) {\n    var last = lst(array);\n    if (last.ranges) { array.pop(); }\n    else { break }\n  }\n}\n\n// Find the top change event in the history. Pop off selection\n// events that are in the way.\nfunction lastChangeEvent(hist, force) {\n  if (force) {\n    clearSelectionEvents(hist.done);\n    return lst(hist.done)\n  } else if (hist.done.length && !lst(hist.done).ranges) {\n    return lst(hist.done)\n  } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {\n    hist.done.pop();\n    return lst(hist.done)\n  }\n}\n\n// Register a change in the history. Merges changes that are within\n// a single operation, or are close together with an origin that\n// allows merging (starting with \"+\") into a single event.\nfunction addChangeToHistory(doc, change, selAfter, opId) {\n  var hist = doc.history;\n  hist.undone.length = 0;\n  var time = +new Date, cur;\n  var last;\n\n  if ((hist.lastOp == opId ||\n       hist.lastOrigin == change.origin && change.origin &&\n       ((change.origin.charAt(0) == \"+\" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) ||\n        change.origin.charAt(0) == \"*\")) &&\n      (cur = lastChangeEvent(hist, hist.lastOp == opId))) {\n    // Merge this change into the last event\n    last = lst(cur.changes);\n    if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {\n      // Optimized case for simple insertion -- don't want to add\n      // new changesets for every character typed\n      last.to = changeEnd(change);\n    } else {\n      // Add new sub-event\n      cur.changes.push(historyChangeFromChange(doc, change));\n    }\n  } else {\n    // Can not be merged, start a new event.\n    var before = lst(hist.done);\n    if (!before || !before.ranges)\n      { pushSelectionToHistory(doc.sel, hist.done); }\n    cur = {changes: [historyChangeFromChange(doc, change)],\n           generation: hist.generation};\n    hist.done.push(cur);\n    while (hist.done.length > hist.undoDepth) {\n      hist.done.shift();\n      if (!hist.done[0].ranges) { hist.done.shift(); }\n    }\n  }\n  hist.done.push(selAfter);\n  hist.generation = ++hist.maxGeneration;\n  hist.lastModTime = hist.lastSelTime = time;\n  hist.lastOp = hist.lastSelOp = opId;\n  hist.lastOrigin = hist.lastSelOrigin = change.origin;\n\n  if (!last) { signal(doc, \"historyAdded\"); }\n}\n\nfunction selectionEventCanBeMerged(doc, origin, prev, sel) {\n  var ch = origin.charAt(0);\n  return ch == \"*\" ||\n    ch == \"+\" &&\n    prev.ranges.length == sel.ranges.length &&\n    prev.somethingSelected() == sel.somethingSelected() &&\n    new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500)\n}\n\n// Called whenever the selection changes, sets the new selection as\n// the pending selection in the history, and pushes the old pending\n// selection into the 'done' array when it was significantly\n// different (in number of selected ranges, emptiness, or time).\nfunction addSelectionToHistory(doc, sel, opId, options) {\n  var hist = doc.history, origin = options && options.origin;\n\n  // A new event is started when the previous origin does not match\n  // the current, or the origins don't allow matching. Origins\n  // starting with * are always merged, those starting with + are\n  // merged when similar and close together in time.\n  if (opId == hist.lastSelOp ||\n      (origin && hist.lastSelOrigin == origin &&\n       (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||\n        selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))\n    { hist.done[hist.done.length - 1] = sel; }\n  else\n    { pushSelectionToHistory(sel, hist.done); }\n\n  hist.lastSelTime = +new Date;\n  hist.lastSelOrigin = origin;\n  hist.lastSelOp = opId;\n  if (options && options.clearRedo !== false)\n    { clearSelectionEvents(hist.undone); }\n}\n\nfunction pushSelectionToHistory(sel, dest) {\n  var top = lst(dest);\n  if (!(top && top.ranges && top.equals(sel)))\n    { dest.push(sel); }\n}\n\n// Used to store marked span information in the history.\nfunction attachLocalSpans(doc, change, from, to) {\n  var existing = change[\"spans_\" + doc.id], n = 0;\n  doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) {\n    if (line.markedSpans)\n      { (existing || (existing = change[\"spans_\" + doc.id] = {}))[n] = line.markedSpans; }\n    ++n;\n  });\n}\n\n// When un/re-doing restores text containing marked spans, those\n// that have been explicitly cleared should not be restored.\nfunction removeClearedSpans(spans) {\n  if (!spans) { return null }\n  var out;\n  for (var i = 0; i < spans.length; ++i) {\n    if (spans[i].marker.explicitlyCleared) { if (!out) { out = spans.slice(0, i); } }\n    else if (out) { out.push(spans[i]); }\n  }\n  return !out ? spans : out.length ? out : null\n}\n\n// Retrieve and filter the old marked spans stored in a change event.\nfunction getOldSpans(doc, change) {\n  var found = change[\"spans_\" + doc.id];\n  if (!found) { return null }\n  var nw = [];\n  for (var i = 0; i < change.text.length; ++i)\n    { nw.push(removeClearedSpans(found[i])); }\n  return nw\n}\n\n// Used for un/re-doing changes from the history. Combines the\n// result of computing the existing spans with the set of spans that\n// existed in the history (so that deleting around a span and then\n// undoing brings back the span).\nfunction mergeOldSpans(doc, change) {\n  var old = getOldSpans(doc, change);\n  var stretched = stretchSpansOverChange(doc, change);\n  if (!old) { return stretched }\n  if (!stretched) { return old }\n\n  for (var i = 0; i < old.length; ++i) {\n    var oldCur = old[i], stretchCur = stretched[i];\n    if (oldCur && stretchCur) {\n      spans: for (var j = 0; j < stretchCur.length; ++j) {\n        var span = stretchCur[j];\n        for (var k = 0; k < oldCur.length; ++k)\n          { if (oldCur[k].marker == span.marker) { continue spans } }\n        oldCur.push(span);\n      }\n    } else if (stretchCur) {\n      old[i] = stretchCur;\n    }\n  }\n  return old\n}\n\n// Used both to provide a JSON-safe object in .getHistory, and, when\n// detaching a document, to split the history in two\nfunction copyHistoryArray(events, newGroup, instantiateSel) {\n  var copy = [];\n  for (var i = 0; i < events.length; ++i) {\n    var event = events[i];\n    if (event.ranges) {\n      copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);\n      continue\n    }\n    var changes = event.changes, newChanges = [];\n    copy.push({changes: newChanges});\n    for (var j = 0; j < changes.length; ++j) {\n      var change = changes[j], m = (void 0);\n      newChanges.push({from: change.from, to: change.to, text: change.text});\n      if (newGroup) { for (var prop in change) { if (m = prop.match(/^spans_(\\d+)$/)) {\n        if (indexOf(newGroup, Number(m[1])) > -1) {\n          lst(newChanges)[prop] = change[prop];\n          delete change[prop];\n        }\n      } } }\n    }\n  }\n  return copy\n}\n\n// The 'scroll' parameter given to many of these indicated whether\n// the new cursor position should be scrolled into view after\n// modifying the selection.\n\n// If shift is held or the extend flag is set, extends a range to\n// include a given position (and optionally a second position).\n// Otherwise, simply returns the range between the given positions.\n// Used for cursor motion and such.\nfunction extendRange(range, head, other, extend) {\n  if (extend) {\n    var anchor = range.anchor;\n    if (other) {\n      var posBefore = cmp(head, anchor) < 0;\n      if (posBefore != (cmp(other, anchor) < 0)) {\n        anchor = head;\n        head = other;\n      } else if (posBefore != (cmp(head, other) < 0)) {\n        head = other;\n      }\n    }\n    return new Range(anchor, head)\n  } else {\n    return new Range(other || head, head)\n  }\n}\n\n// Extend the primary selection range, discard the rest.\nfunction extendSelection(doc, head, other, options, extend) {\n  if (extend == null) { extend = doc.cm && (doc.cm.display.shift || doc.extend); }\n  setSelection(doc, new Selection([extendRange(doc.sel.primary(), head, other, extend)], 0), options);\n}\n\n// Extend all selections (pos is an array of selections with length\n// equal the number of selections)\nfunction extendSelections(doc, heads, options) {\n  var out = [];\n  var extend = doc.cm && (doc.cm.display.shift || doc.extend);\n  for (var i = 0; i < doc.sel.ranges.length; i++)\n    { out[i] = extendRange(doc.sel.ranges[i], heads[i], null, extend); }\n  var newSel = normalizeSelection(out, doc.sel.primIndex);\n  setSelection(doc, newSel, options);\n}\n\n// Updates a single range in the selection.\nfunction replaceOneSelection(doc, i, range, options) {\n  var ranges = doc.sel.ranges.slice(0);\n  ranges[i] = range;\n  setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);\n}\n\n// Reset the selection to a single range.\nfunction setSimpleSelection(doc, anchor, head, options) {\n  setSelection(doc, simpleSelection(anchor, head), options);\n}\n\n// Give beforeSelectionChange handlers a change to influence a\n// selection update.\nfunction filterSelectionChange(doc, sel, options) {\n  var obj = {\n    ranges: sel.ranges,\n    update: function(ranges) {\n      var this$1 = this;\n\n      this.ranges = [];\n      for (var i = 0; i < ranges.length; i++)\n        { this$1.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),\n                                   clipPos(doc, ranges[i].head)); }\n    },\n    origin: options && options.origin\n  };\n  signal(doc, \"beforeSelectionChange\", doc, obj);\n  if (doc.cm) { signal(doc.cm, \"beforeSelectionChange\", doc.cm, obj); }\n  if (obj.ranges != sel.ranges) { return normalizeSelection(obj.ranges, obj.ranges.length - 1) }\n  else { return sel }\n}\n\nfunction setSelectionReplaceHistory(doc, sel, options) {\n  var done = doc.history.done, last = lst(done);\n  if (last && last.ranges) {\n    done[done.length - 1] = sel;\n    setSelectionNoUndo(doc, sel, options);\n  } else {\n    setSelection(doc, sel, options);\n  }\n}\n\n// Set a new selection.\nfunction setSelection(doc, sel, options) {\n  setSelectionNoUndo(doc, sel, options);\n  addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);\n}\n\nfunction setSelectionNoUndo(doc, sel, options) {\n  if (hasHandler(doc, \"beforeSelectionChange\") || doc.cm && hasHandler(doc.cm, \"beforeSelectionChange\"))\n    { sel = filterSelectionChange(doc, sel, options); }\n\n  var bias = options && options.bias ||\n    (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);\n  setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));\n\n  if (!(options && options.scroll === false) && doc.cm)\n    { ensureCursorVisible(doc.cm); }\n}\n\nfunction setSelectionInner(doc, sel) {\n  if (sel.equals(doc.sel)) { return }\n\n  doc.sel = sel;\n\n  if (doc.cm) {\n    doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;\n    signalCursorActivity(doc.cm);\n  }\n  signalLater(doc, \"cursorActivity\", doc);\n}\n\n// Verify that the selection does not partially select any atomic\n// marked ranges.\nfunction reCheckSelection(doc) {\n  setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false));\n}\n\n// Return a selection that does not partially select any atomic\n// ranges.\nfunction skipAtomicInSelection(doc, sel, bias, mayClear) {\n  var out;\n  for (var i = 0; i < sel.ranges.length; i++) {\n    var range = sel.ranges[i];\n    var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];\n    var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);\n    var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);\n    if (out || newAnchor != range.anchor || newHead != range.head) {\n      if (!out) { out = sel.ranges.slice(0, i); }\n      out[i] = new Range(newAnchor, newHead);\n    }\n  }\n  return out ? normalizeSelection(out, sel.primIndex) : sel\n}\n\nfunction skipAtomicInner(doc, pos, oldPos, dir, mayClear) {\n  var line = getLine(doc, pos.line);\n  if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {\n    var sp = line.markedSpans[i], m = sp.marker;\n    if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&\n        (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {\n      if (mayClear) {\n        signal(m, \"beforeCursorEnter\");\n        if (m.explicitlyCleared) {\n          if (!line.markedSpans) { break }\n          else {--i; continue}\n        }\n      }\n      if (!m.atomic) { continue }\n\n      if (oldPos) {\n        var near = m.find(dir < 0 ? 1 : -1), diff = (void 0);\n        if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft)\n          { near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); }\n        if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))\n          { return skipAtomicInner(doc, near, pos, dir, mayClear) }\n      }\n\n      var far = m.find(dir < 0 ? -1 : 1);\n      if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight)\n        { far = movePos(doc, far, dir, far.line == pos.line ? line : null); }\n      return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null\n    }\n  } }\n  return pos\n}\n\n// Ensure a given position is not inside an atomic range.\nfunction skipAtomic(doc, pos, oldPos, bias, mayClear) {\n  var dir = bias || 1;\n  var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||\n      (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||\n      skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||\n      (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));\n  if (!found) {\n    doc.cantEdit = true;\n    return Pos(doc.first, 0)\n  }\n  return found\n}\n\nfunction movePos(doc, pos, dir, line) {\n  if (dir < 0 && pos.ch == 0) {\n    if (pos.line > doc.first) { return clipPos(doc, Pos(pos.line - 1)) }\n    else { return null }\n  } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {\n    if (pos.line < doc.first + doc.size - 1) { return Pos(pos.line + 1, 0) }\n    else { return null }\n  } else {\n    return new Pos(pos.line, pos.ch + dir)\n  }\n}\n\nfunction selectAll(cm) {\n  cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);\n}\n\n// UPDATING\n\n// Allow \"beforeChange\" event handlers to influence a change\nfunction filterChange(doc, change, update) {\n  var obj = {\n    canceled: false,\n    from: change.from,\n    to: change.to,\n    text: change.text,\n    origin: change.origin,\n    cancel: function () { return obj.canceled = true; }\n  };\n  if (update) { obj.update = function (from, to, text, origin) {\n    if (from) { obj.from = clipPos(doc, from); }\n    if (to) { obj.to = clipPos(doc, to); }\n    if (text) { obj.text = text; }\n    if (origin !== undefined) { obj.origin = origin; }\n  }; }\n  signal(doc, \"beforeChange\", doc, obj);\n  if (doc.cm) { signal(doc.cm, \"beforeChange\", doc.cm, obj); }\n\n  if (obj.canceled) { return null }\n  return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}\n}\n\n// Apply a change to a document, and add it to the document's\n// history, and propagating it to all linked documents.\nfunction makeChange(doc, change, ignoreReadOnly) {\n  if (doc.cm) {\n    if (!doc.cm.curOp) { return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) }\n    if (doc.cm.state.suppressEdits) { return }\n  }\n\n  if (hasHandler(doc, \"beforeChange\") || doc.cm && hasHandler(doc.cm, \"beforeChange\")) {\n    change = filterChange(doc, change, true);\n    if (!change) { return }\n  }\n\n  // Possibly split or suppress the update based on the presence\n  // of read-only spans in its range.\n  var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);\n  if (split) {\n    for (var i = split.length - 1; i >= 0; --i)\n      { makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [\"\"] : change.text}); }\n  } else {\n    makeChangeInner(doc, change);\n  }\n}\n\nfunction makeChangeInner(doc, change) {\n  if (change.text.length == 1 && change.text[0] == \"\" && cmp(change.from, change.to) == 0) { return }\n  var selAfter = computeSelAfterChange(doc, change);\n  addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);\n\n  makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));\n  var rebased = [];\n\n  linkedDocs(doc, function (doc, sharedHist) {\n    if (!sharedHist && indexOf(rebased, doc.history) == -1) {\n      rebaseHist(doc.history, change);\n      rebased.push(doc.history);\n    }\n    makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));\n  });\n}\n\n// Revert a change stored in a document's history.\nfunction makeChangeFromHistory(doc, type, allowSelectionOnly) {\n  if (doc.cm && doc.cm.state.suppressEdits && !allowSelectionOnly) { return }\n\n  var hist = doc.history, event, selAfter = doc.sel;\n  var source = type == \"undo\" ? hist.done : hist.undone, dest = type == \"undo\" ? hist.undone : hist.done;\n\n  // Verify that there is a useable event (so that ctrl-z won't\n  // needlessly clear selection events)\n  var i = 0;\n  for (; i < source.length; i++) {\n    event = source[i];\n    if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)\n      { break }\n  }\n  if (i == source.length) { return }\n  hist.lastOrigin = hist.lastSelOrigin = null;\n\n  for (;;) {\n    event = source.pop();\n    if (event.ranges) {\n      pushSelectionToHistory(event, dest);\n      if (allowSelectionOnly && !event.equals(doc.sel)) {\n        setSelection(doc, event, {clearRedo: false});\n        return\n      }\n      selAfter = event;\n    }\n    else { break }\n  }\n\n  // Build up a reverse change object to add to the opposite history\n  // stack (redo when undoing, and vice versa).\n  var antiChanges = [];\n  pushSelectionToHistory(selAfter, dest);\n  dest.push({changes: antiChanges, generation: hist.generation});\n  hist.generation = event.generation || ++hist.maxGeneration;\n\n  var filter = hasHandler(doc, \"beforeChange\") || doc.cm && hasHandler(doc.cm, \"beforeChange\");\n\n  var loop = function ( i ) {\n    var change = event.changes[i];\n    change.origin = type;\n    if (filter && !filterChange(doc, change, false)) {\n      source.length = 0;\n      return {}\n    }\n\n    antiChanges.push(historyChangeFromChange(doc, change));\n\n    var after = i ? computeSelAfterChange(doc, change) : lst(source);\n    makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));\n    if (!i && doc.cm) { doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); }\n    var rebased = [];\n\n    // Propagate to the linked documents\n    linkedDocs(doc, function (doc, sharedHist) {\n      if (!sharedHist && indexOf(rebased, doc.history) == -1) {\n        rebaseHist(doc.history, change);\n        rebased.push(doc.history);\n      }\n      makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));\n    });\n  };\n\n  for (var i$1 = event.changes.length - 1; i$1 >= 0; --i$1) {\n    var returned = loop( i$1 );\n\n    if ( returned ) return returned.v;\n  }\n}\n\n// Sub-views need their line numbers shifted when text is added\n// above or below them in the parent document.\nfunction shiftDoc(doc, distance) {\n  if (distance == 0) { return }\n  doc.first += distance;\n  doc.sel = new Selection(map(doc.sel.ranges, function (range) { return new Range(\n    Pos(range.anchor.line + distance, range.anchor.ch),\n    Pos(range.head.line + distance, range.head.ch)\n  ); }), doc.sel.primIndex);\n  if (doc.cm) {\n    regChange(doc.cm, doc.first, doc.first - distance, distance);\n    for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)\n      { regLineChange(doc.cm, l, \"gutter\"); }\n  }\n}\n\n// More lower-level change function, handling only a single document\n// (not linked ones).\nfunction makeChangeSingleDoc(doc, change, selAfter, spans) {\n  if (doc.cm && !doc.cm.curOp)\n    { return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) }\n\n  if (change.to.line < doc.first) {\n    shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));\n    return\n  }\n  if (change.from.line > doc.lastLine()) { return }\n\n  // Clip the change to the size of this doc\n  if (change.from.line < doc.first) {\n    var shift = change.text.length - 1 - (doc.first - change.from.line);\n    shiftDoc(doc, shift);\n    change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),\n              text: [lst(change.text)], origin: change.origin};\n  }\n  var last = doc.lastLine();\n  if (change.to.line > last) {\n    change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),\n              text: [change.text[0]], origin: change.origin};\n  }\n\n  change.removed = getBetween(doc, change.from, change.to);\n\n  if (!selAfter) { selAfter = computeSelAfterChange(doc, change); }\n  if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans); }\n  else { updateDoc(doc, change, spans); }\n  setSelectionNoUndo(doc, selAfter, sel_dontScroll);\n}\n\n// Handle the interaction of a change to a document with the editor\n// that this document is part of.\nfunction makeChangeSingleDocInEditor(cm, change, spans) {\n  var doc = cm.doc, display = cm.display, from = change.from, to = change.to;\n\n  var recomputeMaxLength = false, checkWidthStart = from.line;\n  if (!cm.options.lineWrapping) {\n    checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));\n    doc.iter(checkWidthStart, to.line + 1, function (line) {\n      if (line == display.maxLine) {\n        recomputeMaxLength = true;\n        return true\n      }\n    });\n  }\n\n  if (doc.sel.contains(change.from, change.to) > -1)\n    { signalCursorActivity(cm); }\n\n  updateDoc(doc, change, spans, estimateHeight(cm));\n\n  if (!cm.options.lineWrapping) {\n    doc.iter(checkWidthStart, from.line + change.text.length, function (line) {\n      var len = lineLength(line);\n      if (len > display.maxLineLength) {\n        display.maxLine = line;\n        display.maxLineLength = len;\n        display.maxLineChanged = true;\n        recomputeMaxLength = false;\n      }\n    });\n    if (recomputeMaxLength) { cm.curOp.updateMaxLine = true; }\n  }\n\n  retreatFrontier(doc, from.line);\n  startWorker(cm, 400);\n\n  var lendiff = change.text.length - (to.line - from.line) - 1;\n  // Remember that these lines changed, for updating the display\n  if (change.full)\n    { regChange(cm); }\n  else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))\n    { regLineChange(cm, from.line, \"text\"); }\n  else\n    { regChange(cm, from.line, to.line + 1, lendiff); }\n\n  var changesHandler = hasHandler(cm, \"changes\"), changeHandler = hasHandler(cm, \"change\");\n  if (changeHandler || changesHandler) {\n    var obj = {\n      from: from, to: to,\n      text: change.text,\n      removed: change.removed,\n      origin: change.origin\n    };\n    if (changeHandler) { signalLater(cm, \"change\", cm, obj); }\n    if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); }\n  }\n  cm.display.selForContextMenu = null;\n}\n\nfunction replaceRange(doc, code, from, to, origin) {\n  if (!to) { to = from; }\n  if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; }\n  if (typeof code == \"string\") { code = doc.splitLines(code); }\n  makeChange(doc, {from: from, to: to, text: code, origin: origin});\n}\n\n// Rebasing/resetting history to deal with externally-sourced changes\n\nfunction rebaseHistSelSingle(pos, from, to, diff) {\n  if (to < pos.line) {\n    pos.line += diff;\n  } else if (from < pos.line) {\n    pos.line = from;\n    pos.ch = 0;\n  }\n}\n\n// Tries to rebase an array of history events given a change in the\n// document. If the change touches the same lines as the event, the\n// event, and everything 'behind' it, is discarded. If the change is\n// before the event, the event's positions are updated. Uses a\n// copy-on-write scheme for the positions, to avoid having to\n// reallocate them all on every rebase, but also avoid problems with\n// shared position objects being unsafely updated.\nfunction rebaseHistArray(array, from, to, diff) {\n  for (var i = 0; i < array.length; ++i) {\n    var sub = array[i], ok = true;\n    if (sub.ranges) {\n      if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }\n      for (var j = 0; j < sub.ranges.length; j++) {\n        rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);\n        rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);\n      }\n      continue\n    }\n    for (var j$1 = 0; j$1 < sub.changes.length; ++j$1) {\n      var cur = sub.changes[j$1];\n      if (to < cur.from.line) {\n        cur.from = Pos(cur.from.line + diff, cur.from.ch);\n        cur.to = Pos(cur.to.line + diff, cur.to.ch);\n      } else if (from <= cur.to.line) {\n        ok = false;\n        break\n      }\n    }\n    if (!ok) {\n      array.splice(0, i + 1);\n      i = 0;\n    }\n  }\n}\n\nfunction rebaseHist(hist, change) {\n  var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;\n  rebaseHistArray(hist.done, from, to, diff);\n  rebaseHistArray(hist.undone, from, to, diff);\n}\n\n// Utility for applying a change to a line by handle or number,\n// returning the number and optionally registering the line as\n// changed.\nfunction changeLine(doc, handle, changeType, op) {\n  var no = handle, line = handle;\n  if (typeof handle == \"number\") { line = getLine(doc, clipLine(doc, handle)); }\n  else { no = lineNo(handle); }\n  if (no == null) { return null }\n  if (op(line, no) && doc.cm) { regLineChange(doc.cm, no, changeType); }\n  return line\n}\n\n// The document is represented as a BTree consisting of leaves, with\n// chunk of lines in them, and branches, with up to ten leaves or\n// other branch nodes below them. The top node is always a branch\n// node, and is the document object itself (meaning it has\n// additional methods and properties).\n//\n// All nodes have parent links. The tree is used both to go from\n// line numbers to line objects, and to go from objects to numbers.\n// It also indexes by height, and is used to convert between height\n// and line object, and to find the total height of the document.\n//\n// See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html\n\nfunction LeafChunk(lines) {\n  var this$1 = this;\n\n  this.lines = lines;\n  this.parent = null;\n  var height = 0;\n  for (var i = 0; i < lines.length; ++i) {\n    lines[i].parent = this$1;\n    height += lines[i].height;\n  }\n  this.height = height;\n}\n\nLeafChunk.prototype = {\n  chunkSize: function() { return this.lines.length },\n\n  // Remove the n lines at offset 'at'.\n  removeInner: function(at, n) {\n    var this$1 = this;\n\n    for (var i = at, e = at + n; i < e; ++i) {\n      var line = this$1.lines[i];\n      this$1.height -= line.height;\n      cleanUpLine(line);\n      signalLater(line, \"delete\");\n    }\n    this.lines.splice(at, n);\n  },\n\n  // Helper used to collapse a small branch into a single leaf.\n  collapse: function(lines) {\n    lines.push.apply(lines, this.lines);\n  },\n\n  // Insert the given array of lines at offset 'at', count them as\n  // having the given height.\n  insertInner: function(at, lines, height) {\n    var this$1 = this;\n\n    this.height += height;\n    this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));\n    for (var i = 0; i < lines.length; ++i) { lines[i].parent = this$1; }\n  },\n\n  // Used to iterate over a part of the tree.\n  iterN: function(at, n, op) {\n    var this$1 = this;\n\n    for (var e = at + n; at < e; ++at)\n      { if (op(this$1.lines[at])) { return true } }\n  }\n};\n\nfunction BranchChunk(children) {\n  var this$1 = this;\n\n  this.children = children;\n  var size = 0, height = 0;\n  for (var i = 0; i < children.length; ++i) {\n    var ch = children[i];\n    size += ch.chunkSize(); height += ch.height;\n    ch.parent = this$1;\n  }\n  this.size = size;\n  this.height = height;\n  this.parent = null;\n}\n\nBranchChunk.prototype = {\n  chunkSize: function() { return this.size },\n\n  removeInner: function(at, n) {\n    var this$1 = this;\n\n    this.size -= n;\n    for (var i = 0; i < this.children.length; ++i) {\n      var child = this$1.children[i], sz = child.chunkSize();\n      if (at < sz) {\n        var rm = Math.min(n, sz - at), oldHeight = child.height;\n        child.removeInner(at, rm);\n        this$1.height -= oldHeight - child.height;\n        if (sz == rm) { this$1.children.splice(i--, 1); child.parent = null; }\n        if ((n -= rm) == 0) { break }\n        at = 0;\n      } else { at -= sz; }\n    }\n    // If the result is smaller than 25 lines, ensure that it is a\n    // single leaf node.\n    if (this.size - n < 25 &&\n        (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {\n      var lines = [];\n      this.collapse(lines);\n      this.children = [new LeafChunk(lines)];\n      this.children[0].parent = this;\n    }\n  },\n\n  collapse: function(lines) {\n    var this$1 = this;\n\n    for (var i = 0; i < this.children.length; ++i) { this$1.children[i].collapse(lines); }\n  },\n\n  insertInner: function(at, lines, height) {\n    var this$1 = this;\n\n    this.size += lines.length;\n    this.height += height;\n    for (var i = 0; i < this.children.length; ++i) {\n      var child = this$1.children[i], sz = child.chunkSize();\n      if (at <= sz) {\n        child.insertInner(at, lines, height);\n        if (child.lines && child.lines.length > 50) {\n          // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced.\n          // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest.\n          var remaining = child.lines.length % 25 + 25;\n          for (var pos = remaining; pos < child.lines.length;) {\n            var leaf = new LeafChunk(child.lines.slice(pos, pos += 25));\n            child.height -= leaf.height;\n            this$1.children.splice(++i, 0, leaf);\n            leaf.parent = this$1;\n          }\n          child.lines = child.lines.slice(0, remaining);\n          this$1.maybeSpill();\n        }\n        break\n      }\n      at -= sz;\n    }\n  },\n\n  // When a node has grown, check whether it should be split.\n  maybeSpill: function() {\n    if (this.children.length <= 10) { return }\n    var me = this;\n    do {\n      var spilled = me.children.splice(me.children.length - 5, 5);\n      var sibling = new BranchChunk(spilled);\n      if (!me.parent) { // Become the parent node\n        var copy = new BranchChunk(me.children);\n        copy.parent = me;\n        me.children = [copy, sibling];\n        me = copy;\n     } else {\n        me.size -= sibling.size;\n        me.height -= sibling.height;\n        var myIndex = indexOf(me.parent.children, me);\n        me.parent.children.splice(myIndex + 1, 0, sibling);\n      }\n      sibling.parent = me.parent;\n    } while (me.children.length > 10)\n    me.parent.maybeSpill();\n  },\n\n  iterN: function(at, n, op) {\n    var this$1 = this;\n\n    for (var i = 0; i < this.children.length; ++i) {\n      var child = this$1.children[i], sz = child.chunkSize();\n      if (at < sz) {\n        var used = Math.min(n, sz - at);\n        if (child.iterN(at, used, op)) { return true }\n        if ((n -= used) == 0) { break }\n        at = 0;\n      } else { at -= sz; }\n    }\n  }\n};\n\n// Line widgets are block elements displayed above or below a line.\n\nvar LineWidget = function(doc, node, options) {\n  var this$1 = this;\n\n  if (options) { for (var opt in options) { if (options.hasOwnProperty(opt))\n    { this$1[opt] = options[opt]; } } }\n  this.doc = doc;\n  this.node = node;\n};\n\nLineWidget.prototype.clear = function () {\n    var this$1 = this;\n\n  var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);\n  if (no == null || !ws) { return }\n  for (var i = 0; i < ws.length; ++i) { if (ws[i] == this$1) { ws.splice(i--, 1); } }\n  if (!ws.length) { line.widgets = null; }\n  var height = widgetHeight(this);\n  updateLineHeight(line, Math.max(0, line.height - height));\n  if (cm) {\n    runInOp(cm, function () {\n      adjustScrollWhenAboveVisible(cm, line, -height);\n      regLineChange(cm, no, \"widget\");\n    });\n    signalLater(cm, \"lineWidgetCleared\", cm, this, no);\n  }\n};\n\nLineWidget.prototype.changed = function () {\n    var this$1 = this;\n\n  var oldH = this.height, cm = this.doc.cm, line = this.line;\n  this.height = null;\n  var diff = widgetHeight(this) - oldH;\n  if (!diff) { return }\n  updateLineHeight(line, line.height + diff);\n  if (cm) {\n    runInOp(cm, function () {\n      cm.curOp.forceUpdate = true;\n      adjustScrollWhenAboveVisible(cm, line, diff);\n      signalLater(cm, \"lineWidgetChanged\", cm, this$1, lineNo(line));\n    });\n  }\n};\neventMixin(LineWidget);\n\nfunction adjustScrollWhenAboveVisible(cm, line, diff) {\n  if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))\n    { addToScrollTop(cm, diff); }\n}\n\nfunction addLineWidget(doc, handle, node, options) {\n  var widget = new LineWidget(doc, node, options);\n  var cm = doc.cm;\n  if (cm && widget.noHScroll) { cm.display.alignWidgets = true; }\n  changeLine(doc, handle, \"widget\", function (line) {\n    var widgets = line.widgets || (line.widgets = []);\n    if (widget.insertAt == null) { widgets.push(widget); }\n    else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); }\n    widget.line = line;\n    if (cm && !lineIsHidden(doc, line)) {\n      var aboveVisible = heightAtLine(line) < doc.scrollTop;\n      updateLineHeight(line, line.height + widgetHeight(widget));\n      if (aboveVisible) { addToScrollTop(cm, widget.height); }\n      cm.curOp.forceUpdate = true;\n    }\n    return true\n  });\n  signalLater(cm, \"lineWidgetAdded\", cm, widget, typeof handle == \"number\" ? handle : lineNo(handle));\n  return widget\n}\n\n// TEXTMARKERS\n\n// Created with markText and setBookmark methods. A TextMarker is a\n// handle that can be used to clear or find a marked position in the\n// document. Line objects hold arrays (markedSpans) containing\n// {from, to, marker} object pointing to such marker objects, and\n// indicating that such a marker is present on that line. Multiple\n// lines may point to the same marker when it spans across lines.\n// The spans will have null for their from/to properties when the\n// marker continues beyond the start/end of the line. Markers have\n// links back to the lines they currently touch.\n\n// Collapsed markers have unique ids, in order to be able to order\n// them, which is needed for uniquely determining an outer marker\n// when they overlap (they may nest, but not partially overlap).\nvar nextMarkerId = 0;\n\nvar TextMarker = function(doc, type) {\n  this.lines = [];\n  this.type = type;\n  this.doc = doc;\n  this.id = ++nextMarkerId;\n};\n\n// Clear the marker.\nTextMarker.prototype.clear = function () {\n    var this$1 = this;\n\n  if (this.explicitlyCleared) { return }\n  var cm = this.doc.cm, withOp = cm && !cm.curOp;\n  if (withOp) { startOperation(cm); }\n  if (hasHandler(this, \"clear\")) {\n    var found = this.find();\n    if (found) { signalLater(this, \"clear\", found.from, found.to); }\n  }\n  var min = null, max = null;\n  for (var i = 0; i < this.lines.length; ++i) {\n    var line = this$1.lines[i];\n    var span = getMarkedSpanFor(line.markedSpans, this$1);\n    if (cm && !this$1.collapsed) { regLineChange(cm, lineNo(line), \"text\"); }\n    else if (cm) {\n      if (span.to != null) { max = lineNo(line); }\n      if (span.from != null) { min = lineNo(line); }\n    }\n    line.markedSpans = removeMarkedSpan(line.markedSpans, span);\n    if (span.from == null && this$1.collapsed && !lineIsHidden(this$1.doc, line) && cm)\n      { updateLineHeight(line, textHeight(cm.display)); }\n  }\n  if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) {\n    var visual = visualLine(this$1.lines[i$1]), len = lineLength(visual);\n    if (len > cm.display.maxLineLength) {\n      cm.display.maxLine = visual;\n      cm.display.maxLineLength = len;\n      cm.display.maxLineChanged = true;\n    }\n  } }\n\n  if (min != null && cm && this.collapsed) { regChange(cm, min, max + 1); }\n  this.lines.length = 0;\n  this.explicitlyCleared = true;\n  if (this.atomic && this.doc.cantEdit) {\n    this.doc.cantEdit = false;\n    if (cm) { reCheckSelection(cm.doc); }\n  }\n  if (cm) { signalLater(cm, \"markerCleared\", cm, this, min, max); }\n  if (withOp) { endOperation(cm); }\n  if (this.parent) { this.parent.clear(); }\n};\n\n// Find the position of the marker in the document. Returns a {from,\n// to} object by default. Side can be passed to get a specific side\n// -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the\n// Pos objects returned contain a line object, rather than a line\n// number (used to prevent looking up the same line twice).\nTextMarker.prototype.find = function (side, lineObj) {\n    var this$1 = this;\n\n  if (side == null && this.type == \"bookmark\") { side = 1; }\n  var from, to;\n  for (var i = 0; i < this.lines.length; ++i) {\n    var line = this$1.lines[i];\n    var span = getMarkedSpanFor(line.markedSpans, this$1);\n    if (span.from != null) {\n      from = Pos(lineObj ? line : lineNo(line), span.from);\n      if (side == -1) { return from }\n    }\n    if (span.to != null) {\n      to = Pos(lineObj ? line : lineNo(line), span.to);\n      if (side == 1) { return to }\n    }\n  }\n  return from && {from: from, to: to}\n};\n\n// Signals that the marker's widget changed, and surrounding layout\n// should be recomputed.\nTextMarker.prototype.changed = function () {\n    var this$1 = this;\n\n  var pos = this.find(-1, true), widget = this, cm = this.doc.cm;\n  if (!pos || !cm) { return }\n  runInOp(cm, function () {\n    var line = pos.line, lineN = lineNo(pos.line);\n    var view = findViewForLine(cm, lineN);\n    if (view) {\n      clearLineMeasurementCacheFor(view);\n      cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;\n    }\n    cm.curOp.updateMaxLine = true;\n    if (!lineIsHidden(widget.doc, line) && widget.height != null) {\n      var oldHeight = widget.height;\n      widget.height = null;\n      var dHeight = widgetHeight(widget) - oldHeight;\n      if (dHeight)\n        { updateLineHeight(line, line.height + dHeight); }\n    }\n    signalLater(cm, \"markerChanged\", cm, this$1);\n  });\n};\n\nTextMarker.prototype.attachLine = function (line) {\n  if (!this.lines.length && this.doc.cm) {\n    var op = this.doc.cm.curOp;\n    if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)\n      { (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); }\n  }\n  this.lines.push(line);\n};\n\nTextMarker.prototype.detachLine = function (line) {\n  this.lines.splice(indexOf(this.lines, line), 1);\n  if (!this.lines.length && this.doc.cm) {\n    var op = this.doc.cm.curOp;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);\n  }\n};\neventMixin(TextMarker);\n\n// Create a marker, wire it up to the right lines, and\nfunction markText(doc, from, to, options, type) {\n  // Shared markers (across linked documents) are handled separately\n  // (markTextShared will call out to this again, once per\n  // document).\n  if (options && options.shared) { return markTextShared(doc, from, to, options, type) }\n  // Ensure we are in an operation.\n  if (doc.cm && !doc.cm.curOp) { return operation(doc.cm, markText)(doc, from, to, options, type) }\n\n  var marker = new TextMarker(doc, type), diff = cmp(from, to);\n  if (options) { copyObj(options, marker, false); }\n  // Don't connect empty markers unless clearWhenEmpty is false\n  if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)\n    { return marker }\n  if (marker.replacedWith) {\n    // Showing up as a widget implies collapsed (widget replaces text)\n    marker.collapsed = true;\n    marker.widgetNode = eltP(\"span\", [marker.replacedWith], \"CodeMirror-widget\");\n    if (!options.handleMouseEvents) { marker.widgetNode.setAttribute(\"cm-ignore-events\", \"true\"); }\n    if (options.insertLeft) { marker.widgetNode.insertLeft = true; }\n  }\n  if (marker.collapsed) {\n    if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||\n        from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))\n      { throw new Error(\"Inserting collapsed marker partially overlapping an existing one\") }\n    seeCollapsedSpans();\n  }\n\n  if (marker.addToHistory)\n    { addChangeToHistory(doc, {from: from, to: to, origin: \"markText\"}, doc.sel, NaN); }\n\n  var curLine = from.line, cm = doc.cm, updateMaxLine;\n  doc.iter(curLine, to.line + 1, function (line) {\n    if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)\n      { updateMaxLine = true; }\n    if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0); }\n    addMarkedSpan(line, new MarkedSpan(marker,\n                                       curLine == from.line ? from.ch : null,\n                                       curLine == to.line ? to.ch : null));\n    ++curLine;\n  });\n  // lineIsHidden depends on the presence of the spans, so needs a second pass\n  if (marker.collapsed) { doc.iter(from.line, to.line + 1, function (line) {\n    if (lineIsHidden(doc, line)) { updateLineHeight(line, 0); }\n  }); }\n\n  if (marker.clearOnEnter) { on(marker, \"beforeCursorEnter\", function () { return marker.clear(); }); }\n\n  if (marker.readOnly) {\n    seeReadOnlySpans();\n    if (doc.history.done.length || doc.history.undone.length)\n      { doc.clearHistory(); }\n  }\n  if (marker.collapsed) {\n    marker.id = ++nextMarkerId;\n    marker.atomic = true;\n  }\n  if (cm) {\n    // Sync editor state\n    if (updateMaxLine) { cm.curOp.updateMaxLine = true; }\n    if (marker.collapsed)\n      { regChange(cm, from.line, to.line + 1); }\n    else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)\n      { for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, \"text\"); } }\n    if (marker.atomic) { reCheckSelection(cm.doc); }\n    signalLater(cm, \"markerAdded\", cm, marker);\n  }\n  return marker\n}\n\n// SHARED TEXTMARKERS\n\n// A shared marker spans multiple linked documents. It is\n// implemented as a meta-marker-object controlling multiple normal\n// markers.\nvar SharedTextMarker = function(markers, primary) {\n  var this$1 = this;\n\n  this.markers = markers;\n  this.primary = primary;\n  for (var i = 0; i < markers.length; ++i)\n    { markers[i].parent = this$1; }\n};\n\nSharedTextMarker.prototype.clear = function () {\n    var this$1 = this;\n\n  if (this.explicitlyCleared) { return }\n  this.explicitlyCleared = true;\n  for (var i = 0; i < this.markers.length; ++i)\n    { this$1.markers[i].clear(); }\n  signalLater(this, \"clear\");\n};\n\nSharedTextMarker.prototype.find = function (side, lineObj) {\n  return this.primary.find(side, lineObj)\n};\neventMixin(SharedTextMarker);\n\nfunction markTextShared(doc, from, to, options, type) {\n  options = copyObj(options);\n  options.shared = false;\n  var markers = [markText(doc, from, to, options, type)], primary = markers[0];\n  var widget = options.widgetNode;\n  linkedDocs(doc, function (doc) {\n    if (widget) { options.widgetNode = widget.cloneNode(true); }\n    markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));\n    for (var i = 0; i < doc.linked.length; ++i)\n      { if (doc.linked[i].isParent) { return } }\n    primary = lst(markers);\n  });\n  return new SharedTextMarker(markers, primary)\n}\n\nfunction findSharedMarkers(doc) {\n  return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function (m) { return m.parent; })\n}\n\nfunction copySharedMarkers(doc, markers) {\n  for (var i = 0; i < markers.length; i++) {\n    var marker = markers[i], pos = marker.find();\n    var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);\n    if (cmp(mFrom, mTo)) {\n      var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);\n      marker.markers.push(subMark);\n      subMark.parent = marker;\n    }\n  }\n}\n\nfunction detachSharedMarkers(markers) {\n  var loop = function ( i ) {\n    var marker = markers[i], linked = [marker.primary.doc];\n    linkedDocs(marker.primary.doc, function (d) { return linked.push(d); });\n    for (var j = 0; j < marker.markers.length; j++) {\n      var subMarker = marker.markers[j];\n      if (indexOf(linked, subMarker.doc) == -1) {\n        subMarker.parent = null;\n        marker.markers.splice(j--, 1);\n      }\n    }\n  };\n\n  for (var i = 0; i < markers.length; i++) loop( i );\n}\n\nvar nextDocId = 0;\nvar Doc = function(text, mode, firstLine, lineSep, direction) {\n  if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep, direction) }\n  if (firstLine == null) { firstLine = 0; }\n\n  BranchChunk.call(this, [new LeafChunk([new Line(\"\", null)])]);\n  this.first = firstLine;\n  this.scrollTop = this.scrollLeft = 0;\n  this.cantEdit = false;\n  this.cleanGeneration = 1;\n  this.modeFrontier = this.highlightFrontier = firstLine;\n  var start = Pos(firstLine, 0);\n  this.sel = simpleSelection(start);\n  this.history = new History(null);\n  this.id = ++nextDocId;\n  this.modeOption = mode;\n  this.lineSep = lineSep;\n  this.direction = (direction == \"rtl\") ? \"rtl\" : \"ltr\";\n  this.extend = false;\n\n  if (typeof text == \"string\") { text = this.splitLines(text); }\n  updateDoc(this, {from: start, to: start, text: text});\n  setSelection(this, simpleSelection(start), sel_dontScroll);\n};\n\nDoc.prototype = createObj(BranchChunk.prototype, {\n  constructor: Doc,\n  // Iterate over the document. Supports two forms -- with only one\n  // argument, it calls that for each line in the document. With\n  // three, it iterates over the range given by the first two (with\n  // the second being non-inclusive).\n  iter: function(from, to, op) {\n    if (op) { this.iterN(from - this.first, to - from, op); }\n    else { this.iterN(this.first, this.first + this.size, from); }\n  },\n\n  // Non-public interface for adding and removing lines.\n  insert: function(at, lines) {\n    var height = 0;\n    for (var i = 0; i < lines.length; ++i) { height += lines[i].height; }\n    this.insertInner(at - this.first, lines, height);\n  },\n  remove: function(at, n) { this.removeInner(at - this.first, n); },\n\n  // From here, the methods are part of the public interface. Most\n  // are also available from CodeMirror (editor) instances.\n\n  getValue: function(lineSep) {\n    var lines = getLines(this, this.first, this.first + this.size);\n    if (lineSep === false) { return lines }\n    return lines.join(lineSep || this.lineSeparator())\n  },\n  setValue: docMethodOp(function(code) {\n    var top = Pos(this.first, 0), last = this.first + this.size - 1;\n    makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),\n                      text: this.splitLines(code), origin: \"setValue\", full: true}, true);\n    if (this.cm) { scrollToCoords(this.cm, 0, 0); }\n    setSelection(this, simpleSelection(top), sel_dontScroll);\n  }),\n  replaceRange: function(code, from, to, origin) {\n    from = clipPos(this, from);\n    to = to ? clipPos(this, to) : from;\n    replaceRange(this, code, from, to, origin);\n  },\n  getRange: function(from, to, lineSep) {\n    var lines = getBetween(this, clipPos(this, from), clipPos(this, to));\n    if (lineSep === false) { return lines }\n    return lines.join(lineSep || this.lineSeparator())\n  },\n\n  getLine: function(line) {var l = this.getLineHandle(line); return l && l.text},\n\n  getLineHandle: function(line) {if (isLine(this, line)) { return getLine(this, line) }},\n  getLineNumber: function(line) {return lineNo(line)},\n\n  getLineHandleVisualStart: function(line) {\n    if (typeof line == \"number\") { line = getLine(this, line); }\n    return visualLine(line)\n  },\n\n  lineCount: function() {return this.size},\n  firstLine: function() {return this.first},\n  lastLine: function() {return this.first + this.size - 1},\n\n  clipPos: function(pos) {return clipPos(this, pos)},\n\n  getCursor: function(start) {\n    var range$$1 = this.sel.primary(), pos;\n    if (start == null || start == \"head\") { pos = range$$1.head; }\n    else if (start == \"anchor\") { pos = range$$1.anchor; }\n    else if (start == \"end\" || start == \"to\" || start === false) { pos = range$$1.to(); }\n    else { pos = range$$1.from(); }\n    return pos\n  },\n  listSelections: function() { return this.sel.ranges },\n  somethingSelected: function() {return this.sel.somethingSelected()},\n\n  setCursor: docMethodOp(function(line, ch, options) {\n    setSimpleSelection(this, clipPos(this, typeof line == \"number\" ? Pos(line, ch || 0) : line), null, options);\n  }),\n  setSelection: docMethodOp(function(anchor, head, options) {\n    setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);\n  }),\n  extendSelection: docMethodOp(function(head, other, options) {\n    extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);\n  }),\n  extendSelections: docMethodOp(function(heads, options) {\n    extendSelections(this, clipPosArray(this, heads), options);\n  }),\n  extendSelectionsBy: docMethodOp(function(f, options) {\n    var heads = map(this.sel.ranges, f);\n    extendSelections(this, clipPosArray(this, heads), options);\n  }),\n  setSelections: docMethodOp(function(ranges, primary, options) {\n    var this$1 = this;\n\n    if (!ranges.length) { return }\n    var out = [];\n    for (var i = 0; i < ranges.length; i++)\n      { out[i] = new Range(clipPos(this$1, ranges[i].anchor),\n                         clipPos(this$1, ranges[i].head)); }\n    if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex); }\n    setSelection(this, normalizeSelection(out, primary), options);\n  }),\n  addSelection: docMethodOp(function(anchor, head, options) {\n    var ranges = this.sel.ranges.slice(0);\n    ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));\n    setSelection(this, normalizeSelection(ranges, ranges.length - 1), options);\n  }),\n\n  getSelection: function(lineSep) {\n    var this$1 = this;\n\n    var ranges = this.sel.ranges, lines;\n    for (var i = 0; i < ranges.length; i++) {\n      var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());\n      lines = lines ? lines.concat(sel) : sel;\n    }\n    if (lineSep === false) { return lines }\n    else { return lines.join(lineSep || this.lineSeparator()) }\n  },\n  getSelections: function(lineSep) {\n    var this$1 = this;\n\n    var parts = [], ranges = this.sel.ranges;\n    for (var i = 0; i < ranges.length; i++) {\n      var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());\n      if (lineSep !== false) { sel = sel.join(lineSep || this$1.lineSeparator()); }\n      parts[i] = sel;\n    }\n    return parts\n  },\n  replaceSelection: function(code, collapse, origin) {\n    var dup = [];\n    for (var i = 0; i < this.sel.ranges.length; i++)\n      { dup[i] = code; }\n    this.replaceSelections(dup, collapse, origin || \"+input\");\n  },\n  replaceSelections: docMethodOp(function(code, collapse, origin) {\n    var this$1 = this;\n\n    var changes = [], sel = this.sel;\n    for (var i = 0; i < sel.ranges.length; i++) {\n      var range$$1 = sel.ranges[i];\n      changes[i] = {from: range$$1.from(), to: range$$1.to(), text: this$1.splitLines(code[i]), origin: origin};\n    }\n    var newSel = collapse && collapse != \"end\" && computeReplacedSel(this, changes, collapse);\n    for (var i$1 = changes.length - 1; i$1 >= 0; i$1--)\n      { makeChange(this$1, changes[i$1]); }\n    if (newSel) { setSelectionReplaceHistory(this, newSel); }\n    else if (this.cm) { ensureCursorVisible(this.cm); }\n  }),\n  undo: docMethodOp(function() {makeChangeFromHistory(this, \"undo\");}),\n  redo: docMethodOp(function() {makeChangeFromHistory(this, \"redo\");}),\n  undoSelection: docMethodOp(function() {makeChangeFromHistory(this, \"undo\", true);}),\n  redoSelection: docMethodOp(function() {makeChangeFromHistory(this, \"redo\", true);}),\n\n  setExtending: function(val) {this.extend = val;},\n  getExtending: function() {return this.extend},\n\n  historySize: function() {\n    var hist = this.history, done = 0, undone = 0;\n    for (var i = 0; i < hist.done.length; i++) { if (!hist.done[i].ranges) { ++done; } }\n    for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone; } }\n    return {undo: done, redo: undone}\n  },\n  clearHistory: function() {this.history = new History(this.history.maxGeneration);},\n\n  markClean: function() {\n    this.cleanGeneration = this.changeGeneration(true);\n  },\n  changeGeneration: function(forceSplit) {\n    if (forceSplit)\n      { this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; }\n    return this.history.generation\n  },\n  isClean: function (gen) {\n    return this.history.generation == (gen || this.cleanGeneration)\n  },\n\n  getHistory: function() {\n    return {done: copyHistoryArray(this.history.done),\n            undone: copyHistoryArray(this.history.undone)}\n  },\n  setHistory: function(histData) {\n    var hist = this.history = new History(this.history.maxGeneration);\n    hist.done = copyHistoryArray(histData.done.slice(0), null, true);\n    hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);\n  },\n\n  setGutterMarker: docMethodOp(function(line, gutterID, value) {\n    return changeLine(this, line, \"gutter\", function (line) {\n      var markers = line.gutterMarkers || (line.gutterMarkers = {});\n      markers[gutterID] = value;\n      if (!value && isEmpty(markers)) { line.gutterMarkers = null; }\n      return true\n    })\n  }),\n\n  clearGutter: docMethodOp(function(gutterID) {\n    var this$1 = this;\n\n    this.iter(function (line) {\n      if (line.gutterMarkers && line.gutterMarkers[gutterID]) {\n        changeLine(this$1, line, \"gutter\", function () {\n          line.gutterMarkers[gutterID] = null;\n          if (isEmpty(line.gutterMarkers)) { line.gutterMarkers = null; }\n          return true\n        });\n      }\n    });\n  }),\n\n  lineInfo: function(line) {\n    var n;\n    if (typeof line == \"number\") {\n      if (!isLine(this, line)) { return null }\n      n = line;\n      line = getLine(this, line);\n      if (!line) { return null }\n    } else {\n      n = lineNo(line);\n      if (n == null) { return null }\n    }\n    return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,\n            textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,\n            widgets: line.widgets}\n  },\n\n  addLineClass: docMethodOp(function(handle, where, cls) {\n    return changeLine(this, handle, where == \"gutter\" ? \"gutter\" : \"class\", function (line) {\n      var prop = where == \"text\" ? \"textClass\"\n               : where == \"background\" ? \"bgClass\"\n               : where == \"gutter\" ? \"gutterClass\" : \"wrapClass\";\n      if (!line[prop]) { line[prop] = cls; }\n      else if (classTest(cls).test(line[prop])) { return false }\n      else { line[prop] += \" \" + cls; }\n      return true\n    })\n  }),\n  removeLineClass: docMethodOp(function(handle, where, cls) {\n    return changeLine(this, handle, where == \"gutter\" ? \"gutter\" : \"class\", function (line) {\n      var prop = where == \"text\" ? \"textClass\"\n               : where == \"background\" ? \"bgClass\"\n               : where == \"gutter\" ? \"gutterClass\" : \"wrapClass\";\n      var cur = line[prop];\n      if (!cur) { return false }\n      else if (cls == null) { line[prop] = null; }\n      else {\n        var found = cur.match(classTest(cls));\n        if (!found) { return false }\n        var end = found.index + found[0].length;\n        line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? \"\" : \" \") + cur.slice(end) || null;\n      }\n      return true\n    })\n  }),\n\n  addLineWidget: docMethodOp(function(handle, node, options) {\n    return addLineWidget(this, handle, node, options)\n  }),\n  removeLineWidget: function(widget) { widget.clear(); },\n\n  markText: function(from, to, options) {\n    return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || \"range\")\n  },\n  setBookmark: function(pos, options) {\n    var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),\n                    insertLeft: options && options.insertLeft,\n                    clearWhenEmpty: false, shared: options && options.shared,\n                    handleMouseEvents: options && options.handleMouseEvents};\n    pos = clipPos(this, pos);\n    return markText(this, pos, pos, realOpts, \"bookmark\")\n  },\n  findMarksAt: function(pos) {\n    pos = clipPos(this, pos);\n    var markers = [], spans = getLine(this, pos.line).markedSpans;\n    if (spans) { for (var i = 0; i < spans.length; ++i) {\n      var span = spans[i];\n      if ((span.from == null || span.from <= pos.ch) &&\n          (span.to == null || span.to >= pos.ch))\n        { markers.push(span.marker.parent || span.marker); }\n    } }\n    return markers\n  },\n  findMarks: function(from, to, filter) {\n    from = clipPos(this, from); to = clipPos(this, to);\n    var found = [], lineNo$$1 = from.line;\n    this.iter(from.line, to.line + 1, function (line) {\n      var spans = line.markedSpans;\n      if (spans) { for (var i = 0; i < spans.length; i++) {\n        var span = spans[i];\n        if (!(span.to != null && lineNo$$1 == from.line && from.ch >= span.to ||\n              span.from == null && lineNo$$1 != from.line ||\n              span.from != null && lineNo$$1 == to.line && span.from >= to.ch) &&\n            (!filter || filter(span.marker)))\n          { found.push(span.marker.parent || span.marker); }\n      } }\n      ++lineNo$$1;\n    });\n    return found\n  },\n  getAllMarks: function() {\n    var markers = [];\n    this.iter(function (line) {\n      var sps = line.markedSpans;\n      if (sps) { for (var i = 0; i < sps.length; ++i)\n        { if (sps[i].from != null) { markers.push(sps[i].marker); } } }\n    });\n    return markers\n  },\n\n  posFromIndex: function(off) {\n    var ch, lineNo$$1 = this.first, sepSize = this.lineSeparator().length;\n    this.iter(function (line) {\n      var sz = line.text.length + sepSize;\n      if (sz > off) { ch = off; return true }\n      off -= sz;\n      ++lineNo$$1;\n    });\n    return clipPos(this, Pos(lineNo$$1, ch))\n  },\n  indexFromPos: function (coords) {\n    coords = clipPos(this, coords);\n    var index = coords.ch;\n    if (coords.line < this.first || coords.ch < 0) { return 0 }\n    var sepSize = this.lineSeparator().length;\n    this.iter(this.first, coords.line, function (line) { // iter aborts when callback returns a truthy value\n      index += line.text.length + sepSize;\n    });\n    return index\n  },\n\n  copy: function(copyHistory) {\n    var doc = new Doc(getLines(this, this.first, this.first + this.size),\n                      this.modeOption, this.first, this.lineSep, this.direction);\n    doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;\n    doc.sel = this.sel;\n    doc.extend = false;\n    if (copyHistory) {\n      doc.history.undoDepth = this.history.undoDepth;\n      doc.setHistory(this.getHistory());\n    }\n    return doc\n  },\n\n  linkedDoc: function(options) {\n    if (!options) { options = {}; }\n    var from = this.first, to = this.first + this.size;\n    if (options.from != null && options.from > from) { from = options.from; }\n    if (options.to != null && options.to < to) { to = options.to; }\n    var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep, this.direction);\n    if (options.sharedHist) { copy.history = this.history\n    ; }(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});\n    copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];\n    copySharedMarkers(copy, findSharedMarkers(this));\n    return copy\n  },\n  unlinkDoc: function(other) {\n    var this$1 = this;\n\n    if (other instanceof CodeMirror$1) { other = other.doc; }\n    if (this.linked) { for (var i = 0; i < this.linked.length; ++i) {\n      var link = this$1.linked[i];\n      if (link.doc != other) { continue }\n      this$1.linked.splice(i, 1);\n      other.unlinkDoc(this$1);\n      detachSharedMarkers(findSharedMarkers(this$1));\n      break\n    } }\n    // If the histories were shared, split them again\n    if (other.history == this.history) {\n      var splitIds = [other.id];\n      linkedDocs(other, function (doc) { return splitIds.push(doc.id); }, true);\n      other.history = new History(null);\n      other.history.done = copyHistoryArray(this.history.done, splitIds);\n      other.history.undone = copyHistoryArray(this.history.undone, splitIds);\n    }\n  },\n  iterLinkedDocs: function(f) {linkedDocs(this, f);},\n\n  getMode: function() {return this.mode},\n  getEditor: function() {return this.cm},\n\n  splitLines: function(str) {\n    if (this.lineSep) { return str.split(this.lineSep) }\n    return splitLinesAuto(str)\n  },\n  lineSeparator: function() { return this.lineSep || \"\\n\" },\n\n  setDirection: docMethodOp(function (dir) {\n    if (dir != \"rtl\") { dir = \"ltr\"; }\n    if (dir == this.direction) { return }\n    this.direction = dir;\n    this.iter(function (line) { return line.order = null; });\n    if (this.cm) { directionChanged(this.cm); }\n  })\n});\n\n// Public alias.\nDoc.prototype.eachLine = Doc.prototype.iter;\n\n// Kludge to work around strange IE behavior where it'll sometimes\n// re-fire a series of drag-related events right after the drop (#1551)\nvar lastDrop = 0;\n\nfunction onDrop(e) {\n  var cm = this;\n  clearDragCursor(cm);\n  if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))\n    { return }\n  e_preventDefault(e);\n  if (ie) { lastDrop = +new Date; }\n  var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;\n  if (!pos || cm.isReadOnly()) { return }\n  // Might be a file drop, in which case we simply extract the text\n  // and insert it.\n  if (files && files.length && window.FileReader && window.File) {\n    var n = files.length, text = Array(n), read = 0;\n    var loadFile = function (file, i) {\n      if (cm.options.allowDropFileTypes &&\n          indexOf(cm.options.allowDropFileTypes, file.type) == -1)\n        { return }\n\n      var reader = new FileReader;\n      reader.onload = operation(cm, function () {\n        var content = reader.result;\n        if (/[\\x00-\\x08\\x0e-\\x1f]{2}/.test(content)) { content = \"\"; }\n        text[i] = content;\n        if (++read == n) {\n          pos = clipPos(cm.doc, pos);\n          var change = {from: pos, to: pos,\n                        text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())),\n                        origin: \"paste\"};\n          makeChange(cm.doc, change);\n          setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));\n        }\n      });\n      reader.readAsText(file);\n    };\n    for (var i = 0; i < n; ++i) { loadFile(files[i], i); }\n  } else { // Normal drop\n    // Don't do a replace if the drop happened inside of the selected text.\n    if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {\n      cm.state.draggingText(e);\n      // Ensure the editor is re-focused\n      setTimeout(function () { return cm.display.input.focus(); }, 20);\n      return\n    }\n    try {\n      var text$1 = e.dataTransfer.getData(\"Text\");\n      if (text$1) {\n        var selected;\n        if (cm.state.draggingText && !cm.state.draggingText.copy)\n          { selected = cm.listSelections(); }\n        setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));\n        if (selected) { for (var i$1 = 0; i$1 < selected.length; ++i$1)\n          { replaceRange(cm.doc, \"\", selected[i$1].anchor, selected[i$1].head, \"drag\"); } }\n        cm.replaceSelection(text$1, \"around\", \"paste\");\n        cm.display.input.focus();\n      }\n    }\n    catch(e){}\n  }\n}\n\nfunction onDragStart(cm, e) {\n  if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return }\n  if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) { return }\n\n  e.dataTransfer.setData(\"Text\", cm.getSelection());\n  e.dataTransfer.effectAllowed = \"copyMove\";\n\n  // Use dummy image instead of default browsers image.\n  // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.\n  if (e.dataTransfer.setDragImage && !safari) {\n    var img = elt(\"img\", null, null, \"position: fixed; left: 0; top: 0;\");\n    img.src = \"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\";\n    if (presto) {\n      img.width = img.height = 1;\n      cm.display.wrapper.appendChild(img);\n      // Force a relayout, or Opera won't use our image for some obscure reason\n      img._top = img.offsetTop;\n    }\n    e.dataTransfer.setDragImage(img, 0, 0);\n    if (presto) { img.parentNode.removeChild(img); }\n  }\n}\n\nfunction onDragOver(cm, e) {\n  var pos = posFromMouse(cm, e);\n  if (!pos) { return }\n  var frag = document.createDocumentFragment();\n  drawSelectionCursor(cm, pos, frag);\n  if (!cm.display.dragCursor) {\n    cm.display.dragCursor = elt(\"div\", null, \"CodeMirror-cursors CodeMirror-dragcursors\");\n    cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);\n  }\n  removeChildrenAndAdd(cm.display.dragCursor, frag);\n}\n\nfunction clearDragCursor(cm) {\n  if (cm.display.dragCursor) {\n    cm.display.lineSpace.removeChild(cm.display.dragCursor);\n    cm.display.dragCursor = null;\n  }\n}\n\n// These must be handled carefully, because naively registering a\n// handler for each editor will cause the editors to never be\n// garbage collected.\n\nfunction forEachCodeMirror(f) {\n  if (!document.getElementsByClassName) { return }\n  var byClass = document.getElementsByClassName(\"CodeMirror\");\n  for (var i = 0; i < byClass.length; i++) {\n    var cm = byClass[i].CodeMirror;\n    if (cm) { f(cm); }\n  }\n}\n\nvar globalsRegistered = false;\nfunction ensureGlobalHandlers() {\n  if (globalsRegistered) { return }\n  registerGlobalHandlers();\n  globalsRegistered = true;\n}\nfunction registerGlobalHandlers() {\n  // When the window resizes, we need to refresh active editors.\n  var resizeTimer;\n  on(window, \"resize\", function () {\n    if (resizeTimer == null) { resizeTimer = setTimeout(function () {\n      resizeTimer = null;\n      forEachCodeMirror(onResize);\n    }, 100); }\n  });\n  // When the window loses focus, we want to show the editor as blurred\n  on(window, \"blur\", function () { return forEachCodeMirror(onBlur); });\n}\n// Called when the window resizes\nfunction onResize(cm) {\n  var d = cm.display;\n  if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth)\n    { return }\n  // Might be a text scaling operation, clear size caches.\n  d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;\n  d.scrollbarsClipped = false;\n  cm.setSize();\n}\n\nvar keyNames = {\n  3: \"Enter\", 8: \"Backspace\", 9: \"Tab\", 13: \"Enter\", 16: \"Shift\", 17: \"Ctrl\", 18: \"Alt\",\n  19: \"Pause\", 20: \"CapsLock\", 27: \"Esc\", 32: \"Space\", 33: \"PageUp\", 34: \"PageDown\", 35: \"End\",\n  36: \"Home\", 37: \"Left\", 38: \"Up\", 39: \"Right\", 40: \"Down\", 44: \"PrintScrn\", 45: \"Insert\",\n  46: \"Delete\", 59: \";\", 61: \"=\", 91: \"Mod\", 92: \"Mod\", 93: \"Mod\",\n  106: \"*\", 107: \"=\", 109: \"-\", 110: \".\", 111: \"/\", 127: \"Delete\",\n  173: \"-\", 186: \";\", 187: \"=\", 188: \",\", 189: \"-\", 190: \".\", 191: \"/\", 192: \"`\", 219: \"[\", 220: \"\\\\\",\n  221: \"]\", 222: \"'\", 63232: \"Up\", 63233: \"Down\", 63234: \"Left\", 63235: \"Right\", 63272: \"Delete\",\n  63273: \"Home\", 63275: \"End\", 63276: \"PageUp\", 63277: \"PageDown\", 63302: \"Insert\"\n};\n\n// Number keys\nfor (var i = 0; i < 10; i++) { keyNames[i + 48] = keyNames[i + 96] = String(i); }\n// Alphabetic keys\nfor (var i$1 = 65; i$1 <= 90; i$1++) { keyNames[i$1] = String.fromCharCode(i$1); }\n// Function keys\nfor (var i$2 = 1; i$2 <= 12; i$2++) { keyNames[i$2 + 111] = keyNames[i$2 + 63235] = \"F\" + i$2; }\n\nvar keyMap = {};\n\nkeyMap.basic = {\n  \"Left\": \"goCharLeft\", \"Right\": \"goCharRight\", \"Up\": \"goLineUp\", \"Down\": \"goLineDown\",\n  \"End\": \"goLineEnd\", \"Home\": \"goLineStartSmart\", \"PageUp\": \"goPageUp\", \"PageDown\": \"goPageDown\",\n  \"Delete\": \"delCharAfter\", \"Backspace\": \"delCharBefore\", \"Shift-Backspace\": \"delCharBefore\",\n  \"Tab\": \"defaultTab\", \"Shift-Tab\": \"indentAuto\",\n  \"Enter\": \"newlineAndIndent\", \"Insert\": \"toggleOverwrite\",\n  \"Esc\": \"singleSelection\"\n};\n// Note that the save and find-related commands aren't defined by\n// default. User code or addons can define them. Unknown commands\n// are simply ignored.\nkeyMap.pcDefault = {\n  \"Ctrl-A\": \"selectAll\", \"Ctrl-D\": \"deleteLine\", \"Ctrl-Z\": \"undo\", \"Shift-Ctrl-Z\": \"redo\", \"Ctrl-Y\": \"redo\",\n  \"Ctrl-Home\": \"goDocStart\", \"Ctrl-End\": \"goDocEnd\", \"Ctrl-Up\": \"goLineUp\", \"Ctrl-Down\": \"goLineDown\",\n  \"Ctrl-Left\": \"goGroupLeft\", \"Ctrl-Right\": \"goGroupRight\", \"Alt-Left\": \"goLineStart\", \"Alt-Right\": \"goLineEnd\",\n  \"Ctrl-Backspace\": \"delGroupBefore\", \"Ctrl-Delete\": \"delGroupAfter\", \"Ctrl-S\": \"save\", \"Ctrl-F\": \"find\",\n  \"Ctrl-G\": \"findNext\", \"Shift-Ctrl-G\": \"findPrev\", \"Shift-Ctrl-F\": \"replace\", \"Shift-Ctrl-R\": \"replaceAll\",\n  \"Ctrl-[\": \"indentLess\", \"Ctrl-]\": \"indentMore\",\n  \"Ctrl-U\": \"undoSelection\", \"Shift-Ctrl-U\": \"redoSelection\", \"Alt-U\": \"redoSelection\",\n  fallthrough: \"basic\"\n};\n// Very basic readline/emacs-style bindings, which are standard on Mac.\nkeyMap.emacsy = {\n  \"Ctrl-F\": \"goCharRight\", \"Ctrl-B\": \"goCharLeft\", \"Ctrl-P\": \"goLineUp\", \"Ctrl-N\": \"goLineDown\",\n  \"Alt-F\": \"goWordRight\", \"Alt-B\": \"goWordLeft\", \"Ctrl-A\": \"goLineStart\", \"Ctrl-E\": \"goLineEnd\",\n  \"Ctrl-V\": \"goPageDown\", \"Shift-Ctrl-V\": \"goPageUp\", \"Ctrl-D\": \"delCharAfter\", \"Ctrl-H\": \"delCharBefore\",\n  \"Alt-D\": \"delWordAfter\", \"Alt-Backspace\": \"delWordBefore\", \"Ctrl-K\": \"killLine\", \"Ctrl-T\": \"transposeChars\",\n  \"Ctrl-O\": \"openLine\"\n};\nkeyMap.macDefault = {\n  \"Cmd-A\": \"selectAll\", \"Cmd-D\": \"deleteLine\", \"Cmd-Z\": \"undo\", \"Shift-Cmd-Z\": \"redo\", \"Cmd-Y\": \"redo\",\n  \"Cmd-Home\": \"goDocStart\", \"Cmd-Up\": \"goDocStart\", \"Cmd-End\": \"goDocEnd\", \"Cmd-Down\": \"goDocEnd\", \"Alt-Left\": \"goGroupLeft\",\n  \"Alt-Right\": \"goGroupRight\", \"Cmd-Left\": \"goLineLeft\", \"Cmd-Right\": \"goLineRight\", \"Alt-Backspace\": \"delGroupBefore\",\n  \"Ctrl-Alt-Backspace\": \"delGroupAfter\", \"Alt-Delete\": \"delGroupAfter\", \"Cmd-S\": \"save\", \"Cmd-F\": \"find\",\n  \"Cmd-G\": \"findNext\", \"Shift-Cmd-G\": \"findPrev\", \"Cmd-Alt-F\": \"replace\", \"Shift-Cmd-Alt-F\": \"replaceAll\",\n  \"Cmd-[\": \"indentLess\", \"Cmd-]\": \"indentMore\", \"Cmd-Backspace\": \"delWrappedLineLeft\", \"Cmd-Delete\": \"delWrappedLineRight\",\n  \"Cmd-U\": \"undoSelection\", \"Shift-Cmd-U\": \"redoSelection\", \"Ctrl-Up\": \"goDocStart\", \"Ctrl-Down\": \"goDocEnd\",\n  fallthrough: [\"basic\", \"emacsy\"]\n};\nkeyMap[\"default\"] = mac ? keyMap.macDefault : keyMap.pcDefault;\n\n// KEYMAP DISPATCH\n\nfunction normalizeKeyName(name) {\n  var parts = name.split(/-(?!$)/);\n  name = parts[parts.length - 1];\n  var alt, ctrl, shift, cmd;\n  for (var i = 0; i < parts.length - 1; i++) {\n    var mod = parts[i];\n    if (/^(cmd|meta|m)$/i.test(mod)) { cmd = true; }\n    else if (/^a(lt)?$/i.test(mod)) { alt = true; }\n    else if (/^(c|ctrl|control)$/i.test(mod)) { ctrl = true; }\n    else if (/^s(hift)?$/i.test(mod)) { shift = true; }\n    else { throw new Error(\"Unrecognized modifier name: \" + mod) }\n  }\n  if (alt) { name = \"Alt-\" + name; }\n  if (ctrl) { name = \"Ctrl-\" + name; }\n  if (cmd) { name = \"Cmd-\" + name; }\n  if (shift) { name = \"Shift-\" + name; }\n  return name\n}\n\n// This is a kludge to keep keymaps mostly working as raw objects\n// (backwards compatibility) while at the same time support features\n// like normalization and multi-stroke key bindings. It compiles a\n// new normalized keymap, and then updates the old object to reflect\n// this.\nfunction normalizeKeyMap(keymap) {\n  var copy = {};\n  for (var keyname in keymap) { if (keymap.hasOwnProperty(keyname)) {\n    var value = keymap[keyname];\n    if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) { continue }\n    if (value == \"...\") { delete keymap[keyname]; continue }\n\n    var keys = map(keyname.split(\" \"), normalizeKeyName);\n    for (var i = 0; i < keys.length; i++) {\n      var val = (void 0), name = (void 0);\n      if (i == keys.length - 1) {\n        name = keys.join(\" \");\n        val = value;\n      } else {\n        name = keys.slice(0, i + 1).join(\" \");\n        val = \"...\";\n      }\n      var prev = copy[name];\n      if (!prev) { copy[name] = val; }\n      else if (prev != val) { throw new Error(\"Inconsistent bindings for \" + name) }\n    }\n    delete keymap[keyname];\n  } }\n  for (var prop in copy) { keymap[prop] = copy[prop]; }\n  return keymap\n}\n\nfunction lookupKey(key, map$$1, handle, context) {\n  map$$1 = getKeyMap(map$$1);\n  var found = map$$1.call ? map$$1.call(key, context) : map$$1[key];\n  if (found === false) { return \"nothing\" }\n  if (found === \"...\") { return \"multi\" }\n  if (found != null && handle(found)) { return \"handled\" }\n\n  if (map$$1.fallthrough) {\n    if (Object.prototype.toString.call(map$$1.fallthrough) != \"[object Array]\")\n      { return lookupKey(key, map$$1.fallthrough, handle, context) }\n    for (var i = 0; i < map$$1.fallthrough.length; i++) {\n      var result = lookupKey(key, map$$1.fallthrough[i], handle, context);\n      if (result) { return result }\n    }\n  }\n}\n\n// Modifier key presses don't count as 'real' key presses for the\n// purpose of keymap fallthrough.\nfunction isModifierKey(value) {\n  var name = typeof value == \"string\" ? value : keyNames[value.keyCode];\n  return name == \"Ctrl\" || name == \"Alt\" || name == \"Shift\" || name == \"Mod\"\n}\n\nfunction addModifierNames(name, event, noShift) {\n  var base = name;\n  if (event.altKey && base != \"Alt\") { name = \"Alt-\" + name; }\n  if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != \"Ctrl\") { name = \"Ctrl-\" + name; }\n  if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != \"Cmd\") { name = \"Cmd-\" + name; }\n  if (!noShift && event.shiftKey && base != \"Shift\") { name = \"Shift-\" + name; }\n  return name\n}\n\n// Look up the name of a key as indicated by an event object.\nfunction keyName(event, noShift) {\n  if (presto && event.keyCode == 34 && event[\"char\"]) { return false }\n  var name = keyNames[event.keyCode];\n  if (name == null || event.altGraphKey) { return false }\n  return addModifierNames(name, event, noShift)\n}\n\nfunction getKeyMap(val) {\n  return typeof val == \"string\" ? keyMap[val] : val\n}\n\n// Helper for deleting text near the selection(s), used to implement\n// backspace, delete, and similar functionality.\nfunction deleteNearSelection(cm, compute) {\n  var ranges = cm.doc.sel.ranges, kill = [];\n  // Build up a set of ranges to kill first, merging overlapping\n  // ranges.\n  for (var i = 0; i < ranges.length; i++) {\n    var toKill = compute(ranges[i]);\n    while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {\n      var replaced = kill.pop();\n      if (cmp(replaced.from, toKill.from) < 0) {\n        toKill.from = replaced.from;\n        break\n      }\n    }\n    kill.push(toKill);\n  }\n  // Next, remove those actual ranges.\n  runInOp(cm, function () {\n    for (var i = kill.length - 1; i >= 0; i--)\n      { replaceRange(cm.doc, \"\", kill[i].from, kill[i].to, \"+delete\"); }\n    ensureCursorVisible(cm);\n  });\n}\n\n// Commands are parameter-less actions that can be performed on an\n// editor, mostly used for keybindings.\nvar commands = {\n  selectAll: selectAll,\n  singleSelection: function (cm) { return cm.setSelection(cm.getCursor(\"anchor\"), cm.getCursor(\"head\"), sel_dontScroll); },\n  killLine: function (cm) { return deleteNearSelection(cm, function (range) {\n    if (range.empty()) {\n      var len = getLine(cm.doc, range.head.line).text.length;\n      if (range.head.ch == len && range.head.line < cm.lastLine())\n        { return {from: range.head, to: Pos(range.head.line + 1, 0)} }\n      else\n        { return {from: range.head, to: Pos(range.head.line, len)} }\n    } else {\n      return {from: range.from(), to: range.to()}\n    }\n  }); },\n  deleteLine: function (cm) { return deleteNearSelection(cm, function (range) { return ({\n    from: Pos(range.from().line, 0),\n    to: clipPos(cm.doc, Pos(range.to().line + 1, 0))\n  }); }); },\n  delLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { return ({\n    from: Pos(range.from().line, 0), to: range.from()\n  }); }); },\n  delWrappedLineLeft: function (cm) { return deleteNearSelection(cm, function (range) {\n    var top = cm.charCoords(range.head, \"div\").top + 5;\n    var leftPos = cm.coordsChar({left: 0, top: top}, \"div\");\n    return {from: leftPos, to: range.from()}\n  }); },\n  delWrappedLineRight: function (cm) { return deleteNearSelection(cm, function (range) {\n    var top = cm.charCoords(range.head, \"div\").top + 5;\n    var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, \"div\");\n    return {from: range.from(), to: rightPos }\n  }); },\n  undo: function (cm) { return cm.undo(); },\n  redo: function (cm) { return cm.redo(); },\n  undoSelection: function (cm) { return cm.undoSelection(); },\n  redoSelection: function (cm) { return cm.redoSelection(); },\n  goDocStart: function (cm) { return cm.extendSelection(Pos(cm.firstLine(), 0)); },\n  goDocEnd: function (cm) { return cm.extendSelection(Pos(cm.lastLine())); },\n  goLineStart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); },\n    {origin: \"+move\", bias: 1}\n  ); },\n  goLineStartSmart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStartSmart(cm, range.head); },\n    {origin: \"+move\", bias: 1}\n  ); },\n  goLineEnd: function (cm) { return cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); },\n    {origin: \"+move\", bias: -1}\n  ); },\n  goLineRight: function (cm) { return cm.extendSelectionsBy(function (range) {\n    var top = cm.cursorCoords(range.head, \"div\").top + 5;\n    return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, \"div\")\n  }, sel_move); },\n  goLineLeft: function (cm) { return cm.extendSelectionsBy(function (range) {\n    var top = cm.cursorCoords(range.head, \"div\").top + 5;\n    return cm.coordsChar({left: 0, top: top}, \"div\")\n  }, sel_move); },\n  goLineLeftSmart: function (cm) { return cm.extendSelectionsBy(function (range) {\n    var top = cm.charCoords(range.head, \"div\").top + 5;\n    var pos = cm.coordsChar({left: 0, top: top}, \"div\");\n    if (pos.ch < cm.getLine(pos.line).search(/\\S/)) { return lineStartSmart(cm, range.head) }\n    return pos\n  }, sel_move); },\n  goLineUp: function (cm) { return cm.moveV(-1, \"line\"); },\n  goLineDown: function (cm) { return cm.moveV(1, \"line\"); },\n  goPageUp: function (cm) { return cm.moveV(-1, \"page\"); },\n  goPageDown: function (cm) { return cm.moveV(1, \"page\"); },\n  goCharLeft: function (cm) { return cm.moveH(-1, \"char\"); },\n  goCharRight: function (cm) { return cm.moveH(1, \"char\"); },\n  goColumnLeft: function (cm) { return cm.moveH(-1, \"column\"); },\n  goColumnRight: function (cm) { return cm.moveH(1, \"column\"); },\n  goWordLeft: function (cm) { return cm.moveH(-1, \"word\"); },\n  goGroupRight: function (cm) { return cm.moveH(1, \"group\"); },\n  goGroupLeft: function (cm) { return cm.moveH(-1, \"group\"); },\n  goWordRight: function (cm) { return cm.moveH(1, \"word\"); },\n  delCharBefore: function (cm) { return cm.deleteH(-1, \"char\"); },\n  delCharAfter: function (cm) { return cm.deleteH(1, \"char\"); },\n  delWordBefore: function (cm) { return cm.deleteH(-1, \"word\"); },\n  delWordAfter: function (cm) { return cm.deleteH(1, \"word\"); },\n  delGroupBefore: function (cm) { return cm.deleteH(-1, \"group\"); },\n  delGroupAfter: function (cm) { return cm.deleteH(1, \"group\"); },\n  indentAuto: function (cm) { return cm.indentSelection(\"smart\"); },\n  indentMore: function (cm) { return cm.indentSelection(\"add\"); },\n  indentLess: function (cm) { return cm.indentSelection(\"subtract\"); },\n  insertTab: function (cm) { return cm.replaceSelection(\"\\t\"); },\n  insertSoftTab: function (cm) {\n    var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;\n    for (var i = 0; i < ranges.length; i++) {\n      var pos = ranges[i].from();\n      var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);\n      spaces.push(spaceStr(tabSize - col % tabSize));\n    }\n    cm.replaceSelections(spaces);\n  },\n  defaultTab: function (cm) {\n    if (cm.somethingSelected()) { cm.indentSelection(\"add\"); }\n    else { cm.execCommand(\"insertTab\"); }\n  },\n  // Swap the two chars left and right of each selection's head.\n  // Move cursor behind the two swapped characters afterwards.\n  //\n  // Doesn't consider line feeds a character.\n  // Doesn't scan more than one line above to find a character.\n  // Doesn't do anything on an empty line.\n  // Doesn't do anything with non-empty selections.\n  transposeChars: function (cm) { return runInOp(cm, function () {\n    var ranges = cm.listSelections(), newSel = [];\n    for (var i = 0; i < ranges.length; i++) {\n      if (!ranges[i].empty()) { continue }\n      var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;\n      if (line) {\n        if (cur.ch == line.length) { cur = new Pos(cur.line, cur.ch - 1); }\n        if (cur.ch > 0) {\n          cur = new Pos(cur.line, cur.ch + 1);\n          cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),\n                          Pos(cur.line, cur.ch - 2), cur, \"+transpose\");\n        } else if (cur.line > cm.doc.first) {\n          var prev = getLine(cm.doc, cur.line - 1).text;\n          if (prev) {\n            cur = new Pos(cur.line, 1);\n            cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +\n                            prev.charAt(prev.length - 1),\n                            Pos(cur.line - 1, prev.length - 1), cur, \"+transpose\");\n          }\n        }\n      }\n      newSel.push(new Range(cur, cur));\n    }\n    cm.setSelections(newSel);\n  }); },\n  newlineAndIndent: function (cm) { return runInOp(cm, function () {\n    var sels = cm.listSelections();\n    for (var i = sels.length - 1; i >= 0; i--)\n      { cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, \"+input\"); }\n    sels = cm.listSelections();\n    for (var i$1 = 0; i$1 < sels.length; i$1++)\n      { cm.indentLine(sels[i$1].from().line, null, true); }\n    ensureCursorVisible(cm);\n  }); },\n  openLine: function (cm) { return cm.replaceSelection(\"\\n\", \"start\"); },\n  toggleOverwrite: function (cm) { return cm.toggleOverwrite(); }\n};\n\n\nfunction lineStart(cm, lineN) {\n  var line = getLine(cm.doc, lineN);\n  var visual = visualLine(line);\n  if (visual != line) { lineN = lineNo(visual); }\n  return endOfLine(true, cm, visual, lineN, 1)\n}\nfunction lineEnd(cm, lineN) {\n  var line = getLine(cm.doc, lineN);\n  var visual = visualLineEnd(line);\n  if (visual != line) { lineN = lineNo(visual); }\n  return endOfLine(true, cm, line, lineN, -1)\n}\nfunction lineStartSmart(cm, pos) {\n  var start = lineStart(cm, pos.line);\n  var line = getLine(cm.doc, start.line);\n  var order = getOrder(line, cm.doc.direction);\n  if (!order || order[0].level == 0) {\n    var firstNonWS = Math.max(0, line.text.search(/\\S/));\n    var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;\n    return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky)\n  }\n  return start\n}\n\n// Run a handler that was bound to a key.\nfunction doHandleBinding(cm, bound, dropShift) {\n  if (typeof bound == \"string\") {\n    bound = commands[bound];\n    if (!bound) { return false }\n  }\n  // Ensure previous input has been read, so that the handler sees a\n  // consistent view of the document\n  cm.display.input.ensurePolled();\n  var prevShift = cm.display.shift, done = false;\n  try {\n    if (cm.isReadOnly()) { cm.state.suppressEdits = true; }\n    if (dropShift) { cm.display.shift = false; }\n    done = bound(cm) != Pass;\n  } finally {\n    cm.display.shift = prevShift;\n    cm.state.suppressEdits = false;\n  }\n  return done\n}\n\nfunction lookupKeyForEditor(cm, name, handle) {\n  for (var i = 0; i < cm.state.keyMaps.length; i++) {\n    var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);\n    if (result) { return result }\n  }\n  return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))\n    || lookupKey(name, cm.options.keyMap, handle, cm)\n}\n\n// Note that, despite the name, this function is also used to check\n// for bound mouse clicks.\n\nvar stopSeq = new Delayed;\nfunction dispatchKey(cm, name, e, handle) {\n  var seq = cm.state.keySeq;\n  if (seq) {\n    if (isModifierKey(name)) { return \"handled\" }\n    stopSeq.set(50, function () {\n      if (cm.state.keySeq == seq) {\n        cm.state.keySeq = null;\n        cm.display.input.reset();\n      }\n    });\n    name = seq + \" \" + name;\n  }\n  var result = lookupKeyForEditor(cm, name, handle);\n\n  if (result == \"multi\")\n    { cm.state.keySeq = name; }\n  if (result == \"handled\")\n    { signalLater(cm, \"keyHandled\", cm, name, e); }\n\n  if (result == \"handled\" || result == \"multi\") {\n    e_preventDefault(e);\n    restartBlink(cm);\n  }\n\n  if (seq && !result && /\\'$/.test(name)) {\n    e_preventDefault(e);\n    return true\n  }\n  return !!result\n}\n\n// Handle a key from the keydown event.\nfunction handleKeyBinding(cm, e) {\n  var name = keyName(e, true);\n  if (!name) { return false }\n\n  if (e.shiftKey && !cm.state.keySeq) {\n    // First try to resolve full name (including 'Shift-'). Failing\n    // that, see if there is a cursor-motion command (starting with\n    // 'go') bound to the keyname without 'Shift-'.\n    return dispatchKey(cm, \"Shift-\" + name, e, function (b) { return doHandleBinding(cm, b, true); })\n        || dispatchKey(cm, name, e, function (b) {\n             if (typeof b == \"string\" ? /^go[A-Z]/.test(b) : b.motion)\n               { return doHandleBinding(cm, b) }\n           })\n  } else {\n    return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); })\n  }\n}\n\n// Handle a key from the keypress event\nfunction handleCharBinding(cm, e, ch) {\n  return dispatchKey(cm, \"'\" + ch + \"'\", e, function (b) { return doHandleBinding(cm, b, true); })\n}\n\nvar lastStoppedKey = null;\nfunction onKeyDown(e) {\n  var cm = this;\n  cm.curOp.focus = activeElt();\n  if (signalDOMEvent(cm, e)) { return }\n  // IE does strange things with escape.\n  if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false; }\n  var code = e.keyCode;\n  cm.display.shift = code == 16 || e.shiftKey;\n  var handled = handleKeyBinding(cm, e);\n  if (presto) {\n    lastStoppedKey = handled ? code : null;\n    // Opera has no cut event... we try to at least catch the key combo\n    if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))\n      { cm.replaceSelection(\"\", null, \"cut\"); }\n  }\n\n  // Turn mouse into crosshair when Alt is held on Mac.\n  if (code == 18 && !/\\bCodeMirror-crosshair\\b/.test(cm.display.lineDiv.className))\n    { showCrossHair(cm); }\n}\n\nfunction showCrossHair(cm) {\n  var lineDiv = cm.display.lineDiv;\n  addClass(lineDiv, \"CodeMirror-crosshair\");\n\n  function up(e) {\n    if (e.keyCode == 18 || !e.altKey) {\n      rmClass(lineDiv, \"CodeMirror-crosshair\");\n      off(document, \"keyup\", up);\n      off(document, \"mouseover\", up);\n    }\n  }\n  on(document, \"keyup\", up);\n  on(document, \"mouseover\", up);\n}\n\nfunction onKeyUp(e) {\n  if (e.keyCode == 16) { this.doc.sel.shift = false; }\n  signalDOMEvent(this, e);\n}\n\nfunction onKeyPress(e) {\n  var cm = this;\n  if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return }\n  var keyCode = e.keyCode, charCode = e.charCode;\n  if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return}\n  if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) { return }\n  var ch = String.fromCharCode(charCode == null ? keyCode : charCode);\n  // Some browsers fire keypress events for backspace\n  if (ch == \"\\x08\") { return }\n  if (handleCharBinding(cm, e, ch)) { return }\n  cm.display.input.onKeyPress(e);\n}\n\nvar DOUBLECLICK_DELAY = 400;\n\nvar PastClick = function(time, pos, button) {\n  this.time = time;\n  this.pos = pos;\n  this.button = button;\n};\n\nPastClick.prototype.compare = function (time, pos, button) {\n  return this.time + DOUBLECLICK_DELAY > time &&\n    cmp(pos, this.pos) == 0 && button == this.button\n};\n\nvar lastClick;\nvar lastDoubleClick;\nfunction clickRepeat(pos, button) {\n  var now = +new Date;\n  if (lastDoubleClick && lastDoubleClick.compare(now, pos, button)) {\n    lastClick = lastDoubleClick = null;\n    return \"triple\"\n  } else if (lastClick && lastClick.compare(now, pos, button)) {\n    lastDoubleClick = new PastClick(now, pos, button);\n    lastClick = null;\n    return \"double\"\n  } else {\n    lastClick = new PastClick(now, pos, button);\n    lastDoubleClick = null;\n    return \"single\"\n  }\n}\n\n// A mouse down can be a single click, double click, triple click,\n// start of selection drag, start of text drag, new cursor\n// (ctrl-click), rectangle drag (alt-drag), or xwin\n// middle-click-paste. Or it might be a click on something we should\n// not interfere with, such as a scrollbar or widget.\nfunction onMouseDown(e) {\n  var cm = this, display = cm.display;\n  if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) { return }\n  display.input.ensurePolled();\n  display.shift = e.shiftKey;\n\n  if (eventInWidget(display, e)) {\n    if (!webkit) {\n      // Briefly turn off draggability, to allow widgets to do\n      // normal dragging things.\n      display.scroller.draggable = false;\n      setTimeout(function () { return display.scroller.draggable = true; }, 100);\n    }\n    return\n  }\n  if (clickInGutter(cm, e)) { return }\n  var pos = posFromMouse(cm, e), button = e_button(e), repeat = pos ? clickRepeat(pos, button) : \"single\";\n  window.focus();\n\n  // #3261: make sure, that we're not starting a second selection\n  if (button == 1 && cm.state.selectingText)\n    { cm.state.selectingText(e); }\n\n  if (pos && handleMappedButton(cm, button, pos, repeat, e)) { return }\n\n  if (button == 1) {\n    if (pos) { leftButtonDown(cm, pos, repeat, e); }\n    else if (e_target(e) == display.scroller) { e_preventDefault(e); }\n  } else if (button == 2) {\n    if (pos) { extendSelection(cm.doc, pos); }\n    setTimeout(function () { return display.input.focus(); }, 20);\n  } else if (button == 3) {\n    if (captureRightClick) { onContextMenu(cm, e); }\n    else { delayBlurEvent(cm); }\n  }\n}\n\nfunction handleMappedButton(cm, button, pos, repeat, event) {\n  var name = \"Click\";\n  if (repeat == \"double\") { name = \"Double\" + name; }\n  else if (repeat == \"triple\") { name = \"Triple\" + name; }\n  name = (button == 1 ? \"Left\" : button == 2 ? \"Middle\" : \"Right\") + name;\n\n  return dispatchKey(cm,  addModifierNames(name, event), event, function (bound) {\n    if (typeof bound == \"string\") { bound = commands[bound]; }\n    if (!bound) { return false }\n    var done = false;\n    try {\n      if (cm.isReadOnly()) { cm.state.suppressEdits = true; }\n      done = bound(cm, pos) != Pass;\n    } finally {\n      cm.state.suppressEdits = false;\n    }\n    return done\n  })\n}\n\nfunction configureMouse(cm, repeat, event) {\n  var option = cm.getOption(\"configureMouse\");\n  var value = option ? option(cm, repeat, event) : {};\n  if (value.unit == null) {\n    var rect = chromeOS ? event.shiftKey && event.metaKey : event.altKey;\n    value.unit = rect ? \"rectangle\" : repeat == \"single\" ? \"char\" : repeat == \"double\" ? \"word\" : \"line\";\n  }\n  if (value.extend == null || cm.doc.extend) { value.extend = cm.doc.extend || event.shiftKey; }\n  if (value.addNew == null) { value.addNew = mac ? event.metaKey : event.ctrlKey; }\n  if (value.moveOnDrag == null) { value.moveOnDrag = !(mac ? event.altKey : event.ctrlKey); }\n  return value\n}\n\nfunction leftButtonDown(cm, pos, repeat, event) {\n  if (ie) { setTimeout(bind(ensureFocus, cm), 0); }\n  else { cm.curOp.focus = activeElt(); }\n\n  var behavior = configureMouse(cm, repeat, event);\n\n  var sel = cm.doc.sel, contained;\n  if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&\n      repeat == \"single\" && (contained = sel.contains(pos)) > -1 &&\n      (cmp((contained = sel.ranges[contained]).from(), pos) < 0 || pos.xRel > 0) &&\n      (cmp(contained.to(), pos) > 0 || pos.xRel < 0))\n    { leftButtonStartDrag(cm, event, pos, behavior); }\n  else\n    { leftButtonSelect(cm, event, pos, behavior); }\n}\n\n// Start a text drag. When it ends, see if any dragging actually\n// happen, and treat as a click if it didn't.\nfunction leftButtonStartDrag(cm, event, pos, behavior) {\n  var display = cm.display, moved = false;\n  var dragEnd = operation(cm, function (e) {\n    if (webkit) { display.scroller.draggable = false; }\n    cm.state.draggingText = false;\n    off(document, \"mouseup\", dragEnd);\n    off(document, \"mousemove\", mouseMove);\n    off(display.scroller, \"dragstart\", dragStart);\n    off(display.scroller, \"drop\", dragEnd);\n    if (!moved) {\n      e_preventDefault(e);\n      if (!behavior.addNew)\n        { extendSelection(cm.doc, pos, null, null, behavior.extend); }\n      // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)\n      if (webkit || ie && ie_version == 9)\n        { setTimeout(function () {document.body.focus(); display.input.focus();}, 20); }\n      else\n        { display.input.focus(); }\n    }\n  });\n  var mouseMove = function(e2) {\n    moved = moved || Math.abs(event.clientX - e2.clientX) + Math.abs(event.clientY - e2.clientY) >= 10;\n  };\n  var dragStart = function () { return moved = true; };\n  // Let the drag handler handle this.\n  if (webkit) { display.scroller.draggable = true; }\n  cm.state.draggingText = dragEnd;\n  dragEnd.copy = !behavior.moveOnDrag;\n  // IE's approach to draggable\n  if (display.scroller.dragDrop) { display.scroller.dragDrop(); }\n  on(document, \"mouseup\", dragEnd);\n  on(document, \"mousemove\", mouseMove);\n  on(display.scroller, \"dragstart\", dragStart);\n  on(display.scroller, \"drop\", dragEnd);\n\n  delayBlurEvent(cm);\n  setTimeout(function () { return display.input.focus(); }, 20);\n}\n\nfunction rangeForUnit(cm, pos, unit) {\n  if (unit == \"char\") { return new Range(pos, pos) }\n  if (unit == \"word\") { return cm.findWordAt(pos) }\n  if (unit == \"line\") { return new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) }\n  var result = unit(cm, pos);\n  return new Range(result.from, result.to)\n}\n\n// Normal selection, as opposed to text dragging.\nfunction leftButtonSelect(cm, event, start, behavior) {\n  var display = cm.display, doc = cm.doc;\n  e_preventDefault(event);\n\n  var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;\n  if (behavior.addNew && !behavior.extend) {\n    ourIndex = doc.sel.contains(start);\n    if (ourIndex > -1)\n      { ourRange = ranges[ourIndex]; }\n    else\n      { ourRange = new Range(start, start); }\n  } else {\n    ourRange = doc.sel.primary();\n    ourIndex = doc.sel.primIndex;\n  }\n\n  if (behavior.unit == \"rectangle\") {\n    if (!behavior.addNew) { ourRange = new Range(start, start); }\n    start = posFromMouse(cm, event, true, true);\n    ourIndex = -1;\n  } else {\n    var range$$1 = rangeForUnit(cm, start, behavior.unit);\n    if (behavior.extend)\n      { ourRange = extendRange(ourRange, range$$1.anchor, range$$1.head, behavior.extend); }\n    else\n      { ourRange = range$$1; }\n  }\n\n  if (!behavior.addNew) {\n    ourIndex = 0;\n    setSelection(doc, new Selection([ourRange], 0), sel_mouse);\n    startSel = doc.sel;\n  } else if (ourIndex == -1) {\n    ourIndex = ranges.length;\n    setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),\n                 {scroll: false, origin: \"*mouse\"});\n  } else if (ranges.length > 1 && ranges[ourIndex].empty() && behavior.unit == \"char\" && !behavior.extend) {\n    setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),\n                 {scroll: false, origin: \"*mouse\"});\n    startSel = doc.sel;\n  } else {\n    replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);\n  }\n\n  var lastPos = start;\n  function extendTo(pos) {\n    if (cmp(lastPos, pos) == 0) { return }\n    lastPos = pos;\n\n    if (behavior.unit == \"rectangle\") {\n      var ranges = [], tabSize = cm.options.tabSize;\n      var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);\n      var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);\n      var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);\n      for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));\n           line <= end; line++) {\n        var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);\n        if (left == right)\n          { ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); }\n        else if (text.length > leftPos)\n          { ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); }\n      }\n      if (!ranges.length) { ranges.push(new Range(start, start)); }\n      setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),\n                   {origin: \"*mouse\", scroll: false});\n      cm.scrollIntoView(pos);\n    } else {\n      var oldRange = ourRange;\n      var range$$1 = rangeForUnit(cm, pos, behavior.unit);\n      var anchor = oldRange.anchor, head;\n      if (cmp(range$$1.anchor, anchor) > 0) {\n        head = range$$1.head;\n        anchor = minPos(oldRange.from(), range$$1.anchor);\n      } else {\n        head = range$$1.anchor;\n        anchor = maxPos(oldRange.to(), range$$1.head);\n      }\n      var ranges$1 = startSel.ranges.slice(0);\n      ranges$1[ourIndex] = new Range(clipPos(doc, anchor), head);\n      setSelection(doc, normalizeSelection(ranges$1, ourIndex), sel_mouse);\n    }\n  }\n\n  var editorSize = display.wrapper.getBoundingClientRect();\n  // Used to ensure timeout re-tries don't fire when another extend\n  // happened in the meantime (clearTimeout isn't reliable -- at\n  // least on Chrome, the timeouts still happen even when cleared,\n  // if the clear happens after their scheduled firing time).\n  var counter = 0;\n\n  function extend(e) {\n    var curCount = ++counter;\n    var cur = posFromMouse(cm, e, true, behavior.unit == \"rectangle\");\n    if (!cur) { return }\n    if (cmp(cur, lastPos) != 0) {\n      cm.curOp.focus = activeElt();\n      extendTo(cur);\n      var visible = visibleLines(display, doc);\n      if (cur.line >= visible.to || cur.line < visible.from)\n        { setTimeout(operation(cm, function () {if (counter == curCount) { extend(e); }}), 150); }\n    } else {\n      var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;\n      if (outside) { setTimeout(operation(cm, function () {\n        if (counter != curCount) { return }\n        display.scroller.scrollTop += outside;\n        extend(e);\n      }), 50); }\n    }\n  }\n\n  function done(e) {\n    cm.state.selectingText = false;\n    counter = Infinity;\n    e_preventDefault(e);\n    display.input.focus();\n    off(document, \"mousemove\", move);\n    off(document, \"mouseup\", up);\n    doc.history.lastSelOrigin = null;\n  }\n\n  var move = operation(cm, function (e) {\n    if (!e_button(e)) { done(e); }\n    else { extend(e); }\n  });\n  var up = operation(cm, done);\n  cm.state.selectingText = up;\n  on(document, \"mousemove\", move);\n  on(document, \"mouseup\", up);\n}\n\n\n// Determines whether an event happened in the gutter, and fires the\n// handlers for the corresponding event.\nfunction gutterEvent(cm, e, type, prevent) {\n  var mX, mY;\n  try { mX = e.clientX; mY = e.clientY; }\n  catch(e) { return false }\n  if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }\n  if (prevent) { e_preventDefault(e); }\n\n  var display = cm.display;\n  var lineBox = display.lineDiv.getBoundingClientRect();\n\n  if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) }\n  mY -= lineBox.top - display.viewOffset;\n\n  for (var i = 0; i < cm.options.gutters.length; ++i) {\n    var g = display.gutters.childNodes[i];\n    if (g && g.getBoundingClientRect().right >= mX) {\n      var line = lineAtHeight(cm.doc, mY);\n      var gutter = cm.options.gutters[i];\n      signal(cm, type, cm, line, gutter, e);\n      return e_defaultPrevented(e)\n    }\n  }\n}\n\nfunction clickInGutter(cm, e) {\n  return gutterEvent(cm, e, \"gutterClick\", true)\n}\n\n// CONTEXT MENU HANDLING\n\n// To make the context menu work, we need to briefly unhide the\n// textarea (making it as unobtrusive as possible) to let the\n// right-click take effect on it.\nfunction onContextMenu(cm, e) {\n  if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) { return }\n  if (signalDOMEvent(cm, e, \"contextmenu\")) { return }\n  cm.display.input.onContextMenu(e);\n}\n\nfunction contextMenuInGutter(cm, e) {\n  if (!hasHandler(cm, \"gutterContextMenu\")) { return false }\n  return gutterEvent(cm, e, \"gutterContextMenu\", false)\n}\n\nfunction themeChanged(cm) {\n  cm.display.wrapper.className = cm.display.wrapper.className.replace(/\\s*cm-s-\\S+/g, \"\") +\n    cm.options.theme.replace(/(^|\\s)\\s*/g, \" cm-s-\");\n  clearCaches(cm);\n}\n\nvar Init = {toString: function(){return \"CodeMirror.Init\"}};\n\nvar defaults = {};\nvar optionHandlers = {};\n\nfunction defineOptions(CodeMirror) {\n  var optionHandlers = CodeMirror.optionHandlers;\n\n  function option(name, deflt, handle, notOnInit) {\n    CodeMirror.defaults[name] = deflt;\n    if (handle) { optionHandlers[name] =\n      notOnInit ? function (cm, val, old) {if (old != Init) { handle(cm, val, old); }} : handle; }\n  }\n\n  CodeMirror.defineOption = option;\n\n  // Passed to option handlers when there is no old value.\n  CodeMirror.Init = Init;\n\n  // These two are, on init, called from the constructor because they\n  // have to be initialized before the editor can start at all.\n  option(\"value\", \"\", function (cm, val) { return cm.setValue(val); }, true);\n  option(\"mode\", null, function (cm, val) {\n    cm.doc.modeOption = val;\n    loadMode(cm);\n  }, true);\n\n  option(\"indentUnit\", 2, loadMode, true);\n  option(\"indentWithTabs\", false);\n  option(\"smartIndent\", true);\n  option(\"tabSize\", 4, function (cm) {\n    resetModeState(cm);\n    clearCaches(cm);\n    regChange(cm);\n  }, true);\n  option(\"lineSeparator\", null, function (cm, val) {\n    cm.doc.lineSep = val;\n    if (!val) { return }\n    var newBreaks = [], lineNo = cm.doc.first;\n    cm.doc.iter(function (line) {\n      for (var pos = 0;;) {\n        var found = line.text.indexOf(val, pos);\n        if (found == -1) { break }\n        pos = found + val.length;\n        newBreaks.push(Pos(lineNo, found));\n      }\n      lineNo++;\n    });\n    for (var i = newBreaks.length - 1; i >= 0; i--)\n      { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)); }\n  });\n  option(\"specialChars\", /[\\u0000-\\u001f\\u007f-\\u009f\\u00ad\\u061c\\u200b-\\u200f\\u2028\\u2029\\ufeff]/g, function (cm, val, old) {\n    cm.state.specialChars = new RegExp(val.source + (val.test(\"\\t\") ? \"\" : \"|\\t\"), \"g\");\n    if (old != Init) { cm.refresh(); }\n  });\n  option(\"specialCharPlaceholder\", defaultSpecialCharPlaceholder, function (cm) { return cm.refresh(); }, true);\n  option(\"electricChars\", true);\n  option(\"inputStyle\", mobile ? \"contenteditable\" : \"textarea\", function () {\n    throw new Error(\"inputStyle can not (yet) be changed in a running editor\") // FIXME\n  }, true);\n  option(\"spellcheck\", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true);\n  option(\"rtlMoveVisually\", !windows);\n  option(\"wholeLineUpdateBefore\", true);\n\n  option(\"theme\", \"default\", function (cm) {\n    themeChanged(cm);\n    guttersChanged(cm);\n  }, true);\n  option(\"keyMap\", \"default\", function (cm, val, old) {\n    var next = getKeyMap(val);\n    var prev = old != Init && getKeyMap(old);\n    if (prev && prev.detach) { prev.detach(cm, next); }\n    if (next.attach) { next.attach(cm, prev || null); }\n  });\n  option(\"extraKeys\", null);\n  option(\"configureMouse\", null);\n\n  option(\"lineWrapping\", false, wrappingChanged, true);\n  option(\"gutters\", [], function (cm) {\n    setGuttersForLineNumbers(cm.options);\n    guttersChanged(cm);\n  }, true);\n  option(\"fixedGutter\", true, function (cm, val) {\n    cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + \"px\" : \"0\";\n    cm.refresh();\n  }, true);\n  option(\"coverGutterNextToScrollbar\", false, function (cm) { return updateScrollbars(cm); }, true);\n  option(\"scrollbarStyle\", \"native\", function (cm) {\n    initScrollbars(cm);\n    updateScrollbars(cm);\n    cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);\n    cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);\n  }, true);\n  option(\"lineNumbers\", false, function (cm) {\n    setGuttersForLineNumbers(cm.options);\n    guttersChanged(cm);\n  }, true);\n  option(\"firstLineNumber\", 1, guttersChanged, true);\n  option(\"lineNumberFormatter\", function (integer) { return integer; }, guttersChanged, true);\n  option(\"showCursorWhenSelecting\", false, updateSelection, true);\n\n  option(\"resetSelectionOnContextMenu\", true);\n  option(\"lineWiseCopyCut\", true);\n  option(\"pasteLinesPerSelection\", true);\n\n  option(\"readOnly\", false, function (cm, val) {\n    if (val == \"nocursor\") {\n      onBlur(cm);\n      cm.display.input.blur();\n    }\n    cm.display.input.readOnlyChanged(val);\n  });\n  option(\"disableInput\", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true);\n  option(\"dragDrop\", true, dragDropChanged);\n  option(\"allowDropFileTypes\", null);\n\n  option(\"cursorBlinkRate\", 530);\n  option(\"cursorScrollMargin\", 0);\n  option(\"cursorHeight\", 1, updateSelection, true);\n  option(\"singleCursorHeightPerLine\", true, updateSelection, true);\n  option(\"workTime\", 100);\n  option(\"workDelay\", 100);\n  option(\"flattenSpans\", true, resetModeState, true);\n  option(\"addModeClass\", false, resetModeState, true);\n  option(\"pollInterval\", 100);\n  option(\"undoDepth\", 200, function (cm, val) { return cm.doc.history.undoDepth = val; });\n  option(\"historyEventDelay\", 1250);\n  option(\"viewportMargin\", 10, function (cm) { return cm.refresh(); }, true);\n  option(\"maxHighlightLength\", 10000, resetModeState, true);\n  option(\"moveInputWithCursor\", true, function (cm, val) {\n    if (!val) { cm.display.input.resetPosition(); }\n  });\n\n  option(\"tabindex\", null, function (cm, val) { return cm.display.input.getField().tabIndex = val || \"\"; });\n  option(\"autofocus\", null);\n  option(\"direction\", \"ltr\", function (cm, val) { return cm.doc.setDirection(val); }, true);\n}\n\nfunction guttersChanged(cm) {\n  updateGutters(cm);\n  regChange(cm);\n  alignHorizontally(cm);\n}\n\nfunction dragDropChanged(cm, value, old) {\n  var wasOn = old && old != Init;\n  if (!value != !wasOn) {\n    var funcs = cm.display.dragFunctions;\n    var toggle = value ? on : off;\n    toggle(cm.display.scroller, \"dragstart\", funcs.start);\n    toggle(cm.display.scroller, \"dragenter\", funcs.enter);\n    toggle(cm.display.scroller, \"dragover\", funcs.over);\n    toggle(cm.display.scroller, \"dragleave\", funcs.leave);\n    toggle(cm.display.scroller, \"drop\", funcs.drop);\n  }\n}\n\nfunction wrappingChanged(cm) {\n  if (cm.options.lineWrapping) {\n    addClass(cm.display.wrapper, \"CodeMirror-wrap\");\n    cm.display.sizer.style.minWidth = \"\";\n    cm.display.sizerWidth = null;\n  } else {\n    rmClass(cm.display.wrapper, \"CodeMirror-wrap\");\n    findMaxLine(cm);\n  }\n  estimateLineHeights(cm);\n  regChange(cm);\n  clearCaches(cm);\n  setTimeout(function () { return updateScrollbars(cm); }, 100);\n}\n\n// A CodeMirror instance represents an editor. This is the object\n// that user code is usually dealing with.\n\nfunction CodeMirror$1(place, options) {\n  var this$1 = this;\n\n  if (!(this instanceof CodeMirror$1)) { return new CodeMirror$1(place, options) }\n\n  this.options = options = options ? copyObj(options) : {};\n  // Determine effective options based on given values and defaults.\n  copyObj(defaults, options, false);\n  setGuttersForLineNumbers(options);\n\n  var doc = options.value;\n  if (typeof doc == \"string\") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction); }\n  this.doc = doc;\n\n  var input = new CodeMirror$1.inputStyles[options.inputStyle](this);\n  var display = this.display = new Display(place, doc, input);\n  display.wrapper.CodeMirror = this;\n  updateGutters(this);\n  themeChanged(this);\n  if (options.lineWrapping)\n    { this.display.wrapper.className += \" CodeMirror-wrap\"; }\n  initScrollbars(this);\n\n  this.state = {\n    keyMaps: [],  // stores maps added by addKeyMap\n    overlays: [], // highlighting overlays, as added by addOverlay\n    modeGen: 0,   // bumped when mode/overlay changes, used to invalidate highlighting info\n    overwrite: false,\n    delayingBlurEvent: false,\n    focused: false,\n    suppressEdits: false, // used to disable editing during key handlers when in readOnly mode\n    pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll\n    selectingText: false,\n    draggingText: false,\n    highlight: new Delayed(), // stores highlight worker timeout\n    keySeq: null,  // Unfinished key sequence\n    specialChars: null\n  };\n\n  if (options.autofocus && !mobile) { display.input.focus(); }\n\n  // Override magic textarea content restore that IE sometimes does\n  // on our hidden textarea on reload\n  if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20); }\n\n  registerEventHandlers(this);\n  ensureGlobalHandlers();\n\n  startOperation(this);\n  this.curOp.forceUpdate = true;\n  attachDoc(this, doc);\n\n  if ((options.autofocus && !mobile) || this.hasFocus())\n    { setTimeout(bind(onFocus, this), 20); }\n  else\n    { onBlur(this); }\n\n  for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt))\n    { optionHandlers[opt](this$1, options[opt], Init); } }\n  maybeUpdateLineNumberWidth(this);\n  if (options.finishInit) { options.finishInit(this); }\n  for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this$1); }\n  endOperation(this);\n  // Suppress optimizelegibility in Webkit, since it breaks text\n  // measuring on line wrapping boundaries.\n  if (webkit && options.lineWrapping &&\n      getComputedStyle(display.lineDiv).textRendering == \"optimizelegibility\")\n    { display.lineDiv.style.textRendering = \"auto\"; }\n}\n\n// The default configuration options.\nCodeMirror$1.defaults = defaults;\n// Functions to run when options are changed.\nCodeMirror$1.optionHandlers = optionHandlers;\n\n// Attach the necessary event handlers when initializing the editor\nfunction registerEventHandlers(cm) {\n  var d = cm.display;\n  on(d.scroller, \"mousedown\", operation(cm, onMouseDown));\n  // Older IE's will not fire a second mousedown for a double click\n  if (ie && ie_version < 11)\n    { on(d.scroller, \"dblclick\", operation(cm, function (e) {\n      if (signalDOMEvent(cm, e)) { return }\n      var pos = posFromMouse(cm, e);\n      if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) { return }\n      e_preventDefault(e);\n      var word = cm.findWordAt(pos);\n      extendSelection(cm.doc, word.anchor, word.head);\n    })); }\n  else\n    { on(d.scroller, \"dblclick\", function (e) { return signalDOMEvent(cm, e) || e_preventDefault(e); }); }\n  // Some browsers fire contextmenu *after* opening the menu, at\n  // which point we can't mess with it anymore. Context menu is\n  // handled in onMouseDown for these browsers.\n  if (!captureRightClick) { on(d.scroller, \"contextmenu\", function (e) { return onContextMenu(cm, e); }); }\n\n  // Used to suppress mouse event handling when a touch happens\n  var touchFinished, prevTouch = {end: 0};\n  function finishTouch() {\n    if (d.activeTouch) {\n      touchFinished = setTimeout(function () { return d.activeTouch = null; }, 1000);\n      prevTouch = d.activeTouch;\n      prevTouch.end = +new Date;\n    }\n  }\n  function isMouseLikeTouchEvent(e) {\n    if (e.touches.length != 1) { return false }\n    var touch = e.touches[0];\n    return touch.radiusX <= 1 && touch.radiusY <= 1\n  }\n  function farAway(touch, other) {\n    if (other.left == null) { return true }\n    var dx = other.left - touch.left, dy = other.top - touch.top;\n    return dx * dx + dy * dy > 20 * 20\n  }\n  on(d.scroller, \"touchstart\", function (e) {\n    if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) {\n      d.input.ensurePolled();\n      clearTimeout(touchFinished);\n      var now = +new Date;\n      d.activeTouch = {start: now, moved: false,\n                       prev: now - prevTouch.end <= 300 ? prevTouch : null};\n      if (e.touches.length == 1) {\n        d.activeTouch.left = e.touches[0].pageX;\n        d.activeTouch.top = e.touches[0].pageY;\n      }\n    }\n  });\n  on(d.scroller, \"touchmove\", function () {\n    if (d.activeTouch) { d.activeTouch.moved = true; }\n  });\n  on(d.scroller, \"touchend\", function (e) {\n    var touch = d.activeTouch;\n    if (touch && !eventInWidget(d, e) && touch.left != null &&\n        !touch.moved && new Date - touch.start < 300) {\n      var pos = cm.coordsChar(d.activeTouch, \"page\"), range;\n      if (!touch.prev || farAway(touch, touch.prev)) // Single tap\n        { range = new Range(pos, pos); }\n      else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap\n        { range = cm.findWordAt(pos); }\n      else // Triple tap\n        { range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); }\n      cm.setSelection(range.anchor, range.head);\n      cm.focus();\n      e_preventDefault(e);\n    }\n    finishTouch();\n  });\n  on(d.scroller, \"touchcancel\", finishTouch);\n\n  // Sync scrolling between fake scrollbars and real scrollable\n  // area, ensure viewport is updated when scrolling.\n  on(d.scroller, \"scroll\", function () {\n    if (d.scroller.clientHeight) {\n      updateScrollTop(cm, d.scroller.scrollTop);\n      setScrollLeft(cm, d.scroller.scrollLeft, true);\n      signal(cm, \"scroll\", cm);\n    }\n  });\n\n  // Listen to wheel events in order to try and update the viewport on time.\n  on(d.scroller, \"mousewheel\", function (e) { return onScrollWheel(cm, e); });\n  on(d.scroller, \"DOMMouseScroll\", function (e) { return onScrollWheel(cm, e); });\n\n  // Prevent wrapper from ever scrolling\n  on(d.wrapper, \"scroll\", function () { return d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });\n\n  d.dragFunctions = {\n    enter: function (e) {if (!signalDOMEvent(cm, e)) { e_stop(e); }},\n    over: function (e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},\n    start: function (e) { return onDragStart(cm, e); },\n    drop: operation(cm, onDrop),\n    leave: function (e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }}\n  };\n\n  var inp = d.input.getField();\n  on(inp, \"keyup\", function (e) { return onKeyUp.call(cm, e); });\n  on(inp, \"keydown\", operation(cm, onKeyDown));\n  on(inp, \"keypress\", operation(cm, onKeyPress));\n  on(inp, \"focus\", function (e) { return onFocus(cm, e); });\n  on(inp, \"blur\", function (e) { return onBlur(cm, e); });\n}\n\nvar initHooks = [];\nCodeMirror$1.defineInitHook = function (f) { return initHooks.push(f); };\n\n// Indent the given line. The how parameter can be \"smart\",\n// \"add\"/null, \"subtract\", or \"prev\". When aggressive is false\n// (typically set to true for forced single-line indents), empty\n// lines are not indented, and places where the mode returns Pass\n// are left alone.\nfunction indentLine(cm, n, how, aggressive) {\n  var doc = cm.doc, state;\n  if (how == null) { how = \"add\"; }\n  if (how == \"smart\") {\n    // Fall back to \"prev\" when the mode doesn't have an indentation\n    // method.\n    if (!doc.mode.indent) { how = \"prev\"; }\n    else { state = getContextBefore(cm, n).state; }\n  }\n\n  var tabSize = cm.options.tabSize;\n  var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);\n  if (line.stateAfter) { line.stateAfter = null; }\n  var curSpaceString = line.text.match(/^\\s*/)[0], indentation;\n  if (!aggressive && !/\\S/.test(line.text)) {\n    indentation = 0;\n    how = \"not\";\n  } else if (how == \"smart\") {\n    indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);\n    if (indentation == Pass || indentation > 150) {\n      if (!aggressive) { return }\n      how = \"prev\";\n    }\n  }\n  if (how == \"prev\") {\n    if (n > doc.first) { indentation = countColumn(getLine(doc, n-1).text, null, tabSize); }\n    else { indentation = 0; }\n  } else if (how == \"add\") {\n    indentation = curSpace + cm.options.indentUnit;\n  } else if (how == \"subtract\") {\n    indentation = curSpace - cm.options.indentUnit;\n  } else if (typeof how == \"number\") {\n    indentation = curSpace + how;\n  }\n  indentation = Math.max(0, indentation);\n\n  var indentString = \"\", pos = 0;\n  if (cm.options.indentWithTabs)\n    { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += \"\\t\";} }\n  if (pos < indentation) { indentString += spaceStr(indentation - pos); }\n\n  if (indentString != curSpaceString) {\n    replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), \"+input\");\n    line.stateAfter = null;\n    return true\n  } else {\n    // Ensure that, if the cursor was in the whitespace at the start\n    // of the line, it is moved to the end of that space.\n    for (var i$1 = 0; i$1 < doc.sel.ranges.length; i$1++) {\n      var range = doc.sel.ranges[i$1];\n      if (range.head.line == n && range.head.ch < curSpaceString.length) {\n        var pos$1 = Pos(n, curSpaceString.length);\n        replaceOneSelection(doc, i$1, new Range(pos$1, pos$1));\n        break\n      }\n    }\n  }\n}\n\n// This will be set to a {lineWise: bool, text: [string]} object, so\n// that, when pasting, we know what kind of selections the copied\n// text was made out of.\nvar lastCopied = null;\n\nfunction setLastCopied(newLastCopied) {\n  lastCopied = newLastCopied;\n}\n\nfunction applyTextInput(cm, inserted, deleted, sel, origin) {\n  var doc = cm.doc;\n  cm.display.shift = false;\n  if (!sel) { sel = doc.sel; }\n\n  var paste = cm.state.pasteIncoming || origin == \"paste\";\n  var textLines = splitLinesAuto(inserted), multiPaste = null;\n  // When pasing N lines into N selections, insert one line per selection\n  if (paste && sel.ranges.length > 1) {\n    if (lastCopied && lastCopied.text.join(\"\\n\") == inserted) {\n      if (sel.ranges.length % lastCopied.text.length == 0) {\n        multiPaste = [];\n        for (var i = 0; i < lastCopied.text.length; i++)\n          { multiPaste.push(doc.splitLines(lastCopied.text[i])); }\n      }\n    } else if (textLines.length == sel.ranges.length && cm.options.pasteLinesPerSelection) {\n      multiPaste = map(textLines, function (l) { return [l]; });\n    }\n  }\n\n  var updateInput;\n  // Normal behavior is to insert the new text into every selection\n  for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) {\n    var range$$1 = sel.ranges[i$1];\n    var from = range$$1.from(), to = range$$1.to();\n    if (range$$1.empty()) {\n      if (deleted && deleted > 0) // Handle deletion\n        { from = Pos(from.line, from.ch - deleted); }\n      else if (cm.state.overwrite && !paste) // Handle overwrite\n        { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); }\n      else if (lastCopied && lastCopied.lineWise && lastCopied.text.join(\"\\n\") == inserted)\n        { from = to = Pos(from.line, 0); }\n    }\n    updateInput = cm.curOp.updateInput;\n    var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines,\n                       origin: origin || (paste ? \"paste\" : cm.state.cutIncoming ? \"cut\" : \"+input\")};\n    makeChange(cm.doc, changeEvent);\n    signalLater(cm, \"inputRead\", cm, changeEvent);\n  }\n  if (inserted && !paste)\n    { triggerElectric(cm, inserted); }\n\n  ensureCursorVisible(cm);\n  cm.curOp.updateInput = updateInput;\n  cm.curOp.typing = true;\n  cm.state.pasteIncoming = cm.state.cutIncoming = false;\n}\n\nfunction handlePaste(e, cm) {\n  var pasted = e.clipboardData && e.clipboardData.getData(\"Text\");\n  if (pasted) {\n    e.preventDefault();\n    if (!cm.isReadOnly() && !cm.options.disableInput)\n      { runInOp(cm, function () { return applyTextInput(cm, pasted, 0, null, \"paste\"); }); }\n    return true\n  }\n}\n\nfunction triggerElectric(cm, inserted) {\n  // When an 'electric' character is inserted, immediately trigger a reindent\n  if (!cm.options.electricChars || !cm.options.smartIndent) { return }\n  var sel = cm.doc.sel;\n\n  for (var i = sel.ranges.length - 1; i >= 0; i--) {\n    var range$$1 = sel.ranges[i];\n    if (range$$1.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range$$1.head.line)) { continue }\n    var mode = cm.getModeAt(range$$1.head);\n    var indented = false;\n    if (mode.electricChars) {\n      for (var j = 0; j < mode.electricChars.length; j++)\n        { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {\n          indented = indentLine(cm, range$$1.head.line, \"smart\");\n          break\n        } }\n    } else if (mode.electricInput) {\n      if (mode.electricInput.test(getLine(cm.doc, range$$1.head.line).text.slice(0, range$$1.head.ch)))\n        { indented = indentLine(cm, range$$1.head.line, \"smart\"); }\n    }\n    if (indented) { signalLater(cm, \"electricInput\", cm, range$$1.head.line); }\n  }\n}\n\nfunction copyableRanges(cm) {\n  var text = [], ranges = [];\n  for (var i = 0; i < cm.doc.sel.ranges.length; i++) {\n    var line = cm.doc.sel.ranges[i].head.line;\n    var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};\n    ranges.push(lineRange);\n    text.push(cm.getRange(lineRange.anchor, lineRange.head));\n  }\n  return {text: text, ranges: ranges}\n}\n\nfunction disableBrowserMagic(field, spellcheck) {\n  field.setAttribute(\"autocorrect\", \"off\");\n  field.setAttribute(\"autocapitalize\", \"off\");\n  field.setAttribute(\"spellcheck\", !!spellcheck);\n}\n\nfunction hiddenTextarea() {\n  var te = elt(\"textarea\", null, null, \"position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none\");\n  var div = elt(\"div\", [te], null, \"overflow: hidden; position: relative; width: 3px; height: 0px;\");\n  // The textarea is kept positioned near the cursor to prevent the\n  // fact that it'll be scrolled into view on input from scrolling\n  // our fake cursor out of view. On webkit, when wrap=off, paste is\n  // very slow. So make the area wide instead.\n  if (webkit) { te.style.width = \"1000px\"; }\n  else { te.setAttribute(\"wrap\", \"off\"); }\n  // If border: 0; -- iOS fails to open keyboard (issue #1287)\n  if (ios) { te.style.border = \"1px solid black\"; }\n  disableBrowserMagic(te);\n  return div\n}\n\n// The publicly visible API. Note that methodOp(f) means\n// 'wrap f in an operation, performed on its `this` parameter'.\n\n// This is not the complete set of editor methods. Most of the\n// methods defined on the Doc type are also injected into\n// CodeMirror.prototype, for backwards compatibility and\n// convenience.\n\nvar addEditorMethods = function(CodeMirror) {\n  var optionHandlers = CodeMirror.optionHandlers;\n\n  var helpers = CodeMirror.helpers = {};\n\n  CodeMirror.prototype = {\n    constructor: CodeMirror,\n    focus: function(){window.focus(); this.display.input.focus();},\n\n    setOption: function(option, value) {\n      var options = this.options, old = options[option];\n      if (options[option] == value && option != \"mode\") { return }\n      options[option] = value;\n      if (optionHandlers.hasOwnProperty(option))\n        { operation(this, optionHandlers[option])(this, value, old); }\n      signal(this, \"optionChange\", this, option);\n    },\n\n    getOption: function(option) {return this.options[option]},\n    getDoc: function() {return this.doc},\n\n    addKeyMap: function(map$$1, bottom) {\n      this.state.keyMaps[bottom ? \"push\" : \"unshift\"](getKeyMap(map$$1));\n    },\n    removeKeyMap: function(map$$1) {\n      var maps = this.state.keyMaps;\n      for (var i = 0; i < maps.length; ++i)\n        { if (maps[i] == map$$1 || maps[i].name == map$$1) {\n          maps.splice(i, 1);\n          return true\n        } }\n    },\n\n    addOverlay: methodOp(function(spec, options) {\n      var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);\n      if (mode.startState) { throw new Error(\"Overlays may not be stateful.\") }\n      insertSorted(this.state.overlays,\n                   {mode: mode, modeSpec: spec, opaque: options && options.opaque,\n                    priority: (options && options.priority) || 0},\n                   function (overlay) { return overlay.priority; });\n      this.state.modeGen++;\n      regChange(this);\n    }),\n    removeOverlay: methodOp(function(spec) {\n      var this$1 = this;\n\n      var overlays = this.state.overlays;\n      for (var i = 0; i < overlays.length; ++i) {\n        var cur = overlays[i].modeSpec;\n        if (cur == spec || typeof spec == \"string\" && cur.name == spec) {\n          overlays.splice(i, 1);\n          this$1.state.modeGen++;\n          regChange(this$1);\n          return\n        }\n      }\n    }),\n\n    indentLine: methodOp(function(n, dir, aggressive) {\n      if (typeof dir != \"string\" && typeof dir != \"number\") {\n        if (dir == null) { dir = this.options.smartIndent ? \"smart\" : \"prev\"; }\n        else { dir = dir ? \"add\" : \"subtract\"; }\n      }\n      if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive); }\n    }),\n    indentSelection: methodOp(function(how) {\n      var this$1 = this;\n\n      var ranges = this.doc.sel.ranges, end = -1;\n      for (var i = 0; i < ranges.length; i++) {\n        var range$$1 = ranges[i];\n        if (!range$$1.empty()) {\n          var from = range$$1.from(), to = range$$1.to();\n          var start = Math.max(end, from.line);\n          end = Math.min(this$1.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;\n          for (var j = start; j < end; ++j)\n            { indentLine(this$1, j, how); }\n          var newRanges = this$1.doc.sel.ranges;\n          if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)\n            { replaceOneSelection(this$1.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); }\n        } else if (range$$1.head.line > end) {\n          indentLine(this$1, range$$1.head.line, how, true);\n          end = range$$1.head.line;\n          if (i == this$1.doc.sel.primIndex) { ensureCursorVisible(this$1); }\n        }\n      }\n    }),\n\n    // Fetch the parser token for a given character. Useful for hacks\n    // that want to inspect the mode state (say, for completion).\n    getTokenAt: function(pos, precise) {\n      return takeToken(this, pos, precise)\n    },\n\n    getLineTokens: function(line, precise) {\n      return takeToken(this, Pos(line), precise, true)\n    },\n\n    getTokenTypeAt: function(pos) {\n      pos = clipPos(this.doc, pos);\n      var styles = getLineStyles(this, getLine(this.doc, pos.line));\n      var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;\n      var type;\n      if (ch == 0) { type = styles[2]; }\n      else { for (;;) {\n        var mid = (before + after) >> 1;\n        if ((mid ? styles[mid * 2 - 1] : 0) >= ch) { after = mid; }\n        else if (styles[mid * 2 + 1] < ch) { before = mid + 1; }\n        else { type = styles[mid * 2 + 2]; break }\n      } }\n      var cut = type ? type.indexOf(\"overlay \") : -1;\n      return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1)\n    },\n\n    getModeAt: function(pos) {\n      var mode = this.doc.mode;\n      if (!mode.innerMode) { return mode }\n      return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode\n    },\n\n    getHelper: function(pos, type) {\n      return this.getHelpers(pos, type)[0]\n    },\n\n    getHelpers: function(pos, type) {\n      var this$1 = this;\n\n      var found = [];\n      if (!helpers.hasOwnProperty(type)) { return found }\n      var help = helpers[type], mode = this.getModeAt(pos);\n      if (typeof mode[type] == \"string\") {\n        if (help[mode[type]]) { found.push(help[mode[type]]); }\n      } else if (mode[type]) {\n        for (var i = 0; i < mode[type].length; i++) {\n          var val = help[mode[type][i]];\n          if (val) { found.push(val); }\n        }\n      } else if (mode.helperType && help[mode.helperType]) {\n        found.push(help[mode.helperType]);\n      } else if (help[mode.name]) {\n        found.push(help[mode.name]);\n      }\n      for (var i$1 = 0; i$1 < help._global.length; i$1++) {\n        var cur = help._global[i$1];\n        if (cur.pred(mode, this$1) && indexOf(found, cur.val) == -1)\n          { found.push(cur.val); }\n      }\n      return found\n    },\n\n    getStateAfter: function(line, precise) {\n      var doc = this.doc;\n      line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);\n      return getContextBefore(this, line + 1, precise).state\n    },\n\n    cursorCoords: function(start, mode) {\n      var pos, range$$1 = this.doc.sel.primary();\n      if (start == null) { pos = range$$1.head; }\n      else if (typeof start == \"object\") { pos = clipPos(this.doc, start); }\n      else { pos = start ? range$$1.from() : range$$1.to(); }\n      return cursorCoords(this, pos, mode || \"page\")\n    },\n\n    charCoords: function(pos, mode) {\n      return charCoords(this, clipPos(this.doc, pos), mode || \"page\")\n    },\n\n    coordsChar: function(coords, mode) {\n      coords = fromCoordSystem(this, coords, mode || \"page\");\n      return coordsChar(this, coords.left, coords.top)\n    },\n\n    lineAtHeight: function(height, mode) {\n      height = fromCoordSystem(this, {top: height, left: 0}, mode || \"page\").top;\n      return lineAtHeight(this.doc, height + this.display.viewOffset)\n    },\n    heightAtLine: function(line, mode, includeWidgets) {\n      var end = false, lineObj;\n      if (typeof line == \"number\") {\n        var last = this.doc.first + this.doc.size - 1;\n        if (line < this.doc.first) { line = this.doc.first; }\n        else if (line > last) { line = last; end = true; }\n        lineObj = getLine(this.doc, line);\n      } else {\n        lineObj = line;\n      }\n      return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || \"page\", includeWidgets || end).top +\n        (end ? this.doc.height - heightAtLine(lineObj) : 0)\n    },\n\n    defaultTextHeight: function() { return textHeight(this.display) },\n    defaultCharWidth: function() { return charWidth(this.display) },\n\n    getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}},\n\n    addWidget: function(pos, node, scroll, vert, horiz) {\n      var display = this.display;\n      pos = cursorCoords(this, clipPos(this.doc, pos));\n      var top = pos.bottom, left = pos.left;\n      node.style.position = \"absolute\";\n      node.setAttribute(\"cm-ignore-events\", \"true\");\n      this.display.input.setUneditable(node);\n      display.sizer.appendChild(node);\n      if (vert == \"over\") {\n        top = pos.top;\n      } else if (vert == \"above\" || vert == \"near\") {\n        var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),\n        hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);\n        // Default to positioning above (if specified and possible); otherwise default to positioning below\n        if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)\n          { top = pos.top - node.offsetHeight; }\n        else if (pos.bottom + node.offsetHeight <= vspace)\n          { top = pos.bottom; }\n        if (left + node.offsetWidth > hspace)\n          { left = hspace - node.offsetWidth; }\n      }\n      node.style.top = top + \"px\";\n      node.style.left = node.style.right = \"\";\n      if (horiz == \"right\") {\n        left = display.sizer.clientWidth - node.offsetWidth;\n        node.style.right = \"0px\";\n      } else {\n        if (horiz == \"left\") { left = 0; }\n        else if (horiz == \"middle\") { left = (display.sizer.clientWidth - node.offsetWidth) / 2; }\n        node.style.left = left + \"px\";\n      }\n      if (scroll)\n        { scrollIntoView(this, {left: left, top: top, right: left + node.offsetWidth, bottom: top + node.offsetHeight}); }\n    },\n\n    triggerOnKeyDown: methodOp(onKeyDown),\n    triggerOnKeyPress: methodOp(onKeyPress),\n    triggerOnKeyUp: onKeyUp,\n    triggerOnMouseDown: methodOp(onMouseDown),\n\n    execCommand: function(cmd) {\n      if (commands.hasOwnProperty(cmd))\n        { return commands[cmd].call(null, this) }\n    },\n\n    triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),\n\n    findPosH: function(from, amount, unit, visually) {\n      var this$1 = this;\n\n      var dir = 1;\n      if (amount < 0) { dir = -1; amount = -amount; }\n      var cur = clipPos(this.doc, from);\n      for (var i = 0; i < amount; ++i) {\n        cur = findPosH(this$1.doc, cur, dir, unit, visually);\n        if (cur.hitSide) { break }\n      }\n      return cur\n    },\n\n    moveH: methodOp(function(dir, unit) {\n      var this$1 = this;\n\n      this.extendSelectionsBy(function (range$$1) {\n        if (this$1.display.shift || this$1.doc.extend || range$$1.empty())\n          { return findPosH(this$1.doc, range$$1.head, dir, unit, this$1.options.rtlMoveVisually) }\n        else\n          { return dir < 0 ? range$$1.from() : range$$1.to() }\n      }, sel_move);\n    }),\n\n    deleteH: methodOp(function(dir, unit) {\n      var sel = this.doc.sel, doc = this.doc;\n      if (sel.somethingSelected())\n        { doc.replaceSelection(\"\", null, \"+delete\"); }\n      else\n        { deleteNearSelection(this, function (range$$1) {\n          var other = findPosH(doc, range$$1.head, dir, unit, false);\n          return dir < 0 ? {from: other, to: range$$1.head} : {from: range$$1.head, to: other}\n        }); }\n    }),\n\n    findPosV: function(from, amount, unit, goalColumn) {\n      var this$1 = this;\n\n      var dir = 1, x = goalColumn;\n      if (amount < 0) { dir = -1; amount = -amount; }\n      var cur = clipPos(this.doc, from);\n      for (var i = 0; i < amount; ++i) {\n        var coords = cursorCoords(this$1, cur, \"div\");\n        if (x == null) { x = coords.left; }\n        else { coords.left = x; }\n        cur = findPosV(this$1, coords, dir, unit);\n        if (cur.hitSide) { break }\n      }\n      return cur\n    },\n\n    moveV: methodOp(function(dir, unit) {\n      var this$1 = this;\n\n      var doc = this.doc, goals = [];\n      var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected();\n      doc.extendSelectionsBy(function (range$$1) {\n        if (collapse)\n          { return dir < 0 ? range$$1.from() : range$$1.to() }\n        var headPos = cursorCoords(this$1, range$$1.head, \"div\");\n        if (range$$1.goalColumn != null) { headPos.left = range$$1.goalColumn; }\n        goals.push(headPos.left);\n        var pos = findPosV(this$1, headPos, dir, unit);\n        if (unit == \"page\" && range$$1 == doc.sel.primary())\n          { addToScrollTop(this$1, charCoords(this$1, pos, \"div\").top - headPos.top); }\n        return pos\n      }, sel_move);\n      if (goals.length) { for (var i = 0; i < doc.sel.ranges.length; i++)\n        { doc.sel.ranges[i].goalColumn = goals[i]; } }\n    }),\n\n    // Find the word at the given position (as returned by coordsChar).\n    findWordAt: function(pos) {\n      var doc = this.doc, line = getLine(doc, pos.line).text;\n      var start = pos.ch, end = pos.ch;\n      if (line) {\n        var helper = this.getHelper(pos, \"wordChars\");\n        if ((pos.sticky == \"before\" || end == line.length) && start) { --start; } else { ++end; }\n        var startChar = line.charAt(start);\n        var check = isWordChar(startChar, helper)\n          ? function (ch) { return isWordChar(ch, helper); }\n          : /\\s/.test(startChar) ? function (ch) { return /\\s/.test(ch); }\n          : function (ch) { return (!/\\s/.test(ch) && !isWordChar(ch)); };\n        while (start > 0 && check(line.charAt(start - 1))) { --start; }\n        while (end < line.length && check(line.charAt(end))) { ++end; }\n      }\n      return new Range(Pos(pos.line, start), Pos(pos.line, end))\n    },\n\n    toggleOverwrite: function(value) {\n      if (value != null && value == this.state.overwrite) { return }\n      if (this.state.overwrite = !this.state.overwrite)\n        { addClass(this.display.cursorDiv, \"CodeMirror-overwrite\"); }\n      else\n        { rmClass(this.display.cursorDiv, \"CodeMirror-overwrite\"); }\n\n      signal(this, \"overwriteToggle\", this, this.state.overwrite);\n    },\n    hasFocus: function() { return this.display.input.getField() == activeElt() },\n    isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) },\n\n    scrollTo: methodOp(function (x, y) { scrollToCoords(this, x, y); }),\n    getScrollInfo: function() {\n      var scroller = this.display.scroller;\n      return {left: scroller.scrollLeft, top: scroller.scrollTop,\n              height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,\n              width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,\n              clientHeight: displayHeight(this), clientWidth: displayWidth(this)}\n    },\n\n    scrollIntoView: methodOp(function(range$$1, margin) {\n      if (range$$1 == null) {\n        range$$1 = {from: this.doc.sel.primary().head, to: null};\n        if (margin == null) { margin = this.options.cursorScrollMargin; }\n      } else if (typeof range$$1 == \"number\") {\n        range$$1 = {from: Pos(range$$1, 0), to: null};\n      } else if (range$$1.from == null) {\n        range$$1 = {from: range$$1, to: null};\n      }\n      if (!range$$1.to) { range$$1.to = range$$1.from; }\n      range$$1.margin = margin || 0;\n\n      if (range$$1.from.line != null) {\n        scrollToRange(this, range$$1);\n      } else {\n        scrollToCoordsRange(this, range$$1.from, range$$1.to, range$$1.margin);\n      }\n    }),\n\n    setSize: methodOp(function(width, height) {\n      var this$1 = this;\n\n      var interpret = function (val) { return typeof val == \"number\" || /^\\d+$/.test(String(val)) ? val + \"px\" : val; };\n      if (width != null) { this.display.wrapper.style.width = interpret(width); }\n      if (height != null) { this.display.wrapper.style.height = interpret(height); }\n      if (this.options.lineWrapping) { clearLineMeasurementCache(this); }\n      var lineNo$$1 = this.display.viewFrom;\n      this.doc.iter(lineNo$$1, this.display.viewTo, function (line) {\n        if (line.widgets) { for (var i = 0; i < line.widgets.length; i++)\n          { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo$$1, \"widget\"); break } } }\n        ++lineNo$$1;\n      });\n      this.curOp.forceUpdate = true;\n      signal(this, \"refresh\", this);\n    }),\n\n    operation: function(f){return runInOp(this, f)},\n\n    refresh: methodOp(function() {\n      var oldHeight = this.display.cachedTextHeight;\n      regChange(this);\n      this.curOp.forceUpdate = true;\n      clearCaches(this);\n      scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop);\n      updateGutterSpace(this);\n      if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)\n        { estimateLineHeights(this); }\n      signal(this, \"refresh\", this);\n    }),\n\n    swapDoc: methodOp(function(doc) {\n      var old = this.doc;\n      old.cm = null;\n      attachDoc(this, doc);\n      clearCaches(this);\n      this.display.input.reset();\n      scrollToCoords(this, doc.scrollLeft, doc.scrollTop);\n      this.curOp.forceScroll = true;\n      signalLater(this, \"swapDoc\", this, old);\n      return old\n    }),\n\n    getInputField: function(){return this.display.input.getField()},\n    getWrapperElement: function(){return this.display.wrapper},\n    getScrollerElement: function(){return this.display.scroller},\n    getGutterElement: function(){return this.display.gutters}\n  };\n  eventMixin(CodeMirror);\n\n  CodeMirror.registerHelper = function(type, name, value) {\n    if (!helpers.hasOwnProperty(type)) { helpers[type] = CodeMirror[type] = {_global: []}; }\n    helpers[type][name] = value;\n  };\n  CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {\n    CodeMirror.registerHelper(type, name, value);\n    helpers[type]._global.push({pred: predicate, val: value});\n  };\n};\n\n// Used for horizontal relative motion. Dir is -1 or 1 (left or\n// right), unit can be \"char\", \"column\" (like char, but doesn't\n// cross line boundaries), \"word\" (across next word), or \"group\" (to\n// the start of next group of word or non-word-non-whitespace\n// chars). The visually param controls whether, in right-to-left\n// text, direction 1 means to move towards the next index in the\n// string, or towards the character to the right of the current\n// position. The resulting position will have a hitSide=true\n// property if it reached the end of the document.\nfunction findPosH(doc, pos, dir, unit, visually) {\n  var oldPos = pos;\n  var origDir = dir;\n  var lineObj = getLine(doc, pos.line);\n  function findNextLine() {\n    var l = pos.line + dir;\n    if (l < doc.first || l >= doc.first + doc.size) { return false }\n    pos = new Pos(l, pos.ch, pos.sticky);\n    return lineObj = getLine(doc, l)\n  }\n  function moveOnce(boundToLine) {\n    var next;\n    if (visually) {\n      next = moveVisually(doc.cm, lineObj, pos, dir);\n    } else {\n      next = moveLogically(lineObj, pos, dir);\n    }\n    if (next == null) {\n      if (!boundToLine && findNextLine())\n        { pos = endOfLine(visually, doc.cm, lineObj, pos.line, dir); }\n      else\n        { return false }\n    } else {\n      pos = next;\n    }\n    return true\n  }\n\n  if (unit == \"char\") {\n    moveOnce();\n  } else if (unit == \"column\") {\n    moveOnce(true);\n  } else if (unit == \"word\" || unit == \"group\") {\n    var sawType = null, group = unit == \"group\";\n    var helper = doc.cm && doc.cm.getHelper(pos, \"wordChars\");\n    for (var first = true;; first = false) {\n      if (dir < 0 && !moveOnce(!first)) { break }\n      var cur = lineObj.text.charAt(pos.ch) || \"\\n\";\n      var type = isWordChar(cur, helper) ? \"w\"\n        : group && cur == \"\\n\" ? \"n\"\n        : !group || /\\s/.test(cur) ? null\n        : \"p\";\n      if (group && !first && !type) { type = \"s\"; }\n      if (sawType && sawType != type) {\n        if (dir < 0) {dir = 1; moveOnce(); pos.sticky = \"after\";}\n        break\n      }\n\n      if (type) { sawType = type; }\n      if (dir > 0 && !moveOnce(!first)) { break }\n    }\n  }\n  var result = skipAtomic(doc, pos, oldPos, origDir, true);\n  if (equalCursorPos(oldPos, result)) { result.hitSide = true; }\n  return result\n}\n\n// For relative vertical movement. Dir may be -1 or 1. Unit can be\n// \"page\" or \"line\". The resulting position will have a hitSide=true\n// property if it reached the end of the document.\nfunction findPosV(cm, pos, dir, unit) {\n  var doc = cm.doc, x = pos.left, y;\n  if (unit == \"page\") {\n    var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);\n    var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3);\n    y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount;\n\n  } else if (unit == \"line\") {\n    y = dir > 0 ? pos.bottom + 3 : pos.top - 3;\n  }\n  var target;\n  for (;;) {\n    target = coordsChar(cm, x, y);\n    if (!target.outside) { break }\n    if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break }\n    y += dir * 5;\n  }\n  return target\n}\n\n// CONTENTEDITABLE INPUT STYLE\n\nvar ContentEditableInput = function(cm) {\n  this.cm = cm;\n  this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;\n  this.polling = new Delayed();\n  this.composing = null;\n  this.gracePeriod = false;\n  this.readDOMTimeout = null;\n};\n\nContentEditableInput.prototype.init = function (display) {\n    var this$1 = this;\n\n  var input = this, cm = input.cm;\n  var div = input.div = display.lineDiv;\n  disableBrowserMagic(div, cm.options.spellcheck);\n\n  on(div, \"paste\", function (e) {\n    if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }\n    // IE doesn't fire input events, so we schedule a read for the pasted content in this way\n    if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); }\n  });\n\n  on(div, \"compositionstart\", function (e) {\n    this$1.composing = {data: e.data, done: false};\n  });\n  on(div, \"compositionupdate\", function (e) {\n    if (!this$1.composing) { this$1.composing = {data: e.data, done: false}; }\n  });\n  on(div, \"compositionend\", function (e) {\n    if (this$1.composing) {\n      if (e.data != this$1.composing.data) { this$1.readFromDOMSoon(); }\n      this$1.composing.done = true;\n    }\n  });\n\n  on(div, \"touchstart\", function () { return input.forceCompositionEnd(); });\n\n  on(div, \"input\", function () {\n    if (!this$1.composing) { this$1.readFromDOMSoon(); }\n  });\n\n  function onCopyCut(e) {\n    if (signalDOMEvent(cm, e)) { return }\n    if (cm.somethingSelected()) {\n      setLastCopied({lineWise: false, text: cm.getSelections()});\n      if (e.type == \"cut\") { cm.replaceSelection(\"\", null, \"cut\"); }\n    } else if (!cm.options.lineWiseCopyCut) {\n      return\n    } else {\n      var ranges = copyableRanges(cm);\n      setLastCopied({lineWise: true, text: ranges.text});\n      if (e.type == \"cut\") {\n        cm.operation(function () {\n          cm.setSelections(ranges.ranges, 0, sel_dontScroll);\n          cm.replaceSelection(\"\", null, \"cut\");\n        });\n      }\n    }\n    if (e.clipboardData) {\n      e.clipboardData.clearData();\n      var content = lastCopied.text.join(\"\\n\");\n      // iOS exposes the clipboard API, but seems to discard content inserted into it\n      e.clipboardData.setData(\"Text\", content);\n      if (e.clipboardData.getData(\"Text\") == content) {\n        e.preventDefault();\n        return\n      }\n    }\n    // Old-fashioned briefly-focus-a-textarea hack\n    var kludge = hiddenTextarea(), te = kludge.firstChild;\n    cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);\n    te.value = lastCopied.text.join(\"\\n\");\n    var hadFocus = document.activeElement;\n    selectInput(te);\n    setTimeout(function () {\n      cm.display.lineSpace.removeChild(kludge);\n      hadFocus.focus();\n      if (hadFocus == div) { input.showPrimarySelection(); }\n    }, 50);\n  }\n  on(div, \"copy\", onCopyCut);\n  on(div, \"cut\", onCopyCut);\n};\n\nContentEditableInput.prototype.prepareSelection = function () {\n  var result = prepareSelection(this.cm, false);\n  result.focus = this.cm.state.focused;\n  return result\n};\n\nContentEditableInput.prototype.showSelection = function (info, takeFocus) {\n  if (!info || !this.cm.display.view.length) { return }\n  if (info.focus || takeFocus) { this.showPrimarySelection(); }\n  this.showMultipleSelections(info);\n};\n\nContentEditableInput.prototype.showPrimarySelection = function () {\n  var sel = window.getSelection(), cm = this.cm, prim = cm.doc.sel.primary();\n  var from = prim.from(), to = prim.to();\n\n  if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) {\n    sel.removeAllRanges();\n    return\n  }\n\n  var curAnchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);\n  var curFocus = domToPos(cm, sel.focusNode, sel.focusOffset);\n  if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&\n      cmp(minPos(curAnchor, curFocus), from) == 0 &&\n      cmp(maxPos(curAnchor, curFocus), to) == 0)\n    { return }\n\n  var view = cm.display.view;\n  var start = (from.line >= cm.display.viewFrom && posToDOM(cm, from)) ||\n      {node: view[0].measure.map[2], offset: 0};\n  var end = to.line < cm.display.viewTo && posToDOM(cm, to);\n  if (!end) {\n    var measure = view[view.length - 1].measure;\n    var map$$1 = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;\n    end = {node: map$$1[map$$1.length - 1], offset: map$$1[map$$1.length - 2] - map$$1[map$$1.length - 3]};\n  }\n\n  if (!start || !end) {\n    sel.removeAllRanges();\n    return\n  }\n\n  var old = sel.rangeCount && sel.getRangeAt(0), rng;\n  try { rng = range(start.node, start.offset, end.offset, end.node); }\n  catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible\n  if (rng) {\n    if (!gecko && cm.state.focused) {\n      sel.collapse(start.node, start.offset);\n      if (!rng.collapsed) {\n        sel.removeAllRanges();\n        sel.addRange(rng);\n      }\n    } else {\n      sel.removeAllRanges();\n      sel.addRange(rng);\n    }\n    if (old && sel.anchorNode == null) { sel.addRange(old); }\n    else if (gecko) { this.startGracePeriod(); }\n  }\n  this.rememberSelection();\n};\n\nContentEditableInput.prototype.startGracePeriod = function () {\n    var this$1 = this;\n\n  clearTimeout(this.gracePeriod);\n  this.gracePeriod = setTimeout(function () {\n    this$1.gracePeriod = false;\n    if (this$1.selectionChanged())\n      { this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }); }\n  }, 20);\n};\n\nContentEditableInput.prototype.showMultipleSelections = function (info) {\n  removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);\n  removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);\n};\n\nContentEditableInput.prototype.rememberSelection = function () {\n  var sel = window.getSelection();\n  this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;\n  this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;\n};\n\nContentEditableInput.prototype.selectionInEditor = function () {\n  var sel = window.getSelection();\n  if (!sel.rangeCount) { return false }\n  var node = sel.getRangeAt(0).commonAncestorContainer;\n  return contains(this.div, node)\n};\n\nContentEditableInput.prototype.focus = function () {\n  if (this.cm.options.readOnly != \"nocursor\") {\n    if (!this.selectionInEditor())\n      { this.showSelection(this.prepareSelection(), true); }\n    this.div.focus();\n  }\n};\nContentEditableInput.prototype.blur = function () { this.div.blur(); };\nContentEditableInput.prototype.getField = function () { return this.div };\n\nContentEditableInput.prototype.supportsTouch = function () { return true };\n\nContentEditableInput.prototype.receivedFocus = function () {\n  var input = this;\n  if (this.selectionInEditor())\n    { this.pollSelection(); }\n  else\n    { runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }); }\n\n  function poll() {\n    if (input.cm.state.focused) {\n      input.pollSelection();\n      input.polling.set(input.cm.options.pollInterval, poll);\n    }\n  }\n  this.polling.set(this.cm.options.pollInterval, poll);\n};\n\nContentEditableInput.prototype.selectionChanged = function () {\n  var sel = window.getSelection();\n  return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||\n    sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset\n};\n\nContentEditableInput.prototype.pollSelection = function () {\n  if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return }\n  var sel = window.getSelection(), cm = this.cm;\n  // On Android Chrome (version 56, at least), backspacing into an\n  // uneditable block element will put the cursor in that element,\n  // and then, because it's not editable, hide the virtual keyboard.\n  // Because Android doesn't allow us to actually detect backspace\n  // presses in a sane way, this code checks for when that happens\n  // and simulates a backspace press in this case.\n  if (android && chrome && this.cm.options.gutters.length && isInGutter(sel.anchorNode)) {\n    this.cm.triggerOnKeyDown({type: \"keydown\", keyCode: 8, preventDefault: Math.abs});\n    this.blur();\n    this.focus();\n    return\n  }\n  if (this.composing) { return }\n  this.rememberSelection();\n  var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);\n  var head = domToPos(cm, sel.focusNode, sel.focusOffset);\n  if (anchor && head) { runInOp(cm, function () {\n    setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);\n    if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true; }\n  }); }\n};\n\nContentEditableInput.prototype.pollContent = function () {\n  if (this.readDOMTimeout != null) {\n    clearTimeout(this.readDOMTimeout);\n    this.readDOMTimeout = null;\n  }\n\n  var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();\n  var from = sel.from(), to = sel.to();\n  if (from.ch == 0 && from.line > cm.firstLine())\n    { from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length); }\n  if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine())\n    { to = Pos(to.line + 1, 0); }\n  if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false }\n\n  var fromIndex, fromLine, fromNode;\n  if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {\n    fromLine = lineNo(display.view[0].line);\n    fromNode = display.view[0].node;\n  } else {\n    fromLine = lineNo(display.view[fromIndex].line);\n    fromNode = display.view[fromIndex - 1].node.nextSibling;\n  }\n  var toIndex = findViewIndex(cm, to.line);\n  var toLine, toNode;\n  if (toIndex == display.view.length - 1) {\n    toLine = display.viewTo - 1;\n    toNode = display.lineDiv.lastChild;\n  } else {\n    toLine = lineNo(display.view[toIndex + 1].line) - 1;\n    toNode = display.view[toIndex + 1].node.previousSibling;\n  }\n\n  if (!fromNode) { return false }\n  var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));\n  var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));\n  while (newText.length > 1 && oldText.length > 1) {\n    if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }\n    else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }\n    else { break }\n  }\n\n  var cutFront = 0, cutEnd = 0;\n  var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);\n  while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))\n    { ++cutFront; }\n  var newBot = lst(newText), oldBot = lst(oldText);\n  var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),\n                           oldBot.length - (oldText.length == 1 ? cutFront : 0));\n  while (cutEnd < maxCutEnd &&\n         newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))\n    { ++cutEnd; }\n  // Try to move start of change to start of selection if ambiguous\n  if (newText.length == 1 && oldText.length == 1 && fromLine == from.line) {\n    while (cutFront && cutFront > from.ch &&\n           newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) {\n      cutFront--;\n      cutEnd++;\n    }\n  }\n\n  newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\\u200b+/, \"\");\n  newText[0] = newText[0].slice(cutFront).replace(/\\u200b+$/, \"\");\n\n  var chFrom = Pos(fromLine, cutFront);\n  var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);\n  if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {\n    replaceRange(cm.doc, newText, chFrom, chTo, \"+input\");\n    return true\n  }\n};\n\nContentEditableInput.prototype.ensurePolled = function () {\n  this.forceCompositionEnd();\n};\nContentEditableInput.prototype.reset = function () {\n  this.forceCompositionEnd();\n};\nContentEditableInput.prototype.forceCompositionEnd = function () {\n  if (!this.composing) { return }\n  clearTimeout(this.readDOMTimeout);\n  this.composing = null;\n  this.updateFromDOM();\n  this.div.blur();\n  this.div.focus();\n};\nContentEditableInput.prototype.readFromDOMSoon = function () {\n    var this$1 = this;\n\n  if (this.readDOMTimeout != null) { return }\n  this.readDOMTimeout = setTimeout(function () {\n    this$1.readDOMTimeout = null;\n    if (this$1.composing) {\n      if (this$1.composing.done) { this$1.composing = null; }\n      else { return }\n    }\n    this$1.updateFromDOM();\n  }, 80);\n};\n\nContentEditableInput.prototype.updateFromDOM = function () {\n    var this$1 = this;\n\n  if (this.cm.isReadOnly() || !this.pollContent())\n    { runInOp(this.cm, function () { return regChange(this$1.cm); }); }\n};\n\nContentEditableInput.prototype.setUneditable = function (node) {\n  node.contentEditable = \"false\";\n};\n\nContentEditableInput.prototype.onKeyPress = function (e) {\n  if (e.charCode == 0) { return }\n  e.preventDefault();\n  if (!this.cm.isReadOnly())\n    { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); }\n};\n\nContentEditableInput.prototype.readOnlyChanged = function (val) {\n  this.div.contentEditable = String(val != \"nocursor\");\n};\n\nContentEditableInput.prototype.onContextMenu = function () {};\nContentEditableInput.prototype.resetPosition = function () {};\n\nContentEditableInput.prototype.needsContentAttribute = true;\n\nfunction posToDOM(cm, pos) {\n  var view = findViewForLine(cm, pos.line);\n  if (!view || view.hidden) { return null }\n  var line = getLine(cm.doc, pos.line);\n  var info = mapFromLineView(view, line, pos.line);\n\n  var order = getOrder(line, cm.doc.direction), side = \"left\";\n  if (order) {\n    var partPos = getBidiPartAt(order, pos.ch);\n    side = partPos % 2 ? \"right\" : \"left\";\n  }\n  var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);\n  result.offset = result.collapse == \"right\" ? result.end : result.start;\n  return result\n}\n\nfunction isInGutter(node) {\n  for (var scan = node; scan; scan = scan.parentNode)\n    { if (/CodeMirror-gutter-wrapper/.test(scan.className)) { return true } }\n  return false\n}\n\nfunction badPos(pos, bad) { if (bad) { pos.bad = true; } return pos }\n\nfunction domTextBetween(cm, from, to, fromLine, toLine) {\n  var text = \"\", closing = false, lineSep = cm.doc.lineSeparator();\n  function recognizeMarker(id) { return function (marker) { return marker.id == id; } }\n  function close() {\n    if (closing) {\n      text += lineSep;\n      closing = false;\n    }\n  }\n  function addText(str) {\n    if (str) {\n      close();\n      text += str;\n    }\n  }\n  function walk(node) {\n    if (node.nodeType == 1) {\n      var cmText = node.getAttribute(\"cm-text\");\n      if (cmText != null) {\n        addText(cmText || node.textContent.replace(/\\u200b/g, \"\"));\n        return\n      }\n      var markerID = node.getAttribute(\"cm-marker\"), range$$1;\n      if (markerID) {\n        var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));\n        if (found.length && (range$$1 = found[0].find()))\n          { addText(getBetween(cm.doc, range$$1.from, range$$1.to).join(lineSep)); }\n        return\n      }\n      if (node.getAttribute(\"contenteditable\") == \"false\") { return }\n      var isBlock = /^(pre|div|p)$/i.test(node.nodeName);\n      if (isBlock) { close(); }\n      for (var i = 0; i < node.childNodes.length; i++)\n        { walk(node.childNodes[i]); }\n      if (isBlock) { closing = true; }\n    } else if (node.nodeType == 3) {\n      addText(node.nodeValue);\n    }\n  }\n  for (;;) {\n    walk(from);\n    if (from == to) { break }\n    from = from.nextSibling;\n  }\n  return text\n}\n\nfunction domToPos(cm, node, offset) {\n  var lineNode;\n  if (node == cm.display.lineDiv) {\n    lineNode = cm.display.lineDiv.childNodes[offset];\n    if (!lineNode) { return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) }\n    node = null; offset = 0;\n  } else {\n    for (lineNode = node;; lineNode = lineNode.parentNode) {\n      if (!lineNode || lineNode == cm.display.lineDiv) { return null }\n      if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) { break }\n    }\n  }\n  for (var i = 0; i < cm.display.view.length; i++) {\n    var lineView = cm.display.view[i];\n    if (lineView.node == lineNode)\n      { return locateNodeInLineView(lineView, node, offset) }\n  }\n}\n\nfunction locateNodeInLineView(lineView, node, offset) {\n  var wrapper = lineView.text.firstChild, bad = false;\n  if (!node || !contains(wrapper, node)) { return badPos(Pos(lineNo(lineView.line), 0), true) }\n  if (node == wrapper) {\n    bad = true;\n    node = wrapper.childNodes[offset];\n    offset = 0;\n    if (!node) {\n      var line = lineView.rest ? lst(lineView.rest) : lineView.line;\n      return badPos(Pos(lineNo(line), line.text.length), bad)\n    }\n  }\n\n  var textNode = node.nodeType == 3 ? node : null, topNode = node;\n  if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {\n    textNode = node.firstChild;\n    if (offset) { offset = textNode.nodeValue.length; }\n  }\n  while (topNode.parentNode != wrapper) { topNode = topNode.parentNode; }\n  var measure = lineView.measure, maps = measure.maps;\n\n  function find(textNode, topNode, offset) {\n    for (var i = -1; i < (maps ? maps.length : 0); i++) {\n      var map$$1 = i < 0 ? measure.map : maps[i];\n      for (var j = 0; j < map$$1.length; j += 3) {\n        var curNode = map$$1[j + 2];\n        if (curNode == textNode || curNode == topNode) {\n          var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);\n          var ch = map$$1[j] + offset;\n          if (offset < 0 || curNode != textNode) { ch = map$$1[j + (offset ? 1 : 0)]; }\n          return Pos(line, ch)\n        }\n      }\n    }\n  }\n  var found = find(textNode, topNode, offset);\n  if (found) { return badPos(found, bad) }\n\n  // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems\n  for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {\n    found = find(after, after.firstChild, 0);\n    if (found)\n      { return badPos(Pos(found.line, found.ch - dist), bad) }\n    else\n      { dist += after.textContent.length; }\n  }\n  for (var before = topNode.previousSibling, dist$1 = offset; before; before = before.previousSibling) {\n    found = find(before, before.firstChild, -1);\n    if (found)\n      { return badPos(Pos(found.line, found.ch + dist$1), bad) }\n    else\n      { dist$1 += before.textContent.length; }\n  }\n}\n\n// TEXTAREA INPUT STYLE\n\nvar TextareaInput = function(cm) {\n  this.cm = cm;\n  // See input.poll and input.reset\n  this.prevInput = \"\";\n\n  // Flag that indicates whether we expect input to appear real soon\n  // now (after some event like 'keypress' or 'input') and are\n  // polling intensively.\n  this.pollingFast = false;\n  // Self-resetting timeout for the poller\n  this.polling = new Delayed();\n  // Tracks when input.reset has punted to just putting a short\n  // string into the textarea instead of the full selection.\n  this.inaccurateSelection = false;\n  // Used to work around IE issue with selection being forgotten when focus moves away from textarea\n  this.hasSelection = false;\n  this.composing = null;\n};\n\nTextareaInput.prototype.init = function (display) {\n    var this$1 = this;\n\n  var input = this, cm = this.cm;\n\n  // Wraps and hides input textarea\n  var div = this.wrapper = hiddenTextarea();\n  // The semihidden textarea that is focused when the editor is\n  // focused, and receives input.\n  var te = this.textarea = div.firstChild;\n  display.wrapper.insertBefore(div, display.wrapper.firstChild);\n\n  // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)\n  if (ios) { te.style.width = \"0px\"; }\n\n  on(te, \"input\", function () {\n    if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null; }\n    input.poll();\n  });\n\n  on(te, \"paste\", function (e) {\n    if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }\n\n    cm.state.pasteIncoming = true;\n    input.fastPoll();\n  });\n\n  function prepareCopyCut(e) {\n    if (signalDOMEvent(cm, e)) { return }\n    if (cm.somethingSelected()) {\n      setLastCopied({lineWise: false, text: cm.getSelections()});\n      if (input.inaccurateSelection) {\n        input.prevInput = \"\";\n        input.inaccurateSelection = false;\n        te.value = lastCopied.text.join(\"\\n\");\n        selectInput(te);\n      }\n    } else if (!cm.options.lineWiseCopyCut) {\n      return\n    } else {\n      var ranges = copyableRanges(cm);\n      setLastCopied({lineWise: true, text: ranges.text});\n      if (e.type == \"cut\") {\n        cm.setSelections(ranges.ranges, null, sel_dontScroll);\n      } else {\n        input.prevInput = \"\";\n        te.value = ranges.text.join(\"\\n\");\n        selectInput(te);\n      }\n    }\n    if (e.type == \"cut\") { cm.state.cutIncoming = true; }\n  }\n  on(te, \"cut\", prepareCopyCut);\n  on(te, \"copy\", prepareCopyCut);\n\n  on(display.scroller, \"paste\", function (e) {\n    if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return }\n    cm.state.pasteIncoming = true;\n    input.focus();\n  });\n\n  // Prevent normal selection in the editor (we handle our own)\n  on(display.lineSpace, \"selectstart\", function (e) {\n    if (!eventInWidget(display, e)) { e_preventDefault(e); }\n  });\n\n  on(te, \"compositionstart\", function () {\n    var start = cm.getCursor(\"from\");\n    if (input.composing) { input.composing.range.clear(); }\n    input.composing = {\n      start: start,\n      range: cm.markText(start, cm.getCursor(\"to\"), {className: \"CodeMirror-composing\"})\n    };\n  });\n  on(te, \"compositionend\", function () {\n    if (input.composing) {\n      input.poll();\n      input.composing.range.clear();\n      input.composing = null;\n    }\n  });\n};\n\nTextareaInput.prototype.prepareSelection = function () {\n  // Redraw the selection and/or cursor\n  var cm = this.cm, display = cm.display, doc = cm.doc;\n  var result = prepareSelection(cm);\n\n  // Move the hidden textarea near the cursor to prevent scrolling artifacts\n  if (cm.options.moveInputWithCursor) {\n    var headPos = cursorCoords(cm, doc.sel.primary().head, \"div\");\n    var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();\n    result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,\n                                        headPos.top + lineOff.top - wrapOff.top));\n    result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,\n                                         headPos.left + lineOff.left - wrapOff.left));\n  }\n\n  return result\n};\n\nTextareaInput.prototype.showSelection = function (drawn) {\n  var cm = this.cm, display = cm.display;\n  removeChildrenAndAdd(display.cursorDiv, drawn.cursors);\n  removeChildrenAndAdd(display.selectionDiv, drawn.selection);\n  if (drawn.teTop != null) {\n    this.wrapper.style.top = drawn.teTop + \"px\";\n    this.wrapper.style.left = drawn.teLeft + \"px\";\n  }\n};\n\n// Reset the input to correspond to the selection (or to be empty,\n// when not typing and nothing is selected)\nTextareaInput.prototype.reset = function (typing) {\n  if (this.contextMenuPending || this.composing) { return }\n  var minimal, selected, cm = this.cm, doc = cm.doc;\n  if (cm.somethingSelected()) {\n    this.prevInput = \"\";\n    var range$$1 = doc.sel.primary();\n    minimal = hasCopyEvent &&\n      (range$$1.to().line - range$$1.from().line > 100 || (selected = cm.getSelection()).length > 1000);\n    var content = minimal ? \"-\" : selected || cm.getSelection();\n    this.textarea.value = content;\n    if (cm.state.focused) { selectInput(this.textarea); }\n    if (ie && ie_version >= 9) { this.hasSelection = content; }\n  } else if (!typing) {\n    this.prevInput = this.textarea.value = \"\";\n    if (ie && ie_version >= 9) { this.hasSelection = null; }\n  }\n  this.inaccurateSelection = minimal;\n};\n\nTextareaInput.prototype.getField = function () { return this.textarea };\n\nTextareaInput.prototype.supportsTouch = function () { return false };\n\nTextareaInput.prototype.focus = function () {\n  if (this.cm.options.readOnly != \"nocursor\" && (!mobile || activeElt() != this.textarea)) {\n    try { this.textarea.focus(); }\n    catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM\n  }\n};\n\nTextareaInput.prototype.blur = function () { this.textarea.blur(); };\n\nTextareaInput.prototype.resetPosition = function () {\n  this.wrapper.style.top = this.wrapper.style.left = 0;\n};\n\nTextareaInput.prototype.receivedFocus = function () { this.slowPoll(); };\n\n// Poll for input changes, using the normal rate of polling. This\n// runs as long as the editor is focused.\nTextareaInput.prototype.slowPoll = function () {\n    var this$1 = this;\n\n  if (this.pollingFast) { return }\n  this.polling.set(this.cm.options.pollInterval, function () {\n    this$1.poll();\n    if (this$1.cm.state.focused) { this$1.slowPoll(); }\n  });\n};\n\n// When an event has just come in that is likely to add or change\n// something in the input textarea, we poll faster, to ensure that\n// the change appears on the screen quickly.\nTextareaInput.prototype.fastPoll = function () {\n  var missed = false, input = this;\n  input.pollingFast = true;\n  function p() {\n    var changed = input.poll();\n    if (!changed && !missed) {missed = true; input.polling.set(60, p);}\n    else {input.pollingFast = false; input.slowPoll();}\n  }\n  input.polling.set(20, p);\n};\n\n// Read input from the textarea, and update the document to match.\n// When something is selected, it is present in the textarea, and\n// selected (unless it is huge, in which case a placeholder is\n// used). When nothing is selected, the cursor sits after previously\n// seen text (can be empty), which is stored in prevInput (we must\n// not reset the textarea when typing, because that breaks IME).\nTextareaInput.prototype.poll = function () {\n    var this$1 = this;\n\n  var cm = this.cm, input = this.textarea, prevInput = this.prevInput;\n  // Since this is called a *lot*, try to bail out as cheaply as\n  // possible when it is clear that nothing happened. hasSelection\n  // will be the case when there is a lot of text in the textarea,\n  // in which case reading its value would be expensive.\n  if (this.contextMenuPending || !cm.state.focused ||\n      (hasSelection(input) && !prevInput && !this.composing) ||\n      cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)\n    { return false }\n\n  var text = input.value;\n  // If nothing changed, bail.\n  if (text == prevInput && !cm.somethingSelected()) { return false }\n  // Work around nonsensical selection resetting in IE9/10, and\n  // inexplicable appearance of private area unicode characters on\n  // some key combos in Mac (#2689).\n  if (ie && ie_version >= 9 && this.hasSelection === text ||\n      mac && /[\\uf700-\\uf7ff]/.test(text)) {\n    cm.display.input.reset();\n    return false\n  }\n\n  if (cm.doc.sel == cm.display.selForContextMenu) {\n    var first = text.charCodeAt(0);\n    if (first == 0x200b && !prevInput) { prevInput = \"\\u200b\"; }\n    if (first == 0x21da) { this.reset(); return this.cm.execCommand(\"undo\") }\n  }\n  // Find the part of the input that is actually new\n  var same = 0, l = Math.min(prevInput.length, text.length);\n  while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same; }\n\n  runInOp(cm, function () {\n    applyTextInput(cm, text.slice(same), prevInput.length - same,\n                   null, this$1.composing ? \"*compose\" : null);\n\n    // Don't leave long text in the textarea, since it makes further polling slow\n    if (text.length > 1000 || text.indexOf(\"\\n\") > -1) { input.value = this$1.prevInput = \"\"; }\n    else { this$1.prevInput = text; }\n\n    if (this$1.composing) {\n      this$1.composing.range.clear();\n      this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor(\"to\"),\n                                         {className: \"CodeMirror-composing\"});\n    }\n  });\n  return true\n};\n\nTextareaInput.prototype.ensurePolled = function () {\n  if (this.pollingFast && this.poll()) { this.pollingFast = false; }\n};\n\nTextareaInput.prototype.onKeyPress = function () {\n  if (ie && ie_version >= 9) { this.hasSelection = null; }\n  this.fastPoll();\n};\n\nTextareaInput.prototype.onContextMenu = function (e) {\n  var input = this, cm = input.cm, display = cm.display, te = input.textarea;\n  var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;\n  if (!pos || presto) { return } // Opera is difficult.\n\n  // Reset the current text selection only if the click is done outside of the selection\n  // and 'resetSelectionOnContextMenu' option is true.\n  var reset = cm.options.resetSelectionOnContextMenu;\n  if (reset && cm.doc.sel.contains(pos) == -1)\n    { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); }\n\n  var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText;\n  input.wrapper.style.cssText = \"position: absolute\";\n  var wrapperBox = input.wrapper.getBoundingClientRect();\n  te.style.cssText = \"position: absolute; width: 30px; height: 30px;\\n      top: \" + (e.clientY - wrapperBox.top - 5) + \"px; left: \" + (e.clientX - wrapperBox.left - 5) + \"px;\\n      z-index: 1000; background: \" + (ie ? \"rgba(255, 255, 255, .05)\" : \"transparent\") + \";\\n      outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);\";\n  var oldScrollY;\n  if (webkit) { oldScrollY = window.scrollY; } // Work around Chrome issue (#2712)\n  display.input.focus();\n  if (webkit) { window.scrollTo(null, oldScrollY); }\n  display.input.reset();\n  // Adds \"Select all\" to context menu in FF\n  if (!cm.somethingSelected()) { te.value = input.prevInput = \" \"; }\n  input.contextMenuPending = true;\n  display.selForContextMenu = cm.doc.sel;\n  clearTimeout(display.detectingSelectAll);\n\n  // Select-all will be greyed out if there's nothing to select, so\n  // this adds a zero-width space so that we can later check whether\n  // it got selected.\n  function prepareSelectAllHack() {\n    if (te.selectionStart != null) {\n      var selected = cm.somethingSelected();\n      var extval = \"\\u200b\" + (selected ? te.value : \"\");\n      te.value = \"\\u21da\"; // Used to catch context-menu undo\n      te.value = extval;\n      input.prevInput = selected ? \"\" : \"\\u200b\";\n      te.selectionStart = 1; te.selectionEnd = extval.length;\n      // Re-set this, in case some other handler touched the\n      // selection in the meantime.\n      display.selForContextMenu = cm.doc.sel;\n    }\n  }\n  function rehide() {\n    input.contextMenuPending = false;\n    input.wrapper.style.cssText = oldWrapperCSS;\n    te.style.cssText = oldCSS;\n    if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); }\n\n    // Try to detect the user choosing select-all\n    if (te.selectionStart != null) {\n      if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack(); }\n      var i = 0, poll = function () {\n        if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&\n            te.selectionEnd > 0 && input.prevInput == \"\\u200b\") {\n          operation(cm, selectAll)(cm);\n        } else if (i++ < 10) {\n          display.detectingSelectAll = setTimeout(poll, 500);\n        } else {\n          display.selForContextMenu = null;\n          display.input.reset();\n        }\n      };\n      display.detectingSelectAll = setTimeout(poll, 200);\n    }\n  }\n\n  if (ie && ie_version >= 9) { prepareSelectAllHack(); }\n  if (captureRightClick) {\n    e_stop(e);\n    var mouseup = function () {\n      off(window, \"mouseup\", mouseup);\n      setTimeout(rehide, 20);\n    };\n    on(window, \"mouseup\", mouseup);\n  } else {\n    setTimeout(rehide, 50);\n  }\n};\n\nTextareaInput.prototype.readOnlyChanged = function (val) {\n  if (!val) { this.reset(); }\n  this.textarea.disabled = val == \"nocursor\";\n};\n\nTextareaInput.prototype.setUneditable = function () {};\n\nTextareaInput.prototype.needsContentAttribute = false;\n\nfunction fromTextArea(textarea, options) {\n  options = options ? copyObj(options) : {};\n  options.value = textarea.value;\n  if (!options.tabindex && textarea.tabIndex)\n    { options.tabindex = textarea.tabIndex; }\n  if (!options.placeholder && textarea.placeholder)\n    { options.placeholder = textarea.placeholder; }\n  // Set autofocus to true if this textarea is focused, or if it has\n  // autofocus and no other element is focused.\n  if (options.autofocus == null) {\n    var hasFocus = activeElt();\n    options.autofocus = hasFocus == textarea ||\n      textarea.getAttribute(\"autofocus\") != null && hasFocus == document.body;\n  }\n\n  function save() {textarea.value = cm.getValue();}\n\n  var realSubmit;\n  if (textarea.form) {\n    on(textarea.form, \"submit\", save);\n    // Deplorable hack to make the submit method do the right thing.\n    if (!options.leaveSubmitMethodAlone) {\n      var form = textarea.form;\n      realSubmit = form.submit;\n      try {\n        var wrappedSubmit = form.submit = function () {\n          save();\n          form.submit = realSubmit;\n          form.submit();\n          form.submit = wrappedSubmit;\n        };\n      } catch(e) {}\n    }\n  }\n\n  options.finishInit = function (cm) {\n    cm.save = save;\n    cm.getTextArea = function () { return textarea; };\n    cm.toTextArea = function () {\n      cm.toTextArea = isNaN; // Prevent this from being ran twice\n      save();\n      textarea.parentNode.removeChild(cm.getWrapperElement());\n      textarea.style.display = \"\";\n      if (textarea.form) {\n        off(textarea.form, \"submit\", save);\n        if (typeof textarea.form.submit == \"function\")\n          { textarea.form.submit = realSubmit; }\n      }\n    };\n  };\n\n  textarea.style.display = \"none\";\n  var cm = CodeMirror$1(function (node) { return textarea.parentNode.insertBefore(node, textarea.nextSibling); },\n    options);\n  return cm\n}\n\nfunction addLegacyProps(CodeMirror) {\n  CodeMirror.off = off;\n  CodeMirror.on = on;\n  CodeMirror.wheelEventPixels = wheelEventPixels;\n  CodeMirror.Doc = Doc;\n  CodeMirror.splitLines = splitLinesAuto;\n  CodeMirror.countColumn = countColumn;\n  CodeMirror.findColumn = findColumn;\n  CodeMirror.isWordChar = isWordCharBasic;\n  CodeMirror.Pass = Pass;\n  CodeMirror.signal = signal;\n  CodeMirror.Line = Line;\n  CodeMirror.changeEnd = changeEnd;\n  CodeMirror.scrollbarModel = scrollbarModel;\n  CodeMirror.Pos = Pos;\n  CodeMirror.cmpPos = cmp;\n  CodeMirror.modes = modes;\n  CodeMirror.mimeModes = mimeModes;\n  CodeMirror.resolveMode = resolveMode;\n  CodeMirror.getMode = getMode;\n  CodeMirror.modeExtensions = modeExtensions;\n  CodeMirror.extendMode = extendMode;\n  CodeMirror.copyState = copyState;\n  CodeMirror.startState = startState;\n  CodeMirror.innerMode = innerMode;\n  CodeMirror.commands = commands;\n  CodeMirror.keyMap = keyMap;\n  CodeMirror.keyName = keyName;\n  CodeMirror.isModifierKey = isModifierKey;\n  CodeMirror.lookupKey = lookupKey;\n  CodeMirror.normalizeKeyMap = normalizeKeyMap;\n  CodeMirror.StringStream = StringStream;\n  CodeMirror.SharedTextMarker = SharedTextMarker;\n  CodeMirror.TextMarker = TextMarker;\n  CodeMirror.LineWidget = LineWidget;\n  CodeMirror.e_preventDefault = e_preventDefault;\n  CodeMirror.e_stopPropagation = e_stopPropagation;\n  CodeMirror.e_stop = e_stop;\n  CodeMirror.addClass = addClass;\n  CodeMirror.contains = contains;\n  CodeMirror.rmClass = rmClass;\n  CodeMirror.keyNames = keyNames;\n}\n\n// EDITOR CONSTRUCTOR\n\ndefineOptions(CodeMirror$1);\n\naddEditorMethods(CodeMirror$1);\n\n// Set up methods on CodeMirror's prototype to redirect to the editor's document.\nvar dontDelegate = \"iter insert remove copy getEditor constructor\".split(\" \");\nfor (var prop in Doc.prototype) { if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)\n  { CodeMirror$1.prototype[prop] = (function(method) {\n    return function() {return method.apply(this.doc, arguments)}\n  })(Doc.prototype[prop]); } }\n\neventMixin(Doc);\n\n// INPUT HANDLING\n\nCodeMirror$1.inputStyles = {\"textarea\": TextareaInput, \"contenteditable\": ContentEditableInput};\n\n// MODE DEFINITION AND QUERYING\n\n// Extra arguments are stored as the mode's dependencies, which is\n// used by (legacy) mechanisms like loadmode.js to automatically\n// load a mode. (Preferred mechanism is the require/define calls.)\nCodeMirror$1.defineMode = function(name/*, mode, …*/) {\n  if (!CodeMirror$1.defaults.mode && name != \"null\") { CodeMirror$1.defaults.mode = name; }\n  defineMode.apply(this, arguments);\n};\n\nCodeMirror$1.defineMIME = defineMIME;\n\n// Minimal default mode.\nCodeMirror$1.defineMode(\"null\", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); });\nCodeMirror$1.defineMIME(\"text/plain\", \"null\");\n\n// EXTENSIONS\n\nCodeMirror$1.defineExtension = function (name, func) {\n  CodeMirror$1.prototype[name] = func;\n};\nCodeMirror$1.defineDocExtension = function (name, func) {\n  Doc.prototype[name] = func;\n};\n\nCodeMirror$1.fromTextArea = fromTextArea;\n\naddLegacyProps(CodeMirror$1);\n\nCodeMirror$1.version = \"5.27.5\";\n\nreturn CodeMirror$1;\n\n})));\n"
  },
  {
    "path": "docs/js/codemirror/mode/javascript/javascript.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nfunction expressionAllowed(stream, state, backUp) {\n  return /^(?:operator|sof|keyword c|case|new|export|default|[\\[{}\\(,;:]|=>)$/.test(state.lastType) ||\n    (state.lastType == \"quasi\" && /\\{\\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))\n}\n\nCodeMirror.defineMode(\"javascript\", function(config, parserConfig) {\n  var indentUnit = config.indentUnit;\n  var statementIndent = parserConfig.statementIndent;\n  var jsonldMode = parserConfig.jsonld;\n  var jsonMode = parserConfig.json || jsonldMode;\n  var isTS = parserConfig.typescript;\n  var wordRE = parserConfig.wordCharacters || /[\\w$\\xa1-\\uffff]/;\n\n  // Tokenizer\n\n  var keywords = function(){\n    function kw(type) {return {type: type, style: \"keyword\"};}\n    var A = kw(\"keyword a\"), B = kw(\"keyword b\"), C = kw(\"keyword c\");\n    var operator = kw(\"operator\"), atom = {type: \"atom\", style: \"atom\"};\n\n    var jsKeywords = {\n      \"if\": kw(\"if\"), \"while\": A, \"with\": A, \"else\": B, \"do\": B, \"try\": B, \"finally\": B,\n      \"return\": C, \"break\": C, \"continue\": C, \"new\": kw(\"new\"), \"delete\": C, \"throw\": C, \"debugger\": C,\n      \"var\": kw(\"var\"), \"const\": kw(\"var\"), \"let\": kw(\"var\"),\n      \"function\": kw(\"function\"), \"catch\": kw(\"catch\"),\n      \"for\": kw(\"for\"), \"switch\": kw(\"switch\"), \"case\": kw(\"case\"), \"default\": kw(\"default\"),\n      \"in\": operator, \"typeof\": operator, \"instanceof\": operator,\n      \"true\": atom, \"false\": atom, \"null\": atom, \"undefined\": atom, \"NaN\": atom, \"Infinity\": atom,\n      \"this\": kw(\"this\"), \"class\": kw(\"class\"), \"super\": kw(\"atom\"),\n      \"yield\": C, \"export\": kw(\"export\"), \"import\": kw(\"import\"), \"extends\": C,\n      \"await\": C\n    };\n\n    // Extend the 'normal' keywords with the TypeScript language extensions\n    if (isTS) {\n      var type = {type: \"variable\", style: \"type\"};\n      var tsKeywords = {\n        // object-like things\n        \"interface\": kw(\"class\"),\n        \"implements\": C,\n        \"namespace\": C,\n        \"module\": kw(\"module\"),\n        \"enum\": kw(\"module\"),\n\n        // scope modifiers\n        \"public\": kw(\"modifier\"),\n        \"private\": kw(\"modifier\"),\n        \"protected\": kw(\"modifier\"),\n        \"abstract\": kw(\"modifier\"),\n\n        // types\n        \"string\": type, \"number\": type, \"boolean\": type, \"any\": type\n      };\n\n      for (var attr in tsKeywords) {\n        jsKeywords[attr] = tsKeywords[attr];\n      }\n    }\n\n    return jsKeywords;\n  }();\n\n  var isOperatorChar = /[+\\-*&%=<>!?|~^@]/;\n  var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)\"/;\n\n  function readRegexp(stream) {\n    var escaped = false, next, inSet = false;\n    while ((next = stream.next()) != null) {\n      if (!escaped) {\n        if (next == \"/\" && !inSet) return;\n        if (next == \"[\") inSet = true;\n        else if (inSet && next == \"]\") inSet = false;\n      }\n      escaped = !escaped && next == \"\\\\\";\n    }\n  }\n\n  // Used as scratch variables to communicate multiple values without\n  // consing up tons of objects.\n  var type, content;\n  function ret(tp, style, cont) {\n    type = tp; content = cont;\n    return style;\n  }\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n    if (ch == '\"' || ch == \"'\") {\n      state.tokenize = tokenString(ch);\n      return state.tokenize(stream, state);\n    } else if (ch == \".\" && stream.match(/^\\d+(?:[eE][+\\-]?\\d+)?/)) {\n      return ret(\"number\", \"number\");\n    } else if (ch == \".\" && stream.match(\"..\")) {\n      return ret(\"spread\", \"meta\");\n    } else if (/[\\[\\]{}\\(\\),;\\:\\.]/.test(ch)) {\n      return ret(ch);\n    } else if (ch == \"=\" && stream.eat(\">\")) {\n      return ret(\"=>\", \"operator\");\n    } else if (ch == \"0\" && stream.eat(/x/i)) {\n      stream.eatWhile(/[\\da-f]/i);\n      return ret(\"number\", \"number\");\n    } else if (ch == \"0\" && stream.eat(/o/i)) {\n      stream.eatWhile(/[0-7]/i);\n      return ret(\"number\", \"number\");\n    } else if (ch == \"0\" && stream.eat(/b/i)) {\n      stream.eatWhile(/[01]/i);\n      return ret(\"number\", \"number\");\n    } else if (/\\d/.test(ch)) {\n      stream.match(/^\\d*(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/);\n      return ret(\"number\", \"number\");\n    } else if (ch == \"/\") {\n      if (stream.eat(\"*\")) {\n        state.tokenize = tokenComment;\n        return tokenComment(stream, state);\n      } else if (stream.eat(\"/\")) {\n        stream.skipToEnd();\n        return ret(\"comment\", \"comment\");\n      } else if (expressionAllowed(stream, state, 1)) {\n        readRegexp(stream);\n        stream.match(/^\\b(([gimyu])(?![gimyu]*\\2))+\\b/);\n        return ret(\"regexp\", \"string-2\");\n      } else {\n        stream.eatWhile(isOperatorChar);\n        return ret(\"operator\", \"operator\", stream.current());\n      }\n    } else if (ch == \"`\") {\n      state.tokenize = tokenQuasi;\n      return tokenQuasi(stream, state);\n    } else if (ch == \"#\") {\n      stream.skipToEnd();\n      return ret(\"error\", \"error\");\n    } else if (isOperatorChar.test(ch)) {\n      if (ch != \">\" || !state.lexical || state.lexical.type != \">\")\n        stream.eatWhile(isOperatorChar);\n      return ret(\"operator\", \"operator\", stream.current());\n    } else if (wordRE.test(ch)) {\n      stream.eatWhile(wordRE);\n      var word = stream.current()\n      if (state.lastType != \".\") {\n        if (keywords.propertyIsEnumerable(word)) {\n          var kw = keywords[word]\n          return ret(kw.type, kw.style, word)\n        }\n        if (word == \"async\" && stream.match(/^\\s*[\\(\\w]/, false))\n          return ret(\"async\", \"keyword\", word)\n      }\n      return ret(\"variable\", \"variable\", word)\n    }\n  }\n\n  function tokenString(quote) {\n    return function(stream, state) {\n      var escaped = false, next;\n      if (jsonldMode && stream.peek() == \"@\" && stream.match(isJsonldKeyword)){\n        state.tokenize = tokenBase;\n        return ret(\"jsonld-keyword\", \"meta\");\n      }\n      while ((next = stream.next()) != null) {\n        if (next == quote && !escaped) break;\n        escaped = !escaped && next == \"\\\\\";\n      }\n      if (!escaped) state.tokenize = tokenBase;\n      return ret(\"string\", \"string\");\n    };\n  }\n\n  function tokenComment(stream, state) {\n    var maybeEnd = false, ch;\n    while (ch = stream.next()) {\n      if (ch == \"/\" && maybeEnd) {\n        state.tokenize = tokenBase;\n        break;\n      }\n      maybeEnd = (ch == \"*\");\n    }\n    return ret(\"comment\", \"comment\");\n  }\n\n  function tokenQuasi(stream, state) {\n    var escaped = false, next;\n    while ((next = stream.next()) != null) {\n      if (!escaped && (next == \"`\" || next == \"$\" && stream.eat(\"{\"))) {\n        state.tokenize = tokenBase;\n        break;\n      }\n      escaped = !escaped && next == \"\\\\\";\n    }\n    return ret(\"quasi\", \"string-2\", stream.current());\n  }\n\n  var brackets = \"([{}])\";\n  // This is a crude lookahead trick to try and notice that we're\n  // parsing the argument patterns for a fat-arrow function before we\n  // actually hit the arrow token. It only works if the arrow is on\n  // the same line as the arguments and there's no strange noise\n  // (comments) in between. Fallback is to only notice when we hit the\n  // arrow, and not declare the arguments as locals for the arrow\n  // body.\n  function findFatArrow(stream, state) {\n    if (state.fatArrowAt) state.fatArrowAt = null;\n    var arrow = stream.string.indexOf(\"=>\", stream.start);\n    if (arrow < 0) return;\n\n    if (isTS) { // Try to skip TypeScript return type declarations after the arguments\n      var m = /:\\s*(?:\\w+(?:<[^>]*>|\\[\\])?|\\{[^}]*\\})\\s*$/.exec(stream.string.slice(stream.start, arrow))\n      if (m) arrow = m.index\n    }\n\n    var depth = 0, sawSomething = false;\n    for (var pos = arrow - 1; pos >= 0; --pos) {\n      var ch = stream.string.charAt(pos);\n      var bracket = brackets.indexOf(ch);\n      if (bracket >= 0 && bracket < 3) {\n        if (!depth) { ++pos; break; }\n        if (--depth == 0) { if (ch == \"(\") sawSomething = true; break; }\n      } else if (bracket >= 3 && bracket < 6) {\n        ++depth;\n      } else if (wordRE.test(ch)) {\n        sawSomething = true;\n      } else if (/[\"'\\/]/.test(ch)) {\n        return;\n      } else if (sawSomething && !depth) {\n        ++pos;\n        break;\n      }\n    }\n    if (sawSomething && !depth) state.fatArrowAt = pos;\n  }\n\n  // Parser\n\n  var atomicTypes = {\"atom\": true, \"number\": true, \"variable\": true, \"string\": true, \"regexp\": true, \"this\": true, \"jsonld-keyword\": true};\n\n  function JSLexical(indented, column, type, align, prev, info) {\n    this.indented = indented;\n    this.column = column;\n    this.type = type;\n    this.prev = prev;\n    this.info = info;\n    if (align != null) this.align = align;\n  }\n\n  function inScope(state, varname) {\n    for (var v = state.localVars; v; v = v.next)\n      if (v.name == varname) return true;\n    for (var cx = state.context; cx; cx = cx.prev) {\n      for (var v = cx.vars; v; v = v.next)\n        if (v.name == varname) return true;\n    }\n  }\n\n  function parseJS(state, style, type, content, stream) {\n    var cc = state.cc;\n    // Communicate our context to the combinators.\n    // (Less wasteful than consing up a hundred closures on every call.)\n    cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;\n\n    if (!state.lexical.hasOwnProperty(\"align\"))\n      state.lexical.align = true;\n\n    while(true) {\n      var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;\n      if (combinator(type, content)) {\n        while(cc.length && cc[cc.length - 1].lex)\n          cc.pop()();\n        if (cx.marked) return cx.marked;\n        if (type == \"variable\" && inScope(state, content)) return \"variable-2\";\n        return style;\n      }\n    }\n  }\n\n  // Combinator utils\n\n  var cx = {state: null, column: null, marked: null, cc: null};\n  function pass() {\n    for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);\n  }\n  function cont() {\n    pass.apply(null, arguments);\n    return true;\n  }\n  function register(varname) {\n    function inList(list) {\n      for (var v = list; v; v = v.next)\n        if (v.name == varname) return true;\n      return false;\n    }\n    var state = cx.state;\n    cx.marked = \"def\";\n    if (state.context) {\n      if (inList(state.localVars)) return;\n      state.localVars = {name: varname, next: state.localVars};\n    } else {\n      if (inList(state.globalVars)) return;\n      if (parserConfig.globalVars)\n        state.globalVars = {name: varname, next: state.globalVars};\n    }\n  }\n\n  // Combinators\n\n  var defaultVars = {name: \"this\", next: {name: \"arguments\"}};\n  function pushcontext() {\n    cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};\n    cx.state.localVars = defaultVars;\n  }\n  function popcontext() {\n    cx.state.localVars = cx.state.context.vars;\n    cx.state.context = cx.state.context.prev;\n  }\n  function pushlex(type, info) {\n    var result = function() {\n      var state = cx.state, indent = state.indented;\n      if (state.lexical.type == \"stat\") indent = state.lexical.indented;\n      else for (var outer = state.lexical; outer && outer.type == \")\" && outer.align; outer = outer.prev)\n        indent = outer.indented;\n      state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);\n    };\n    result.lex = true;\n    return result;\n  }\n  function poplex() {\n    var state = cx.state;\n    if (state.lexical.prev) {\n      if (state.lexical.type == \")\")\n        state.indented = state.lexical.indented;\n      state.lexical = state.lexical.prev;\n    }\n  }\n  poplex.lex = true;\n\n  function expect(wanted) {\n    function exp(type) {\n      if (type == wanted) return cont();\n      else if (wanted == \";\") return pass();\n      else return cont(exp);\n    };\n    return exp;\n  }\n\n  function statement(type, value) {\n    if (type == \"var\") return cont(pushlex(\"vardef\", value.length), vardef, expect(\";\"), poplex);\n    if (type == \"keyword a\") return cont(pushlex(\"form\"), parenExpr, statement, poplex);\n    if (type == \"keyword b\") return cont(pushlex(\"form\"), statement, poplex);\n    if (type == \"{\") return cont(pushlex(\"}\"), block, poplex);\n    if (type == \";\") return cont();\n    if (type == \"if\") {\n      if (cx.state.lexical.info == \"else\" && cx.state.cc[cx.state.cc.length - 1] == poplex)\n        cx.state.cc.pop()();\n      return cont(pushlex(\"form\"), parenExpr, statement, poplex, maybeelse);\n    }\n    if (type == \"function\") return cont(functiondef);\n    if (type == \"for\") return cont(pushlex(\"form\"), forspec, statement, poplex);\n    if (type == \"variable\") {\n      if (isTS && value == \"type\") {\n        cx.marked = \"keyword\"\n        return cont(typeexpr, expect(\"operator\"), typeexpr, expect(\";\"));\n      } else {\n        return cont(pushlex(\"stat\"), maybelabel);\n      }\n    }\n    if (type == \"switch\") return cont(pushlex(\"form\"), parenExpr, expect(\"{\"), pushlex(\"}\", \"switch\"),\n                                      block, poplex, poplex);\n    if (type == \"case\") return cont(expression, expect(\":\"));\n    if (type == \"default\") return cont(expect(\":\"));\n    if (type == \"catch\") return cont(pushlex(\"form\"), pushcontext, expect(\"(\"), funarg, expect(\")\"),\n                                     statement, poplex, popcontext);\n    if (type == \"class\") return cont(pushlex(\"form\"), className, poplex);\n    if (type == \"export\") return cont(pushlex(\"stat\"), afterExport, poplex);\n    if (type == \"import\") return cont(pushlex(\"stat\"), afterImport, poplex);\n    if (type == \"module\") return cont(pushlex(\"form\"), pattern, expect(\"{\"), pushlex(\"}\"), block, poplex, poplex)\n    if (type == \"async\") return cont(statement)\n    if (value == \"@\") return cont(expression, statement)\n    return pass(pushlex(\"stat\"), expression, expect(\";\"), poplex);\n  }\n  function expression(type) {\n    return expressionInner(type, false);\n  }\n  function expressionNoComma(type) {\n    return expressionInner(type, true);\n  }\n  function parenExpr(type) {\n    if (type != \"(\") return pass()\n    return cont(pushlex(\")\"), expression, expect(\")\"), poplex)\n  }\n  function expressionInner(type, noComma) {\n    if (cx.state.fatArrowAt == cx.stream.start) {\n      var body = noComma ? arrowBodyNoComma : arrowBody;\n      if (type == \"(\") return cont(pushcontext, pushlex(\")\"), commasep(pattern, \")\"), poplex, expect(\"=>\"), body, popcontext);\n      else if (type == \"variable\") return pass(pushcontext, pattern, expect(\"=>\"), body, popcontext);\n    }\n\n    var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;\n    if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);\n    if (type == \"function\") return cont(functiondef, maybeop);\n    if (type == \"class\") return cont(pushlex(\"form\"), classExpression, poplex);\n    if (type == \"keyword c\" || type == \"async\") return cont(noComma ? maybeexpressionNoComma : maybeexpression);\n    if (type == \"(\") return cont(pushlex(\")\"), maybeexpression, expect(\")\"), poplex, maybeop);\n    if (type == \"operator\" || type == \"spread\") return cont(noComma ? expressionNoComma : expression);\n    if (type == \"[\") return cont(pushlex(\"]\"), arrayLiteral, poplex, maybeop);\n    if (type == \"{\") return contCommasep(objprop, \"}\", null, maybeop);\n    if (type == \"quasi\") return pass(quasi, maybeop);\n    if (type == \"new\") return cont(maybeTarget(noComma));\n    return cont();\n  }\n  function maybeexpression(type) {\n    if (type.match(/[;\\}\\)\\],]/)) return pass();\n    return pass(expression);\n  }\n  function maybeexpressionNoComma(type) {\n    if (type.match(/[;\\}\\)\\],]/)) return pass();\n    return pass(expressionNoComma);\n  }\n\n  function maybeoperatorComma(type, value) {\n    if (type == \",\") return cont(expression);\n    return maybeoperatorNoComma(type, value, false);\n  }\n  function maybeoperatorNoComma(type, value, noComma) {\n    var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;\n    var expr = noComma == false ? expression : expressionNoComma;\n    if (type == \"=>\") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);\n    if (type == \"operator\") {\n      if (/\\+\\+|--/.test(value)) return cont(me);\n      if (value == \"?\") return cont(expression, expect(\":\"), expr);\n      return cont(expr);\n    }\n    if (type == \"quasi\") { return pass(quasi, me); }\n    if (type == \";\") return;\n    if (type == \"(\") return contCommasep(expressionNoComma, \")\", \"call\", me);\n    if (type == \".\") return cont(property, me);\n    if (type == \"[\") return cont(pushlex(\"]\"), maybeexpression, expect(\"]\"), poplex, me);\n    if (isTS && value == \"as\") { cx.marked = \"keyword\"; return cont(typeexpr, me) }\n  }\n  function quasi(type, value) {\n    if (type != \"quasi\") return pass();\n    if (value.slice(value.length - 2) != \"${\") return cont(quasi);\n    return cont(expression, continueQuasi);\n  }\n  function continueQuasi(type) {\n    if (type == \"}\") {\n      cx.marked = \"string-2\";\n      cx.state.tokenize = tokenQuasi;\n      return cont(quasi);\n    }\n  }\n  function arrowBody(type) {\n    findFatArrow(cx.stream, cx.state);\n    return pass(type == \"{\" ? statement : expression);\n  }\n  function arrowBodyNoComma(type) {\n    findFatArrow(cx.stream, cx.state);\n    return pass(type == \"{\" ? statement : expressionNoComma);\n  }\n  function maybeTarget(noComma) {\n    return function(type) {\n      if (type == \".\") return cont(noComma ? targetNoComma : target);\n      else return pass(noComma ? expressionNoComma : expression);\n    };\n  }\n  function target(_, value) {\n    if (value == \"target\") { cx.marked = \"keyword\"; return cont(maybeoperatorComma); }\n  }\n  function targetNoComma(_, value) {\n    if (value == \"target\") { cx.marked = \"keyword\"; return cont(maybeoperatorNoComma); }\n  }\n  function maybelabel(type) {\n    if (type == \":\") return cont(poplex, statement);\n    return pass(maybeoperatorComma, expect(\";\"), poplex);\n  }\n  function property(type) {\n    if (type == \"variable\") {cx.marked = \"property\"; return cont();}\n  }\n  function objprop(type, value) {\n    if (type == \"async\") {\n      cx.marked = \"property\";\n      return cont(objprop);\n    } else if (type == \"variable\" || cx.style == \"keyword\") {\n      cx.marked = \"property\";\n      if (value == \"get\" || value == \"set\") return cont(getterSetter);\n      return cont(afterprop);\n    } else if (type == \"number\" || type == \"string\") {\n      cx.marked = jsonldMode ? \"property\" : (cx.style + \" property\");\n      return cont(afterprop);\n    } else if (type == \"jsonld-keyword\") {\n      return cont(afterprop);\n    } else if (type == \"modifier\") {\n      return cont(objprop)\n    } else if (type == \"[\") {\n      return cont(expression, expect(\"]\"), afterprop);\n    } else if (type == \"spread\") {\n      return cont(expression, afterprop);\n    } else if (type == \":\") {\n      return pass(afterprop)\n    }\n  }\n  function getterSetter(type) {\n    if (type != \"variable\") return pass(afterprop);\n    cx.marked = \"property\";\n    return cont(functiondef);\n  }\n  function afterprop(type) {\n    if (type == \":\") return cont(expressionNoComma);\n    if (type == \"(\") return pass(functiondef);\n  }\n  function commasep(what, end, sep) {\n    function proceed(type, value) {\n      if (sep ? sep.indexOf(type) > -1 : type == \",\") {\n        var lex = cx.state.lexical;\n        if (lex.info == \"call\") lex.pos = (lex.pos || 0) + 1;\n        return cont(function(type, value) {\n          if (type == end || value == end) return pass()\n          return pass(what)\n        }, proceed);\n      }\n      if (type == end || value == end) return cont();\n      return cont(expect(end));\n    }\n    return function(type, value) {\n      if (type == end || value == end) return cont();\n      return pass(what, proceed);\n    };\n  }\n  function contCommasep(what, end, info) {\n    for (var i = 3; i < arguments.length; i++)\n      cx.cc.push(arguments[i]);\n    return cont(pushlex(end, info), commasep(what, end), poplex);\n  }\n  function block(type) {\n    if (type == \"}\") return cont();\n    return pass(statement, block);\n  }\n  function maybetype(type, value) {\n    if (isTS) {\n      if (type == \":\") return cont(typeexpr);\n      if (value == \"?\") return cont(maybetype);\n    }\n  }\n  function typeexpr(type) {\n    if (type == \"variable\") {cx.marked = \"type\"; return cont(afterType);}\n    if (type == \"string\" || type == \"number\" || type == \"atom\") return cont(afterType);\n    if (type == \"{\") return cont(pushlex(\"}\"), commasep(typeprop, \"}\", \",;\"), poplex, afterType)\n    if (type == \"(\") return cont(commasep(typearg, \")\"), maybeReturnType)\n  }\n  function maybeReturnType(type) {\n    if (type == \"=>\") return cont(typeexpr)\n  }\n  function typeprop(type, value) {\n    if (type == \"variable\" || cx.style == \"keyword\") {\n      cx.marked = \"property\"\n      return cont(typeprop)\n    } else if (value == \"?\") {\n      return cont(typeprop)\n    } else if (type == \":\") {\n      return cont(typeexpr)\n    } else if (type == \"[\") {\n      return cont(expression, maybetype, expect(\"]\"), typeprop)\n    }\n  }\n  function typearg(type) {\n    if (type == \"variable\") return cont(typearg)\n    else if (type == \":\") return cont(typeexpr)\n  }\n  function afterType(type, value) {\n    if (value == \"<\") return cont(pushlex(\">\"), commasep(typeexpr, \">\"), poplex, afterType)\n    if (value == \"|\" || type == \".\") return cont(typeexpr)\n    if (type == \"[\") return cont(expect(\"]\"), afterType)\n    if (value == \"extends\") return cont(typeexpr)\n  }\n  function vardef() {\n    return pass(pattern, maybetype, maybeAssign, vardefCont);\n  }\n  function pattern(type, value) {\n    if (type == \"modifier\") return cont(pattern)\n    if (type == \"variable\") { register(value); return cont(); }\n    if (type == \"spread\") return cont(pattern);\n    if (type == \"[\") return contCommasep(pattern, \"]\");\n    if (type == \"{\") return contCommasep(proppattern, \"}\");\n  }\n  function proppattern(type, value) {\n    if (type == \"variable\" && !cx.stream.match(/^\\s*:/, false)) {\n      register(value);\n      return cont(maybeAssign);\n    }\n    if (type == \"variable\") cx.marked = \"property\";\n    if (type == \"spread\") return cont(pattern);\n    if (type == \"}\") return pass();\n    return cont(expect(\":\"), pattern, maybeAssign);\n  }\n  function maybeAssign(_type, value) {\n    if (value == \"=\") return cont(expressionNoComma);\n  }\n  function vardefCont(type) {\n    if (type == \",\") return cont(vardef);\n  }\n  function maybeelse(type, value) {\n    if (type == \"keyword b\" && value == \"else\") return cont(pushlex(\"form\", \"else\"), statement, poplex);\n  }\n  function forspec(type) {\n    if (type == \"(\") return cont(pushlex(\")\"), forspec1, expect(\")\"), poplex);\n  }\n  function forspec1(type) {\n    if (type == \"var\") return cont(vardef, expect(\";\"), forspec2);\n    if (type == \";\") return cont(forspec2);\n    if (type == \"variable\") return cont(formaybeinof);\n    return pass(expression, expect(\";\"), forspec2);\n  }\n  function formaybeinof(_type, value) {\n    if (value == \"in\" || value == \"of\") { cx.marked = \"keyword\"; return cont(expression); }\n    return cont(maybeoperatorComma, forspec2);\n  }\n  function forspec2(type, value) {\n    if (type == \";\") return cont(forspec3);\n    if (value == \"in\" || value == \"of\") { cx.marked = \"keyword\"; return cont(expression); }\n    return pass(expression, expect(\";\"), forspec3);\n  }\n  function forspec3(type) {\n    if (type != \")\") cont(expression);\n  }\n  function functiondef(type, value) {\n    if (value == \"*\") {cx.marked = \"keyword\"; return cont(functiondef);}\n    if (type == \"variable\") {register(value); return cont(functiondef);}\n    if (type == \"(\") return cont(pushcontext, pushlex(\")\"), commasep(funarg, \")\"), poplex, maybetype, statement, popcontext);\n    if (isTS && value == \"<\") return cont(pushlex(\">\"), commasep(typeexpr, \">\"), poplex, functiondef)\n  }\n  function funarg(type) {\n    if (type == \"spread\") return cont(funarg);\n    return pass(pattern, maybetype, maybeAssign);\n  }\n  function classExpression(type, value) {\n    // Class expressions may have an optional name.\n    if (type == \"variable\") return className(type, value);\n    return classNameAfter(type, value);\n  }\n  function className(type, value) {\n    if (type == \"variable\") {register(value); return cont(classNameAfter);}\n  }\n  function classNameAfter(type, value) {\n    if (value == \"<\") return cont(pushlex(\">\"), commasep(typeexpr, \">\"), poplex, classNameAfter)\n    if (value == \"extends\" || value == \"implements\" || (isTS && type == \",\"))\n      return cont(isTS ? typeexpr : expression, classNameAfter);\n    if (type == \"{\") return cont(pushlex(\"}\"), classBody, poplex);\n  }\n  function classBody(type, value) {\n    if (type == \"variable\" || cx.style == \"keyword\") {\n      if ((value == \"async\" || value == \"static\" || value == \"get\" || value == \"set\" ||\n           (isTS && (value == \"public\" || value == \"private\" || value == \"protected\" || value == \"readonly\" || value == \"abstract\"))) &&\n          cx.stream.match(/^\\s+[\\w$\\xa1-\\uffff]/, false)) {\n        cx.marked = \"keyword\";\n        return cont(classBody);\n      }\n      cx.marked = \"property\";\n      return cont(isTS ? classfield : functiondef, classBody);\n    }\n    if (type == \"[\")\n      return cont(expression, expect(\"]\"), isTS ? classfield : functiondef, classBody)\n    if (value == \"*\") {\n      cx.marked = \"keyword\";\n      return cont(classBody);\n    }\n    if (type == \";\") return cont(classBody);\n    if (type == \"}\") return cont();\n    if (value == \"@\") return cont(expression, classBody)\n  }\n  function classfield(type, value) {\n    if (value == \"?\") return cont(classfield)\n    if (type == \":\") return cont(typeexpr, maybeAssign)\n    if (value == \"=\") return cont(expressionNoComma)\n    return pass(functiondef)\n  }\n  function afterExport(type, value) {\n    if (value == \"*\") { cx.marked = \"keyword\"; return cont(maybeFrom, expect(\";\")); }\n    if (value == \"default\") { cx.marked = \"keyword\"; return cont(expression, expect(\";\")); }\n    if (type == \"{\") return cont(commasep(exportField, \"}\"), maybeFrom, expect(\";\"));\n    return pass(statement);\n  }\n  function exportField(type, value) {\n    if (value == \"as\") { cx.marked = \"keyword\"; return cont(expect(\"variable\")); }\n    if (type == \"variable\") return pass(expressionNoComma, exportField);\n  }\n  function afterImport(type) {\n    if (type == \"string\") return cont();\n    return pass(importSpec, maybeMoreImports, maybeFrom);\n  }\n  function importSpec(type, value) {\n    if (type == \"{\") return contCommasep(importSpec, \"}\");\n    if (type == \"variable\") register(value);\n    if (value == \"*\") cx.marked = \"keyword\";\n    return cont(maybeAs);\n  }\n  function maybeMoreImports(type) {\n    if (type == \",\") return cont(importSpec, maybeMoreImports)\n  }\n  function maybeAs(_type, value) {\n    if (value == \"as\") { cx.marked = \"keyword\"; return cont(importSpec); }\n  }\n  function maybeFrom(_type, value) {\n    if (value == \"from\") { cx.marked = \"keyword\"; return cont(expression); }\n  }\n  function arrayLiteral(type) {\n    if (type == \"]\") return cont();\n    return pass(commasep(expressionNoComma, \"]\"));\n  }\n\n  function isContinuedStatement(state, textAfter) {\n    return state.lastType == \"operator\" || state.lastType == \",\" ||\n      isOperatorChar.test(textAfter.charAt(0)) ||\n      /[,.]/.test(textAfter.charAt(0));\n  }\n\n  // Interface\n\n  return {\n    startState: function(basecolumn) {\n      var state = {\n        tokenize: tokenBase,\n        lastType: \"sof\",\n        cc: [],\n        lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, \"block\", false),\n        localVars: parserConfig.localVars,\n        context: parserConfig.localVars && {vars: parserConfig.localVars},\n        indented: basecolumn || 0\n      };\n      if (parserConfig.globalVars && typeof parserConfig.globalVars == \"object\")\n        state.globalVars = parserConfig.globalVars;\n      return state;\n    },\n\n    token: function(stream, state) {\n      if (stream.sol()) {\n        if (!state.lexical.hasOwnProperty(\"align\"))\n          state.lexical.align = false;\n        state.indented = stream.indentation();\n        findFatArrow(stream, state);\n      }\n      if (state.tokenize != tokenComment && stream.eatSpace()) return null;\n      var style = state.tokenize(stream, state);\n      if (type == \"comment\") return style;\n      state.lastType = type == \"operator\" && (content == \"++\" || content == \"--\") ? \"incdec\" : type;\n      return parseJS(state, style, type, content, stream);\n    },\n\n    indent: function(state, textAfter) {\n      if (state.tokenize == tokenComment) return CodeMirror.Pass;\n      if (state.tokenize != tokenBase) return 0;\n      var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top\n      // Kludge to prevent 'maybelse' from blocking lexical scope pops\n      if (!/^\\s*else\\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {\n        var c = state.cc[i];\n        if (c == poplex) lexical = lexical.prev;\n        else if (c != maybeelse) break;\n      }\n      while ((lexical.type == \"stat\" || lexical.type == \"form\") &&\n             (firstChar == \"}\" || ((top = state.cc[state.cc.length - 1]) &&\n                                   (top == maybeoperatorComma || top == maybeoperatorNoComma) &&\n                                   !/^[,\\.=+\\-*:?[\\(]/.test(textAfter))))\n        lexical = lexical.prev;\n      if (statementIndent && lexical.type == \")\" && lexical.prev.type == \"stat\")\n        lexical = lexical.prev;\n      var type = lexical.type, closing = firstChar == type;\n\n      if (type == \"vardef\") return lexical.indented + (state.lastType == \"operator\" || state.lastType == \",\" ? lexical.info + 1 : 0);\n      else if (type == \"form\" && firstChar == \"{\") return lexical.indented;\n      else if (type == \"form\") return lexical.indented + indentUnit;\n      else if (type == \"stat\")\n        return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);\n      else if (lexical.info == \"switch\" && !closing && parserConfig.doubleIndentSwitch != false)\n        return lexical.indented + (/^(?:case|default)\\b/.test(textAfter) ? indentUnit : 2 * indentUnit);\n      else if (lexical.align) return lexical.column + (closing ? 0 : 1);\n      else return lexical.indented + (closing ? 0 : indentUnit);\n    },\n\n    electricInput: /^\\s*(?:case .*?:|default:|\\{|\\})$/,\n    blockCommentStart: jsonMode ? null : \"/*\",\n    blockCommentEnd: jsonMode ? null : \"*/\",\n    lineComment: jsonMode ? null : \"//\",\n    fold: \"brace\",\n    closeBrackets: \"()[]{}''\\\"\\\"``\",\n\n    helperType: jsonMode ? \"json\" : \"javascript\",\n    jsonldMode: jsonldMode,\n    jsonMode: jsonMode,\n\n    expressionAllowed: expressionAllowed,\n    skipExpression: function(state) {\n      var top = state.cc[state.cc.length - 1]\n      if (top == expression || top == expressionNoComma) state.cc.pop()\n    }\n  };\n});\n\nCodeMirror.registerHelper(\"wordChars\", \"javascript\", /[\\w$]/);\n\nCodeMirror.defineMIME(\"text/javascript\", \"javascript\");\nCodeMirror.defineMIME(\"text/ecmascript\", \"javascript\");\nCodeMirror.defineMIME(\"application/javascript\", \"javascript\");\nCodeMirror.defineMIME(\"application/x-javascript\", \"javascript\");\nCodeMirror.defineMIME(\"application/ecmascript\", \"javascript\");\nCodeMirror.defineMIME(\"application/json\", {name: \"javascript\", json: true});\nCodeMirror.defineMIME(\"application/x-json\", {name: \"javascript\", json: true});\nCodeMirror.defineMIME(\"application/ld+json\", {name: \"javascript\", jsonld: true});\nCodeMirror.defineMIME(\"text/typescript\", { name: \"javascript\", typescript: true });\nCodeMirror.defineMIME(\"application/typescript\", { name: \"javascript\", typescript: true });\n\n});\n"
  },
  {
    "path": "docs/js/gitter.js",
    "content": "((window.gitter = {}).chat = {}).options = {\n  room: 'techfort/LokiJS'\n};\n$.getScript('https://sidecar.gitter.im/dist/sidecar.v1.js', function() { });\n"
  },
  {
    "path": "docs/js/javascript_editor.js",
    "content": "/* global $ */\n\n\"use strict\";\n\nclass JavascriptEditor {\n  constructor(source) {\n    this._view = source;\n    this._parent = this._view.parent();\n\n    // Buttons in view mode.\n    this._view_controll = $('<div />');\n    let edit_btn = $('<input />', {\n      type: 'button',\n      class: 'jse-button',\n      value: 'Run this code',\n      on: {\n        click: () => {\n          this.switchToEditMode();\n        }\n      }\n    });\n    this._view_controll.append(edit_btn);\n    this._parent.prepend(this._view_controll);\n\n    // Buttons in edit mode.\n    this._edit_controll = $('<div />');\n    let run_btn = $('<input />', {\n      type: 'button',\n      class: 'jse-button',\n      value: 'Run',\n      on: {\n        click: () => {\n          this.compile();\n        }\n      }\n    });\n    let exit_btn = $('<input />', {\n      type: 'button',\n      class: 'jse-button',\n      value: 'Exit',\n      on: {\n        click: () => {\n          this.switchToViewMode();\n        }\n      }\n    });\n    this._edit_controll.append(run_btn);\n    this._edit_controll.append(exit_btn);\n    this._parent.prepend(this._edit_controll);\n\n    // Editor in edit mode.\n    this._editor = $('<div />', {\n      class: 'jse-editor',\n    });\n    this._parent.append(this._editor);\n\n    // Create code mirror.\n    this._editor_window = CodeMirror(this._editor[0], {\n      mode: \"javascript\",\n      lineNumbers: true,\n      matchBrackets: true,\n      tabSize: 2,\n      //readOnly: true,\n      extraKeys: {\n        \"Tab\": function (cm) {\n          const spaces = new Array(cm.getOption(\"indentUnit\") + 1).join(\" \");\n          cm.replaceSelection(spaces);\n        }\n      },\n      foldGutter: true,\n      gutters: [\"CodeMirror-linenumbers\", \"CodeMirror-foldgutter\"]\n    });\n\n    // Add output window\n    this._output = $('<div />', {\n      class: 'jse-output',\n    });\n    this._editor.append(this._output);\n\n    this.switchToViewMode();\n  }\n\n  switchToViewMode() {\n    this._edit_controll.hide();\n    this._view_controll.show();\n    this._editor_window.setValue(this._view.text());\n    this._editor.hide();\n    this._view.show();\n  }\n\n  switchToEditMode() {\n    this._view_controll.hide();\n    this._edit_controll.show();\n    this._view.hide();\n    this._editor.show();\n    this.compile();\n  }\n\n  compile() {\n    // Clear output window and disable buttons.\n    this._output.empty();\n    this._edit_controll.children('input').each(function () {\n      $(this).attr(\"disabled\", true);\n    });\n\n    // Hook console log and error.\n    const console_log = console.log;\n    const console_error = console.error;\n\n    let results = [];\n    console.log = function () {\n      let result = {\n        type: \"log\",\n        value: \"\"\n      };\n      for (let i = 0; i < arguments.length; i++) {\n        result.value += JavascriptEditor.stringify(arguments[i]) + \" \";\n      }\n      results.push(result);\n    };\n    console.error = function () {\n      let result = {\n        type: \"error\",\n        value: \"\"\n      };\n      for (let i = 0; i < arguments.length; i++) {\n        result.value += JavascriptEditor.stringify(arguments[i]) + \" \";\n      }\n      results.push(result);\n    };\n\n    // Run code.\n    try {\n      eval(\"(() => {\" + this._editor_window.getValue() + \"})()\");\n    } catch (e) {\n      console.error(e);\n    }\n\n    // Disable hook.\n    console.log = console_log;\n    console.error = console_error;\n\n    // Put log results into output window.\n    for (let i = 0; i < results.length; i++) {\n      let result = results[i];\n      if (result.type === 'log') {\n        this._output.append($('<span />', {\n          class: 'jse-output-log',\n          text: result.value\n        }));\n      } else {\n        this._output.append($('<span />', {\n          class: 'jse-output-error',\n          text: result.value\n        }));\n      }\n    }\n\n    // Enable buttons.\n    this._edit_controll.children('input').each(function () {\n      $(this).removeAttr(\"disabled\");\n    });\n  }\n\n  static stringify(value) {\n    const type = Object.prototype.toString.call(value);\n    if (type === \"[object Array]\") {\n      let ret = \"[\";\n      for (let i = 0; i < value.length; i++) {\n        ret += JavascriptEditor.stringify(value[i]) + \", \";\n      }\n      if (ret.length !== 1) {\n        ret = ret.slice(0, -2);\n      }\n      return ret + \"]\";\n    }\n    if (type !== \"[object Object]\") {\n      return \"\" + value;\n    }\n    return '{' + Object.keys(value).map(key => `${key}: ${JavascriptEditor.stringify(value[key])}`).join(\",\") + \"}\";\n  }\n}\n\n$('document').ready(function () {\n  // Iterate over each javascript code block.\n  $('code.javascript').each(function () {\n    let code_block = $(this);\n    let html = code_block.html();\n    // Check if code block should be runnable.\n    if (html.indexOf(\"// Runnable code\") === 0) {\n      code_block.html(html.slice(17));\n      new JavascriptEditor(code_block);\n    }\n  });\n});\n"
  },
  {
    "path": "docs/operator_packages.md",
    "content": "# LokiOperatorPackages\n\n## Overview\nLokiDB allows querying your collections with a \"mongo-like\" query object, passed to a collection.find() or query chain. The set of available \"ops\" which you can include within your query object is called a **_LokiOperatorPackage_**.  \n\nA LokiOperatorPackage represents the unindexed or \"fallback\" implementation of all supported ops.\n\n> Ranged Indexes allow the highest performance for querying collections... however they only implement a limited subset of ops ($eq, $lt, $lte, $gt, $gte, $between).\n> \n> Filtering other ops (even when a ranged index is applied) falls back to the LokiOperatorPackage registered as that collection's default.\n\nIn the previous version of LokiDB (LokiJS) there was just one 'LokiOps'.  LokiDB allows and provides multiple for you to choose from or even provide your own.\n\n## Why support multiple implementations of operators?\n\nThe primary reasons/drivers for our adoption of this approach is the following :\n\n- Have simplest and fastest minimal javascript implementations of these operators\n- Also have an implementation which is more tolerant of dirty data and mixed datatypes\n- Have an implementation which allows injecting your own comparators.\n- Future-proofing and smoothing transition between major changes (experimental -> default)\n\nAttempting to merge/blend any of the above use cases into a single implementation had negative impact on performance, so we created the ability to switch out whole implementations which only needs to be done once per find, rather than switching behavior for every document evaluation within that filtering.  Having separate selectable packages also provides future-proofing and development of experimental implementions in parallel with maintaining existing implementations.\n\n## What are the LokiOperatorPackages which LokiDB supports?\nOut of the box, LokiDB implements the following operator packages, which you can choose from (currently per-collection) :\n\n- **\"js\"** (default) : the default implementation using fastest javascript comparisons. This is an instance of the main **LokiOperatorPackage** class.\n- **\"loki\"** : implementation recommended for dirty data / mixed datatypes. This is an instance of **LokiAbstractOperator** class.\n- **_comparator_** - you need to instantiate this yourself and register that with a name within the loki constructor (example below).  These are created by instantiating the **ComparatorOperatorPackage** class, passing in a comparator to its constructor.\n\nIn practice we have one main implementation of all ops in the (default) \"LokiOperatorPackage\" class which our other implementations extend from \nand override base behavior where needed.  We may provide other implementations later, and you can provide your own implementations.  Other variants which we (or you) may provide can simply extend this class and override the ops we/you wish to have different implementations.\n\n## How would I select an operator package to use for my collection?\n\nWhen you call addCollection, such as :\n```javascript\nlet coll = db.addCollection(\"coll\", {\n  defaultLokiOperatorPackage: \"js\"\n});\n```\n\n## How can I create and register my own operator package?\n\nUsually you would extend the default LokiOperatorPackage, however any of our operator package classes can be extended from.\n\nAn example where we extend and override some of the ops with some arbitrary \"opposite logic\" might be :\n```javascript\n// extend and override with some opposite logic\nclass MyOperatorPackage extends LokiOperatorPackage {\n  $gt(a, b): boolean {\n    if (a < b) return true;\n    return false;\n  }\n\n  $lt(a, b): boolean {\n    if (a > b) return true;\n    return false;\n  }\n}\n\n// inject our new operator into global LokiOperatorPackageMap.\n// if it already exists, it will overwrite... this includes overriding native packages.\nlet db = new Loki(\"test.db\", {\n  lokiOperatorPackageMap : {\n    \"MyOperatorPackage\": new MyOperatorPackage()\n  }\n});\n```\n\nHaving registered that operator package (in the above example), and creating collections which set that to their default operator package (example above that), unindexed find() filters using the $gt and $lt op will exibit your filtering behavior (RangedIndexes have their own optimized implementation of those ops).  Any other ops specified in your query objects will use the default implementation in the class \nwhich you extended from.\n\n## How might I create an operator package based on comparators?\n\nIf you have created your own comparator or wish to use one of ours as the ultimate determination of filtering for $eq, $lt, $lte, $gt, $gte, and $between ops... how might you set up an operator package for that?\n\nHere is a quick example showing how you might implement that :\n```javascript\n// create a custom case-insensitive string comparator\nlet customComparator: ILokiComparer = (a, b) => {\n  if (typeof a === \"string\" && typeof b === \"string\") {\n    a = a.toLocaleLowerCase();\n    b = b.toLocaleLowerCase();\n  }\n\n  if (a === b) return 0;\n  if (a > b) return 1;\n  return -1;\n};\n\n// instantiate an operator package based on that comparator\nlet myComparatorOperatorPackage = new ComparatorOperatorPackage(customComparator);\n\n// inject as named operator package within the Loki constructor\nlet db = new Loki(\"test.db\", {\n  lokiOperatorPackageMap: {\n    \"MyComparatorOperatorPackage\": myComparatorOperatorPackage\n  }\n});\n```"
  },
  {
    "path": "docs/ranged_indexes.md",
    "content": "# LokiDB Ranged Indexes\n\n## Overview\nRangedIndexes in LokiDB represent an interface which higher-performance indexes which can implement so that they can be applied to properties within your LokiDB collections.\n\nIn LokiDB, we have settled on and implemented an **_AVL self balancing binary tree (which supports duplicates)_** as our highest performance index for applying to properties.  This AVL index adheres to and implements our IRangedIndex interface.\n\nWhile the \"avl\" ranged index implementation is our only implementation of IRangedIndex, having the interface as an abstraction allows the possibility of offerring alternate implemenations using other algorithms and structures in the future.  It also allows users to experiment, create, and inject their own IRangedIndex implementations in a configurable manner.\n\n## What is the performance of LokiDB's \"avl\" index implementation?\n\nThe best way to compare our AVL index implementation is to compare this with the former LokiJS's implementation of binary indices.\n\nIn that comparison, the avl index seems to be roughly 20% faster for finds() but where avl index really shines is in the \"maintenance\" costs and for inserts, updates, and removes.  Once you get over a few thousand documents, the logarithmic performance of the avl index for maintenance costs really shines comparared to linear maintenance of the binary indices array-splicing approach.\n\nSo **_the AVL index is highly scalable_** and, as such, it is not very dependent on collection size for the ops which are implemented within it ($eq, $lt, $lte, $gt, $gte, $between and somewhat for $in).\n\nOn an older Intel Core i5 laptop (in node.js), avl index performance might equate to roughly :\n- ~800K - 1M find ops/sec doing single object lookups\n- ~250K ops/sec for inserts, updates, and removes (maintenance)\n\nAnd that approximate performance does not significantly change when we scale from 40K documents to 100K documents.\n\nObviously on newer and higher performance processors this quickly scales up well above those numbers but when compared to LokiJS you would not likely be able to see those number with any collection counts above a couple thousand documents.\n\n## How can I apply an avl index to a property in my collection?\n\nEasy... a simple (javascript) example demonstrating this is the following :\n```javascript\nconst db = new Loki(\"idxtest\");\n\n// create a \"users\" collection, applying an avl index to the \"name\" property of its documents\nconst items = db.addCollection(\"users\", {\n  rangedIndexes: {\n    name: { indexTypeName: \"avl\", comparatorName: \"js\" }\n  }\n});\n```\n\n## What other indexes might I want to have an implementation for in the future?\nHonestly, most people probably will not need anything other than our AVL index implementation.\n\nThe AVL tree is known for keeping strict balancing of its property's values as documents are inserted, updated and removed.\n\nOther implementations such as the \"Red-Black\" balanced binary search tree algorithms are less strictly balanced so they may have slightly faster inserts, updates, and removes while potentially having slightly slower lookups/finds. \n\n## If I implement my own RangedIndex, how might I register and use that IRangedIndex implemenation?\n\nTypescript example (may provide javascript example in the future) :\n```typescript\n// define index implementation\nclass customRangedIndex<T> implements IRangedIndex<T> {\n  public name: string;\n  public comparator: ILokiComparer<T>;\n\n  constructor(name: string, comparator: ILokiComparer<T>) {\n    this.name = name;\n    this.comparator = comparator;\n  }\n\n  insert(id: number, val: T) {\n    if (!id || !val) throw new Error(\"\");\n    return;\n  }\n  update(id: number, val: T) {\n    if (!id || val === null) throw new Error(\"\");\n    return;\n  }\n  remove(id: number) {\n    if (!id) throw new Error(\"\");\n    return;\n  }\n  restore(tree: any) {\n    if (!tree) throw new Error(\"\");\n    return;\n  }\n  backup() {\n    return this;\n  }\n  rangeRequest(range?: IRangedIndexRequest<T>) {\n    if (range === null) {\n      // return everything\n      return <number[]> [];\n    }\n    return <number[]> [];\n  }\n  validateIndex() {\n    return true;\n  }\n}\n\n// ranged index implementations need factory function\nlet myCustomIndexFactory = (name: string, cmp: ILokiComparer<any>) => { \n  return new customRangedIndex<any>(name, cmp); \n};\n\n// register ranged index factory function with loki constructor\nlet db = new Loki(\"test.db\", {\n  rangedIndexFactoryMap: {\n    \"MyCustomRangedIndex\": myCustomIndexFactory\n  }\n});\n\n// utilize your registered ranged index within a collection\nlet items = db.addCollection<TestUserType>(\"users\", {\n  rangedIndexes: {\n    \"name\": { indexTypeName: \"MyCustomRangedIndex\", comparatorName: \"js\" }\n  }\n});\n\n\n```\n"
  },
  {
    "path": "integration/.gitignore",
    "content": "node_modules/\n\npackage-lock.json\n"
  },
  {
    "path": "integration/config/jasmine.json",
    "content": "{\n  \"spec_dir\": \"integration\",\n  \"spec_files\": [\n    \"spec/generic/*.spec.js\",\n    \"spec/node/*.spec.js\"\n  ],\n  \"helpers\": [\n    \"spec/helper/*.helper.js\",\n    \"../node_modules/jasmine-expect/index.js\"\n  ],\n  \"stopSpecOnExpectationFailure\": false,\n  \"random\": false\n}\n"
  },
  {
    "path": "integration/config/karma.amd.config.js",
    "content": "/* global process, require, module, require */\nmodule.exports = function (config) {\n  const configuration = {\n    frameworks: [\"jasmine\", \"jasmine-matchers\"],\n    browsers: [\"ChromeHeadless\"],\n    basePath: \"../\",\n    files: [\n      {pattern: \"node_modules/requirejs/require.js\", watched: false},\n      {pattern: \"spec/helper/*.helper.js\", watched: false},\n      {pattern: \"spec/generic/*.spec.js\", watched: false},\n      {pattern: \"spec/web/*.spec.js\", watched: false},\n      {pattern: \"node_modules/@lokidb/**/lokidb.*.js\", watched: false, included: false, served: true, nocache: true}\n    ],\n    reporters: [\"progress\"],\n    mime: {\n      \"text/x-typescript\": [\"js\"]\n    },\n    plugins: [\n      \"karma-chrome-launcher\",\n      \"karma-jasmine\",\n      \"karma-jasmine-matchers\",\n    ],\n  };\n\n  config.set(configuration);\n};\n"
  },
  {
    "path": "integration/config/karma.browser.config.js",
    "content": "/* global process, require, module, require */\nmodule.exports = function (config) {\n  const configuration = {\n    frameworks: [\"jasmine\", \"jasmine-matchers\"],\n    browsers: [\"ChromeHeadless\"],\n    basePath: \"../\",\n    files: [\n      {pattern: \"spec/helper/*.helper.js\", watched: false},\n      {pattern: \"spec/generic/*.spec.js\", watched: false},\n      {pattern: \"spec/web/*.spec.js\", watched: false},\n      {pattern: \"node_modules/@lokidb/**/lokidb.*.js\", watched: false, included: false, served: true, nocache: true}\n    ],\n    reporters: [\"progress\"],\n    mime: {\n      \"text/x-typescript\": [\"js\"]\n    },\n    plugins: [\n      \"karma-chrome-launcher\",\n      \"karma-jasmine\",\n      \"karma-jasmine-matchers\",\n    ],\n  };\n\n  config.set(configuration);\n};\n"
  },
  {
    "path": "integration/package.json",
    "content": "{\n  \"name\": \"@lokidb/integration\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Internal integration environment.\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/LokiJS-Forge/LokiDB.git\"\n  },\n  \"scripts\": {\n    \"postinstall\": \"../node_modules/.bin/ts-node -P ../tsconfig.json scripts/install_lokidb.ts\"\n  },\n  \"devDependencies\": {\n    \"requirejs\": \"^2.3.5\"\n  }\n}\n"
  },
  {
    "path": "integration/scripts/install_lokidb.ts",
    "content": "import * as process from \"process\";\nimport {copy, makeDir} from \"../../scripts/common\";\n\nmakeDir(\"node_modules/@lokidb\");\ncopy(\"../dist/packages-dist/*\", \"node_modules/@lokidb/\", true);\n\nprocess.exit(0);\n"
  },
  {
    "path": "integration/spec/generic/full-text-search-language-de.spec.js",
    "content": "test_integration(\"full-text-search-language-de\",\n  [\"full-text-search-language\"],\n  {\n    \"GermanAnalyzer\": (GermanAnalyzer) => {\n      const ga = new GermanAnalyzer();\n      expect(ga).toHaveMember(\"tokenizer\");\n      expect(ga).toHaveMember(\"token_filter\");\n    },\n  }\n);\n"
  },
  {
    "path": "integration/spec/generic/full-text-search-language-en.spec.js",
    "content": "test_integration(\"full-text-search-language-en\",\n  [\"full-text-search-language\"],\n  {\n    \"EnglishAnalyzer\": (EnglishAnalyzer) => {\n      const ea = new EnglishAnalyzer();\n      expect(ea).toHaveMember(\"tokenizer\");\n      expect(ea).toHaveMember(\"token_filter\");\n    },\n  }\n);\n"
  },
  {
    "path": "integration/spec/generic/full-text-search-language.spec.js",
    "content": "test_integration(\"full-text-search-language\",\n  [],\n  {\n    \"generateStopWordFilter\": (generateStopWordFilter) => {\n      expect(generateStopWordFilter).toBeFunction();\n    },\n    \"generateTrimmer\": (generateTrimmer) => {\n      expect(generateTrimmer).toBeFunction();\n    },\n    \"Among\": (Among) => {\n      const among = new Among(\"1\", 1, 1);\n      expect(among).toHaveMember(\"s\");\n      expect(among).toHaveMember(\"method\");\n    },\n    \"SnowballProgram\": (SnowballProgram) => {\n      const sp = new SnowballProgram();\n      expect(sp).toHaveMethod(\"setCurrent\");\n      expect(sp).toHaveMethod(\"getCurrent\");\n    }\n  }\n);\n"
  },
  {
    "path": "integration/spec/generic/full-text-search.spec.js",
    "content": "test_integration(\"full-text-search\",\n  [],\n  {\n    \"FullTextSearch\": (FullTextSearch) => {\n      expect(FullTextSearch.Analyzer).toBeDefined();\n      expect(FullTextSearch.Tokenizer).toBeDefined();\n      expect(FullTextSearch.TokenFilter).toBeDefined();\n\n      const fts = new FullTextSearch();\n      expect(fts).toHaveMethod(\"search\");\n      expect(fts).toHaveMethod(\"removeDocument\");\n    },\n    \"analyze\": (analyze) => {\n      expect(analyze).toBeFunction();\n    },\n    \"StandardAnalyzer\": (StandardAnalyzer) => {\n      const sa = new StandardAnalyzer();\n      expect(sa).toHaveMember(\"tokenizer\");\n      expect(sa).toHaveMember(\"token_filter\");\n    },\n    \"whitespaceTokenizer\": (whitespaceTokenizer) => {\n      expect(whitespaceTokenizer).toBeFunction();\n    },\n    \"lowercaseTokenFilter\": (lowercaseTokenFilter) => {\n      expect(lowercaseTokenFilter).toBeFunction();\n    },\n    \"uppercaseTokenFilter\": (uppercaseTokenFilter) => {\n      expect(uppercaseTokenFilter).toBeFunction();\n    }\n  }\n);\n"
  },
  {
    "path": "integration/spec/generic/loki.spec.js",
    "content": "test_integration(\"loki\",\n  [],\n  {\n    \"Loki\": (Loki) => {\n      expect(Loki.Collection).toBeDefined();\n\n      const loki = new Loki();\n      expect(loki).toHaveMethod(\"initializePersistence\");\n      expect(loki).toHaveMethod(\"addCollection\");\n    },\n    \"Collection\": (Collection) => {\n      const coll = new Collection();\n      expect(coll).toHaveMethod(\"insert\");\n      expect(coll).toHaveMethod(\"find\");\n    }\n  }\n);\n"
  },
  {
    "path": "integration/spec/generic/memory-storage.spec.js",
    "content": "test_integration(\"memory-storage\",\n  [],\n  {\n    \"MemoryStorage\": (MemoryStorage) => {\n      const ms = new MemoryStorage();\n      expect(ms).toHaveMember(\"loadDatabase\");\n      expect(ms).toHaveMember(\"saveDatabase\");\n    }\n  }\n);\n"
  },
  {
    "path": "integration/spec/generic/partitioning-adapter.spec.js",
    "content": "test_integration(\"partitioning-adapter\",\n  [],\n  {\n    \"PartitioningAdapter\": (PartitioningAdapter) => {\n      const ms = new PartitioningAdapter({});\n      expect(ms).toHaveMember(\"loadDatabase\");\n      expect(ms).toHaveMember(\"exportDatabase\");\n    }\n  }\n);\n"
  },
  {
    "path": "integration/spec/helper/integration.helper.js",
    "content": "// Determine environment.\nconst ENVIRONMENT = (() => {\n  if (typeof exports === 'object' && typeof module === 'object') {\n    return \"node\";\n  } else if (typeof define === 'function' && define.amd) {\n    return \"amd\";\n  } else if (typeof exports === 'object') {\n    /// TODO: Define integration test.\n    return null;\n  }\n  return \"browser\";\n})();\n\nif (ENVIRONMENT === \"amd\") {\n  require.config({\n    paths: {\n      \"@lokidb/fs-storage\": \"base/node_modules/@lokidb/fs-storage/lokidb.fs-storage\",\n      \"@lokidb/full-text-search\": \"base/node_modules/@lokidb/full-text-search/lokidb.full-text-search\",\n      \"@lokidb/full-text-search-language\": \"base/node_modules/@lokidb/full-text-search-language/lokidb.full-text-search-language\",\n      \"@lokidb/full-text-search-language-de\": \"base/node_modules/@lokidb/full-text-search-language-de/lokidb.full-text-search-language-de\",\n      \"@lokidb/full-text-search-language-en\": \"base/node_modules/@lokidb/full-text-search-language-en/lokidb.full-text-search-language-en\",\n      \"@lokidb/indexed-storage\": \"base/node_modules/@lokidb/indexed-storage/lokidb.indexed-storage\",\n      \"@lokidb/local-storage\": \"base/node_modules/@lokidb/local-storage/lokidb.local-storage\",\n      \"@lokidb/loki\": \"base/node_modules/@lokidb/loki/lokidb.loki\",\n      \"@lokidb/memory-storage\": \"base/node_modules/@lokidb/memory-storage/lokidb.memory-storage\",\n      \"@lokidb/partitioning-adapter\": \"base/node_modules/@lokidb/partitioning-adapter/lokidb.partitioning-adapter\",\n    }\n  });\n}\n\nfunction loadScriptByTag(src) {\n  const script = document.createElement(\"script\");\n  script.setAttribute(\"src\", src);\n  document.head.appendChild(script);\n\n  return new Promise(resolve => {\n    script.onload = resolve\n  });\n}\n\nfunction loadScript(name) {\n  if (ENVIRONMENT === \"browser\") {\n    return loadScriptByTag(`base/node_modules/@lokidb/${name}/lokidb.${name}.js`);\n  } else if (ENVIRONMENT === \"node\") {\n    return Promise.resolve(require(`@lokidb/${name}`))\n  } else if (ENVIRONMENT === \"amd\") {\n    return new Promise((resolve) => {\n      require([`@lokidb/${name}`], (rq) => {\n        resolve(rq);\n      })\n    });\n  }\n}\n\n/**\n * Loads a library with dependencies.\n * @param {string} name - the library name\n * @param {string[]} dependencies - the dependencies\n * @returns {Promise<object>}\n */\nfunction loadLibrary(name, dependencies) {\n  let promise = Promise.resolve();\n  if (ENVIRONMENT === \"browser\" || ENVIRONMENT === \"amd\") {\n    for (let dependency of dependencies) {\n      promise = promise.then(() => loadScript(dependency));\n    }\n  }\n\n  return promise\n    .then(() => loadScript(name))\n    .then((script) => {\n      if (ENVIRONMENT === \"browser\") {\n        return this[`@lokidb/${name}`];\n      } else if (ENVIRONMENT === \"node\") {\n        return script;\n      } else if (ENVIRONMENT === \"amd\") {\n        return script\n      }\n    });\n}\n\n/**\n * Creates a generic integration test for a specific library.\n * @param {string} name - the library name\n * @param {string[]} dependencies - the dependencies (needed for browser)\n * @param {object.<string, Function>} tests - the test functions for each export\n */\ntest_integration = function (name, dependencies, tests) {\n  describe(name, () => {\n    let loaded = null;\n    beforeEach(() => {\n      loaded = loadLibrary(name, dependencies);\n    });\n\n    for (let [name, test] of Object.entries(tests)) {\n      it(name, (done) => {\n        loaded.then((parent) => {\n          const target = parent[name];\n          expect(target).toBeDefined();\n          test(target);\n          done();\n        }).catch((e) => {\n          fail(e);\n          done();\n        });\n      });\n    }\n\n    it(\"coverage\", (done) => {\n      loaded.then((parent) => {\n        // Remove all defined tests from exported tag.\n        const defines = Object.keys(parent);\n        const remaining = Object.keys(tests).filter((test) => !defines.includes(test));\n\n        // All exported properties must be tested.\n        expect(remaining).toBeEmptyArray();\n        done();\n      }).catch((e) => {\n        fail(e);\n        done();\n      })\n    });\n  });\n};\n"
  },
  {
    "path": "integration/spec/node/node-storage.spec.js",
    "content": "test_integration(\"fs-storage\",\n  [],\n  {\n    \"FSStorage\": (FSStorage) => {\n      const ms = new FSStorage();\n      expect(ms).toHaveMember(\"loadDatabase\");\n      expect(ms).toHaveMember(\"saveDatabase\");\n    }\n  }\n);\n"
  },
  {
    "path": "integration/spec/web/indexed-storage.spec.js",
    "content": "test_integration(\"indexed-storage\",\n  [],\n  {\n    \"IndexedStorage\": (IndexedStorage) => {\n      const is = new IndexedStorage();\n      expect(is).toHaveMember(\"loadDatabase\");\n      expect(is).toHaveMember(\"saveDatabase\");\n      expect(is).toHaveMember(\"getDatabaseList\");\n    }\n  }\n);\n"
  },
  {
    "path": "integration/spec/web/local-storage.spec.js",
    "content": "test_integration(\"local-storage\",\n  [],\n  {\n    \"LocalStorage\": (LocalStorage) => {\n      const ls = new LocalStorage();\n      expect(ls).toHaveMember(\"loadDatabase\");\n      expect(ls).toHaveMember(\"saveDatabase\");\n    },\n  }\n);\n"
  },
  {
    "path": "mkdocs.yml",
    "content": "copyright: Copyright &copy; 2017\n\nsite_name: LokiDB\nrepo_url: https://github.com/LokiJS-Forge/LokiDB\nrepo_name: GitHub\n\nextra_css:\n  - css/codemirror/codemirror.css\n  - css/codemirror/foldgutter.css\n  - css/javascript_editor.css\n\nextra_javascript:\n  - js/gitter.js\n  - js/javascript_editor.js\n  - js/codemirror/lib/codemirror.js\n  - js/codemirror/addon/fold/brace-fold.js\n  - js/codemirror/addon/fold/foldcode.js\n  - js/codemirror/addon/fold/foldgutter.js\n  - js/codemirror/addon/edit/matchbrackets.js\n  - js/codemirror/mode/javascript/javascript.js\n\n\ntheme: readthedocs\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@lokidb/lokidb-src\",\n  \"version\": \"2.1.0\",\n  \"description\": \"Fast document oriented javascript in-memory database\",\n  \"author\": \"Various authors\",\n  \"license\": \"(MIT OR Apache-2.0)\",\n  \"scripts\": {\n    \"lint\": \"tslint -p config/tsconfig.tslint.json -c config/tslint.json\",\n    \"lint:fix\": \"npm run lint -- --fix\",\n    \"test\": \"npm run test:web && npm run test:node && npm run coverage\",\n    \"test:web\": \"karma start config/karma.config.js --single-run\",\n    \"test:web:watch\": \"karma start config/karma.config.js\",\n    \"test:node\": \"nyc --nycrc-path config/nycrc.node.json jasmine --config=\\\"config/jasmine.json\\\"\",\n    \"test:integration\": \"npm run test:integration:browser && npm run test:integration:amd && npm run test:integration:node\",\n    \"test:integration:browser\": \"karma start integration/config/karma.browser.config.js --single-run\",\n    \"test:integration:amd\": \"karma start integration/config/karma.amd.config.js --single-run\",\n    \"test:integration:node\": \"jasmine --config=\\\"integration/config/jasmine.json\\\"\",\n    \"coverage\": \"istanbul report json lcov && nyc report --nycrc-path config/nycrc.json\",\n    \"docs\": \"typedoc --tsconfig tsconfig.json packages/\",\n    \"build\": \"ts-node scripts/build.ts\",\n    \"deploy\": \"ts-node scripts/deploy.ts\",\n    \"benchmark\": \"node --expose-gc benchmark/benchmark\",\n    \"benchmark:indexes\": \"node --expose-gc benchmark/benchmark_indexes\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/LokiJS-Forge/LokiDB.git\"\n  },\n  \"keywords\": [\n    \"javascript\",\n    \"document-oriented\",\n    \"mmdb\",\n    \"database\",\n    \"json\",\n    \"lokidb\",\n    \"in-memory\"\n  ],\n  \"bugs\": {\n    \"url\": \"https://github.com/LokiJS-Forge/LokiDB/issues\"\n  },\n  \"homepage\": \"https://LokiJS-Forge.github.io/LokiDB\",\n  \"devDependencies\": {\n    \"@types/elasticsearch\": \"^5.0.24\",\n    \"@types/jasmine\": \"^2.8.8\",\n    \"@types/node\": \"^8.10.19\",\n    \"cash\": \"^0.8.0\",\n    \"codecov\": \"^3.0.2\",\n    \"conventional-changelog\": \"^2.0.1\",\n    \"elasticsearch\": \"^13.3.1\",\n    \"istanbul\": \"^0.4.5\",\n    \"istanbul-instrumenter-loader\": \"^3.0.1\",\n    \"jasmine\": \"^3.1.0\",\n    \"jasmine-expect\": \"^3.8.3\",\n    \"karma\": \"^2.0.2\",\n    \"karma-chrome-launcher\": \"^2.2.0\",\n    \"karma-coverage-istanbul-reporter\": \"^2.0.1\",\n    \"karma-jasmine\": \"^1.1.2\",\n    \"karma-jasmine-matchers\": \"^3.7.0\",\n    \"karma-webpack\": \"^3.0.0\",\n    \"nyc\": \"^12.0.2\",\n    \"source-map-loader\": \"^0.2.3\",\n    \"ts-loader\": \"^4.4.1\",\n    \"ts-node\": \"^6.1.0\",\n    \"tslint\": \"^5.10.0\",\n    \"tslint-eslint-rules\": \"^4.1.1\",\n    \"tslint-loader\": \"^3.6.0\",\n    \"typedoc\": \"^0.11.1\",\n    \"typescript\": \"2.8.3\",\n    \"uglify-es\": \"^3.3.10\",\n    \"vrsource-tslint-rules\": \"^5.8.2\",\n    \"webpack\": \"^4.12.0\",\n    \"webpack-cli\": \"^3.0.3\"\n  }\n}\n"
  },
  {
    "path": "packages/common/plugin.ts",
    "content": "function getGlobal(): any {\n  let glob;\n  (function (global) {\n    glob = global;\n  })(global !== undefined && global || this);\n  return glob;\n}\n\n\nfunction create(): void {\n  const global = getGlobal();\n  const sym = Symbol.for(\"LOKI\") as any;\n  if (global[sym] === undefined) {\n    global[sym] = {\n    };\n  }\n  return global[sym];\n}\n\n/**\n * @hidden\n */\nexport const PLUGINS = create();\n"
  },
  {
    "path": "packages/common/types.ts",
    "content": "/**\n * @hidden\n */\nimport { Loki } from \"../loki/src/loki\";\n\nexport interface StorageAdapter {\n  loadDatabase(dbname: string): Promise<any>;\n\n  saveDatabase?(dbname: string, serialization: string): Promise<void>;\n\n  deleteDatabase?(dbname: string): Promise<void>;\n\n  mode?: string;\n\n  exportDatabase?(dbname: string, dbref: Loki): Promise<void>;\n}\n\nexport type Doc<T extends object = object> = T & {\n  $loki: number;\n  meta?: {\n    created: number;\n    revision: number;\n    version: number,\n    updated?: number;\n  };\n};\n\nexport interface Dict<T> {\n  [index: string]: T;\n\n  [index: number]: T;\n}\n\n\n\n\n"
  },
  {
    "path": "packages/fs-storage/package.json",
    "content": "{\n  \"name\": \"@lokidb/fs-storage\",\n  \"description\": \"A persistence adapter which persists to node fs module storage.\",\n  \"author\": \"Various authors\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/LokiJS-Forge/LokiDB.git\"\n  },\n  \"main\": \"lokidb.fs-storage.js\",\n  \"types\": \"./types/fs-storage/src/index.d.ts\",\n  \"dependencies\": {\n    \"@lokidb/loki\": \"0\"\n  }\n}\n"
  },
  {
    "path": "packages/fs-storage/spec/node/fs_storage.spec.ts",
    "content": "/* global describe, it, expect */\nimport { Loki } from \"../../../loki/src/loki\";\nimport { FSStorage } from \"../../src/fs_storage\";\n\ndescribe(\"testing fs storage\", function () {\n\n  interface Name {\n    name: string;\n  }\n\n  beforeAll(() => {\n    FSStorage.register();\n  });\n\n  afterAll(() => {\n    FSStorage.deregister();\n  });\n\n  it(\"LokiFSStorage\", function (done) {\n    const db = new Loki(\"myTestApp\");\n    const adapter = {adapter: new FSStorage()};\n    db.initializePersistence(adapter)\n      .then(() => {\n        db.addCollection<Name>(\"myColl\").insert({name: \"Hello World\"});\n        return db.saveDatabase();\n      })\n      .then(() => {\n        const db2 = new Loki(\"myTestApp\");\n        return db2.initializePersistence()\n          .then(() => {\n            return db2.loadDatabase();\n          }).then(() => {\n            expect(db2.getCollection<Name>(\"myColl\").find()[0].name).toEqual(\"Hello World\");\n          });\n      })\n      .then(() => {\n        const db2 = new Loki(\"myTestApp\");\n        return db2.initializePersistence({persistenceMethod: \"fs-storage\"})\n          .then(() => {\n            return db2.loadDatabase();\n          }).then(() => {\n            expect(db2.getCollection<Name>(\"myColl\").find()[0].name).toEqual(\"Hello World\");\n          });\n      })\n      .then(() => {\n        const db3 = new Loki(\"other\");\n        return db3.initializePersistence()\n          .then(() => {\n            return db3.loadDatabase();\n          }).then(() => {\n            expect(false).toEqual(true);\n          }, () => {\n            expect(true).toEqual(true);\n          });\n      })\n      .then(() => {\n        return db.deleteDatabase();\n      })\n      .then(() => {\n        return db.loadDatabase()\n          .then(() => {\n            expect(db.getCollection<Name>(\"myColl\").find()[0].name).toEqual(\"Hello World\");\n            expect(false).toEqual(true);\n            done();\n          }, () => {\n            expect(true).toEqual(true);\n            done();\n          });\n      });\n  });\n\n  it(\"auto save and auto load\", function (done) {\n    const db = new Loki(\"myTestApp2\");\n\n    db.initializePersistence({autosave: true, autoload: true})\n      .then(() => {\n        db.addCollection<Name>(\"myColl\").insert({name: \"Hello World\"});\n        return db.close();\n      })\n      .then(() => {\n        const db2 = new Loki(\"myTestApp2\");\n        return db2.initializePersistence({autosave: true, autoload: true})\n          .then(() => {\n            expect(db2.getCollection<Name>(\"myColl\").find()[0].name).toEqual(\"Hello World\");\n          });\n      })\n      .catch(e => {\n        fail(e);\n      })\n      .then(() => {\n        done();\n      });\n  });\n});\n"
  },
  {
    "path": "packages/fs-storage/src/fs_storage.ts",
    "content": "import { PLUGINS } from \"../../common/plugin\";\nimport { StorageAdapter } from \"../../common/types\";\nimport * as fs from \"fs\";\n\n/**\n * A loki persistence adapter which persists using node fs module.\n */\nexport class FSStorage implements StorageAdapter {\n  /**\n   * Registers the fs storage as plugin.\n   */\n  static register(): void {\n    PLUGINS[\"FSStorage\"] = FSStorage;\n  }\n\n  /**\n   * Deregisters the fs storage as plugin.\n   */\n  static deregister(): void {\n    delete PLUGINS[\"FSStorage\"];\n  }\n\n  /**\n   * Load data from file, will throw an error if the file does not exist\n   * @param {string} dbname - the filename of the database to load\n   * @returns {Promise} a Promise that resolves after the database was loaded\n   */\n  loadDatabase(dbname: string): Promise<any> {\n    return new Promise((resolve, reject) => {\n      fs.stat(dbname, (err, stats) => {\n        if (!err && stats.isFile()) {\n          fs.readFile(dbname, {\n            encoding: \"utf8\"\n          }, function readFileCallback(err, data) {\n            if (err) {\n              reject(err);\n            } else {\n              resolve(data);\n            }\n          });\n        } else {\n          reject(null);\n        }\n      });\n    });\n  }\n\n  /**\n   * Save data to file, will throw an error if the file can't be saved\n   * might want to expand this to avoid dataloss on partial save\n   * @param {string} dbname - the filename of the database to load\n   * @returns {Promise} a Promise that resolves after the database was persisted\n   */\n  saveDatabase(dbname: string, dbstring: string): Promise<void> {\n    const tmpdbname = dbname + \"~\";\n    return new Promise((resolve, reject) => {\n      fs.writeFile(tmpdbname, dbstring, (err) => {\n        if (err) {\n          reject(err);\n        } else {\n          fs.rename(tmpdbname, dbname, (err) => {\n            if (err) {\n              reject(err);\n            } else {\n              resolve();\n            }\n          });\n        }\n      });\n    }) as any as Promise<void>;\n  }\n\n  /**\n   * Delete the database file, will throw an error if the\n   * file can't be deleted\n   * @param {string} dbname - the filename of the database to delete\n   * @returns {Promise} a Promise that resolves after the database was deleted\n   */\n  deleteDatabase(dbname: string): Promise<void> {\n    return new Promise((resolve, reject) => {\n      fs.unlink(dbname, function deleteDatabaseCallback(err) {\n        if (err) {\n          reject(err);\n        } else {\n          resolve();\n        }\n      });\n    });\n  }\n}\n"
  },
  {
    "path": "packages/fs-storage/src/index.ts",
    "content": "import { FSStorage } from \"./fs_storage\";\n\nexport {FSStorage};\nexport default FSStorage;\n"
  },
  {
    "path": "packages/fs-storage/webpack.config.js",
    "content": "/* global __dirname, module, require */\nconst path = require(\"path\");\nconst webpackConigCreator = require('../../config/webpack-config-creator.js');\n\nmodule.exports = webpackConigCreator({\n  entry: path.join(__dirname, \"src\", \"fs_storage.ts\"),\n  filename: \"lokidb.fs-storage.js\",\n  library: \"@lokidb/fs-storage\",\n  externals: {\n    \"../../loki/src/loki\": \"@lokidb/loki\",\n    \"fs\": \"fs\"\n  },\n});\n"
  },
  {
    "path": "packages/full-text-search/package.json",
    "content": "{\n  \"name\": \"@lokidb/full-text-search\",\n  \"description\": \"A full-text search engine.\",\n  \"author\": \"Various authors\",\n  \"license\": \"Apache-2.0\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/LokiJS-Forge/LokiDB.git\"\n  },\n  \"main\": \"lokidb.full-text-search.js\",\n  \"types\": \"./types/full-text-search/src/index.d.ts\",\n  \"optionalDependencies\": {\n    \"@lokidb/loki\": \"0\"\n  }\n}\n"
  },
  {
    "path": "packages/full-text-search/spec/generic/analyzer/character_filter.spec.ts",
    "content": "/* global describe, it, expect */\n\ndescribe(\"character filter\", () => {\n\n});\n"
  },
  {
    "path": "packages/full-text-search/spec/generic/analyzer/token_filter.spec.ts",
    "content": "/* global describe, it, expect */\nimport { lowercaseTokenFilter, uppercaseTokenFilter } from \"../../../src/analyzer/token_filter\";\n\ndescribe(\"token filter\", () => {\n\n  it(\"lowercaseTokenFilter\", () => {\n    expect(lowercaseTokenFilter(\"\")).toEqual(\"\");\n    expect(lowercaseTokenFilter(\"Abc\")).toEqual(\"abc\");\n    expect(lowercaseTokenFilter(\"c'eEf.\")).toEqual(\"c'eef.\");\n    expect(lowercaseTokenFilter(\"def\")).toEqual(\"def\");\n    expect(lowercaseTokenFilter(\"12.3\")).toEqual(\"12.3\");\n  });\n\n  it(\"uppercaseTokenFilter\", () => {\n    expect(uppercaseTokenFilter(\"\")).toEqual(\"\");\n    expect(uppercaseTokenFilter(\"Abc\")).toEqual(\"ABC\");\n    expect(uppercaseTokenFilter(\"c'eEf.\")).toEqual(\"C'EEF.\");\n    expect(uppercaseTokenFilter(\"DEF\")).toEqual(\"DEF\");\n    expect(uppercaseTokenFilter(\"12.3\")).toEqual(\"12.3\");\n  });\n});\n"
  },
  {
    "path": "packages/full-text-search/spec/generic/analyzer/tokenizer.spec.ts",
    "content": "/* global describe, it, expect */\nimport { whitespaceTokenizer } from \"../../../src/analyzer/tokenizer\";\n\ndescribe(\"tokenizer\", () => {\n\n  it(\"whitespaceTokenizer\", () => {\n    expect(whitespaceTokenizer(\"\")).toEqual([\"\"]);\n    expect(whitespaceTokenizer(\"abc d'ef 123.\")).toEqual([\"abc\", \"d'ef\", \"123.\"]);\n  });\n});\n"
  },
  {
    "path": "packages/full-text-search/spec/generic/full_text_search.spec.ts",
    "content": "/* global describe, ddescribe, it, expect */\nimport { Loki } from \"../../../loki/src/loki\";\nimport { Query } from \"../../src/query_types\";\nimport { MemoryStorage } from \"../../../memory-storage/src/memory_storage\";\nimport { Collection } from \"../../../loki/src/collection\";\nimport { FullTextSearch } from \"../../src/full_text_search\";\nimport { Doc } from \"../../../common/types\";\nimport { Analyzer } from \"../../src/analyzer/analyzer\";\n\ndescribe(\"full-text search standalone\", () => {\n\n  const doc1 = {name: \"quark\", ref: \"#quark\"};\n  const doc2 = {name: \"quarrk\", ref: \"#quarrk\"};\n  const doc3 = {name: \"quak\", ref: \"#quak\"};\n  const doc4 = {name: \"quask\"};\n\n  let fts: FullTextSearch;\n\n  beforeEach(() => {\n    fts = new FullTextSearch([{field: \"name\"}], \"ref\");\n    fts.addDocument(doc1);\n    fts.addDocument(doc2);\n    fts.addDocument(doc3);\n    fts.addDocument(doc4, \"#quask\");\n  });\n\n  it(\"usage\", () => {\n    const query: Query = {query: {type: \"fuzzy\", field: \"name\", value: \"quak\", fuzziness: 1}};\n    const result = fts.search(query);\n    expect(Object.keys(result).length).toBe(3);\n    expect(result).toHaveMember(\"#quark\");\n    expect(result).toHaveMember(\"#quak\");\n    expect(result).toHaveMember(\"#quask\");\n  });\n\n  it(\"insert\", () => {\n    fts.addDocument({name: \"quakk\"}, \"#quakk\");\n\n    const query: Query = {query: {type: \"fuzzy\", field: \"name\", value: \"quak\", fuzziness: 1}};\n    const result = fts.search(query);\n    expect(Object.keys(result).length).toBe(4);\n    expect(result).toHaveMember(\"#quark\");\n    expect(result).toHaveMember(\"#quak\");\n    expect(result).toHaveMember(\"#quask\");\n    expect(result).toHaveMember(\"#quakk\");\n  });\n\n  it(\"remove\", () => {\n    fts.removeDocument(doc1);\n    fts.removeDocument(doc4, \"#quask\");\n\n    const query: Query = {query: {type: \"fuzzy\", field: \"name\", value: \"quak\", fuzziness: 1}};\n    const result = fts.search(query);\n    expect(Object.keys(result).length).toBe(1);\n    expect(result).toHaveMember(\"#quak\");\n  });\n\n  it(\"update\", () => {\n    fts.updateDocument({name: \"qualk\"}, \"#quarrk\");\n\n    const query: Query = {query: {type: \"fuzzy\", field: \"name\", value: \"quak\", fuzziness: 1}};\n    const result = fts.search(query);\n    expect(Object.keys(result).length).toBe(4);\n  });\n});\n\ndescribe(\"full-text search with Loki\", () => {\n  FullTextSearch.register();\n\n  interface User {\n    name: string;\n    id: number;\n  }\n\n  let db: Loki;\n  let coll: Collection<User>;\n\n  beforeEach(() => {\n    db = new Loki(\"MyDB\");\n    coll = db.addCollection<User>(\"User\", {fullTextSearch: [{field: \"name\"}]});\n\n    coll.insert([\n      {name: \"quark\", id: 1},\n      {name: \"quarrk\", id: 2},\n      {name: \"quak\", id: 3},\n      {name: \"quask\", id: 4},\n    ]);\n  });\n\n  it(\"usage\", () => {\n    let query: Query = {query: {type: \"fuzzy\", field: \"name\", value: \"quak\", fuzziness: 1}};\n    expect(coll.find({\"$fts\": query}).length).toBe(3);\n  });\n\n  it(\"chained\", () => {\n    let query: Query = {query: {type: \"fuzzy\", field: \"name\", value: \"quak\", fuzziness: 1}};\n    expect(\n      coll.find({\"$fts\": query})).not.toEqual(\n      coll.find({\"id\": {\"$in\": [1, 2, 3]}}));\n\n    expect(\n      coll\n        .chain()\n        .find({\"id\": {\"$in\": [1, 2, 3]}})\n        .find({\"$fts\": query})\n        .data().length)\n      .toBe(2);\n\n    expect(\n      coll\n        .chain()\n        .find({\"$fts\": query})\n        .find({\"id\": {\"$in\": [1, 2, 3]}})\n        .data().length)\n      .toBe(2);\n  });\n\n  it(\"nested\", () => {\n    const coll2 = db.addCollection<{ user: { name: string, id: number } }, { \"user.name\": string, \"user.id\": number }>(\n      \"coll\", {\n        nestedProperties: [\"user.name\", \"user.id\"],\n        fullTextSearch: [{field: \"user.name\"}]\n      });\n    for (let i of coll.find()) {\n      coll2.insert({user: i});\n    }\n\n    let query: Query = {query: {type: \"fuzzy\", field: \"user.name\", value: \"quak\", fuzziness: 1}};\n    expect(coll2.find({\"$fts\": query}).length).toBe(3);\n\n    expect(\n      coll2.find({\"$fts\": query})).not.toEqual(\n      coll2.find({\"user.id\": {\"$in\": [1, 2, 3]}}));\n\n    expect(\n      coll2\n        .chain()\n        .find({\"user.id\": {\"$in\": [1, 2, 3]}})\n        .find({\"$fts\": query})\n        .data().length)\n      .toBe(2);\n\n    expect(\n      coll2\n        .chain()\n        .find({\"$fts\": query})\n        .find({\"user.id\": {\"$in\": [1, 2, 3]}})\n        .data().length)\n      .toBe(2);\n  });\n\n  it(\"update\", () => {\n    coll.updateWhere((user: User) => {\n      return user.name === \"quak\";\n    }, (user: Doc<User>) => {\n      user.name = \"quaaak\";\n      return user;\n    });\n\n    let query: Query = {query: {type: \"fuzzy\", field: \"name\", value: \"quak\", fuzziness: 1}};\n    expect(coll.find({\"$fts\": query}).length).toBe(2);\n  });\n\n  it(\"remove\", () => {\n    coll.removeWhere((user: User) => {\n      return user.name === \"quak\";\n    });\n\n    let query: Query = {query: {type: \"fuzzy\", field: \"name\", value: \"quak\", fuzziness: 1}};\n    expect(coll.find({\"$fts\": query}).length).toBe(2);\n  });\n\n  it(\"clear\", () => {\n    coll.clear();\n\n    coll.insert([\n      {name: \"abcd\", id: 1},\n      {name: \"abcde\", id: 2},\n      {name: \"abcdef\", id: 3},\n      {name: \"abcdefg\", id: 4},\n    ]);\n\n    let query: Query = {query: {type: \"fuzzy\", field: \"name\", value: \"quak\", fuzziness: 1}};\n    expect(coll.find({\"$fts\": query}).length).toBe(0);\n\n    query = {query: {type: \"fuzzy\", field: \"name\", value: \"abcde\", fuzziness: 1}};\n    expect(coll.find({\"$fts\": query}).length).toBe(3);\n  });\n\n  it(\"sort\", () => {\n    let query: Query = {query: {type: \"fuzzy\", field: \"name\", value: \"quak\", fuzziness: 2}};\n\n    expect(coll.chain().sortByScoring).toThrowAnyError();\n    expect(coll.chain().getScoring).toThrowAnyError();\n\n    let res = coll.chain().find({\"$fts\": query});\n    expect(res.data().length).toBe(4);\n\n    const unsorted = res.data();\n    const sorted_desc = res.sortByScoring().data();\n    const sorted_asc = res.sortByScoring(true).data();\n\n    expect(res.getScoring()).toBeArrayOfSize(unsorted.length);\n\n    expect(unsorted.length).toBe(sorted_desc.length);\n    expect(sorted_desc.length).toBe(sorted_asc.length);\n    expect(unsorted).not.toEqual(sorted_desc);\n    expect(unsorted).not.toEqual(sorted_asc);\n\n    expect(sorted_desc[0].name).toBe(\"quak\");\n    expect(sorted_desc[3].name).toBe(\"quarrk\");\n\n    expect(sorted_asc[0].name).toBe(\"quarrk\");\n    expect(sorted_asc[3].name).toBe(\"quak\");\n\n    // With dynamic view.\n    const dv = coll.addDynamicView(\"MyScoringView\");\n    expect(dv.data()).toEqual(unsorted);\n\n    expect(dv.applySortByScoring).toThrowAnyError();\n    dv.applyFind({\"$fts\": query});\n\n    expect(dv.getScoring()).toBeArrayOfSize(unsorted.length);\n\n    expect(dv.applySortByScoring().data()).toEqual(sorted_desc);\n    expect(dv.applySortByScoring(true).data()).toEqual(sorted_asc);\n  });\n\n  it(\"explain\", () => {\n    let query: Query = {query: {type: \"fuzzy\", field: \"name\", value: \"quak\", fuzziness: 2}, explain: true};\n    let res = coll.chain().find({\"$fts\": query});\n    expect(res.data().length).toBe(4);\n    expect(res.getScoring()[0].explanation).toBeArrayOfObjects();\n  });\n\n  it(\"from/to json\", () => {\n    const fts = coll[\"_fullTextSearch\"];\n    const fts2 = FullTextSearch.fromJSONObject(JSON.parse(JSON.stringify(fts)));\n    expect(JSON.stringify(fts)).toEqual(JSON.stringify(fts2));\n  });\n\n  it(\"save/load\", (done) => {\n    const adapter = {adapter: new MemoryStorage()};\n    db.initializePersistence(adapter)\n      .then(() => {\n        return db.saveDatabase();\n      })\n      .then(() => {\n        const db2 = new Loki(\"MyDB\");\n        return db2.initializePersistence(adapter)\n          .then(() => {\n            return db2.loadDatabase();\n          }).then(() => {\n            const coll2 = db2.getCollection<User>(\"User\");\n            let query: Query = {query: {type: \"fuzzy\", field: \"name\", value: \"quak\", fuzziness: 1}};\n            expect(coll2.find({\"$fts\": query}).length).toBe(3);\n            done();\n          });\n      })\n      .catch(() => {\n        expect(true).toBe(false);\n        done();\n      });\n  });\n\n  it(\"save/load with analyzer\", (done) => {\n    const adapter = {adapter: new MemoryStorage()};\n    db = new Loki(\"MyDB\");\n    const myAnalyzer: Analyzer = {\n      tokenizer: str => (str.split(\"b\"))\n    };\n    coll = db.addCollection<User>(\"User\", {fullTextSearch: [{field: \"name\", analyzer: myAnalyzer}]});\n    coll.insert([\n      {name: \"abc\", id: 1},\n      {name: \"defba\", id: 2},\n    ]);\n\n    db.initializePersistence(adapter)\n      .then(() => {\n        return db.saveDatabase();\n      })\n      .then(() => {\n        const db2 = new Loki(\"MyDB\");\n        return db2.initializePersistence(adapter)\n          .then(() => {\n            return db2.loadDatabase({fullTextSearch: {name: myAnalyzer}});\n          }).then(() => {\n            const coll2 = db2.getCollection<User>(\"User\");\n\n            const query: Query = {query: {type: \"term\", field: \"name\", value: \"a\"}};\n            expect(coll2.find({\"$fts\": query}).length).toBe(2);\n\n            // Analyzer still works.\n            coll2.insert({name: \"abxyz\", id: 3});\n            expect(coll2.find({\"$fts\": query}).length).toBe(3);\n            done();\n          });\n      })\n      .catch(() => {\n        expect(true).toBe(false);\n        done();\n      });\n  });\n});\n"
  },
  {
    "path": "packages/full-text-search/spec/generic/inverted_index.spec.ts",
    "content": "/* global describe, it, expect */\nimport { InvertedIndex, toCodePoints } from \"../../src/inverted_index\";\n\ndescribe(\"inverted index\", () => {\n\n  let field1 = \"Hello world, how are you today?!\";\n  let field2 = \"Well done world...\";\n  let field3 = \"I am good, and you?\";\n  let field4 = \"Now again inside today! You...\";\n  let field5 = \"Good bye NO! for all worlds...\";\n\n  it(\"get\", () => {\n    let ii = new InvertedIndex();\n    expect(ii.docCount).toBeNumber();\n    expect(ii.docStore instanceof Map).toBeTrue();\n    expect(ii.totalFieldLength).toBeNumber();\n    expect(ii.analyzer).toBeObject();\n    expect(ii.root instanceof Map).toBeTrue();\n  });\n\n  it(\"insert\", () => {\n    let ii = new InvertedIndex();\n    ii.insert(field1, 1);\n    expect(() => ii.insert(field2, 1)).toThrowErrorOfType(\"Error\");\n    ii.insert(field3, 2);\n    ii.insert(field4, 3);\n    ii.insert(field4, 4);\n    ii.insert(field5, 5);\n  });\n\n  it(\"remove\", () => {\n    let ii = new InvertedIndex();\n    ii.insert(field1, 1);\n    ii.insert(field2, 2);\n    ii.remove(1);\n    ii.remove(2);\n    ii.remove(15);\n  });\n\n  it(\"insert and remove empty does not change document count\", () => {\n    let ii = new InvertedIndex();\n    ii.insert(field1, 1);\n    expect(ii.docCount).toEqual(1);\n    ii.insert(\"\", 2);\n    expect(ii.docCount).toEqual(1);\n    ii.remove(2);\n    expect(ii.docCount).toEqual(1);\n    ii.remove(1);\n    expect(ii.docCount).toEqual(0);\n  });\n\n  it(\"getTermIndex\", () => {\n    let ii = new InvertedIndex();\n    ii.insert(field1, 1);\n    ii.insert(field2, 2);\n    ii.insert(field3, 3);\n    ii.insert(field4, 4);\n\n    expect(InvertedIndex.getTermIndex(toCodePoints(\"you\"), ii.root)).not.toBe(null);\n    expect(InvertedIndex.getTermIndex(toCodePoints(\"ayou\"), ii.root, 1)).not.toBe(null);\n    expect(InvertedIndex.getTermIndex(toCodePoints(\"you\"), ii.root, 10)).toBe(null);\n    expect(InvertedIndex.getTermIndex(toCodePoints(\"xyz1234\"), ii.root)).toBe(null);\n  });\n\n\n  it(\"extendTermIndex\", () => {\n    let ii = new InvertedIndex();\n    ii.insert(field1, 1);\n    expect(InvertedIndex.extendTermIndex(ii.root).length).toEqual(6);\n  });\n\n  it(\"serialize\", () => {\n    let ii1 = new InvertedIndex();\n    ii1.insert(field1, 1);\n    ii1.insert(field2, 2);\n    ii1.insert(field3, 3);\n\n    let ii2 = new InvertedIndex();\n    ii2.insert(field1, 1);\n    ii2.insert(field2, 2);\n    ii2.insert(field3, 3);\n    ii2.insert(field4, 4);\n\n    let ii3 = InvertedIndex.fromJSONObject(JSON.parse(JSON.stringify(ii2)));\n\n    expect(JSON.stringify(ii3)).toEqual(JSON.stringify(ii2));\n    ii2.remove(4);\n    ii3.remove(4);\n    expect(JSON.stringify(ii2)).toEqual(JSON.stringify(ii1));\n    expect(JSON.stringify(ii3)).toEqual(JSON.stringify(ii1));\n    expect(JSON.stringify(ii3)).toEqual(JSON.stringify(ii2));\n\n    ii2.remove(1);\n    ii3.remove(2);\n    expect(JSON.stringify(ii2)).not.toEqual(JSON.stringify(ii1));\n    expect(JSON.stringify(ii3)).not.toEqual(JSON.stringify(ii1));\n    expect(JSON.stringify(ii3)).not.toEqual(JSON.stringify(ii2));\n\n    ii1.remove(1);\n    ii1.remove(2);\n    ii2.remove(2);\n    ii3.remove(1);\n    expect(JSON.stringify(ii2)).toEqual(JSON.stringify(ii1));\n    expect(JSON.stringify(ii3)).toEqual(JSON.stringify(ii1));\n    expect(JSON.stringify(ii3)).toEqual(JSON.stringify(ii2));\n\n    ii2 = InvertedIndex.fromJSONObject(JSON.parse(JSON.stringify(ii1)));\n    expect(JSON.stringify(ii2)).toEqual(JSON.stringify(ii1));\n\n    ii1.insert(field5, 5);\n    expect(JSON.stringify(ii2)).not.toEqual(JSON.stringify(ii1));\n    expect(JSON.stringify(ii3)).not.toEqual(JSON.stringify(ii1));\n\n    ii1.remove(5);\n    expect(JSON.stringify(ii2)).toEqual(JSON.stringify(ii1));\n    expect(JSON.stringify(ii3)).toEqual(JSON.stringify(ii1));\n    expect(JSON.stringify(ii3)).toEqual(JSON.stringify(ii2));\n\n    // Check if still can be used\n    ii3.insert(field5, 6);\n    ii3.remove(6);\n  });\n\n  it(\"serialize without store\", () => {\n    let ii1 = new InvertedIndex({store: false});\n    ii1.insert(field1, 1);\n    ii1.insert(field2, 2);\n    ii1.insert(field3, 3);\n\n    let ii2 = InvertedIndex.fromJSONObject(JSON.parse(JSON.stringify(ii1)));\n    ii2.insert(field1, 1);\n    ii2.insert(field2, 2);\n    ii2.insert(field3, 3);\n\n    expect(JSON.stringify(ii1)).toEqual(JSON.stringify(ii2));\n    ii1[\"_store\"] = true;\n    ii2[\"_store\"] = true;\n    expect(JSON.stringify(ii1)).toEqual(JSON.stringify(ii2));\n\n    ii2.insert(field4, 4);\n    expect(JSON.stringify(ii1)).not.toEqual(JSON.stringify(ii2));\n  });\n\n  it(\"serialize without optimization\", () => {\n    let ii1 = new InvertedIndex({optimizeChanges: false});\n    ii1.insert(field1, 1);\n    ii1.insert(field2, 2);\n    ii1.insert(field3, 3);\n\n    let ii2 = new InvertedIndex({optimizeChanges: false});\n    ii2.insert(field1, 1);\n    ii2.insert(field2, 2);\n    ii2.insert(field3, 3);\n    ii2.insert(field4, 4);\n\n    let ii3 = InvertedIndex.fromJSONObject(JSON.parse(JSON.stringify(ii2)));\n    expect(JSON.stringify(ii3)).toEqual(JSON.stringify(ii2));\n    ii2.remove(4);\n    ii3.remove(4);\n    expect(JSON.stringify(ii2)).toEqual(JSON.stringify(ii1));\n    expect(JSON.stringify(ii3)).toEqual(JSON.stringify(ii1));\n    expect(JSON.stringify(ii3)).toEqual(JSON.stringify(ii2));\n\n    ii2.remove(1);\n    ii3.remove(2);\n    expect(JSON.stringify(ii2)).not.toEqual(JSON.stringify(ii1));\n    expect(JSON.stringify(ii3)).not.toEqual(JSON.stringify(ii1));\n    expect(JSON.stringify(ii3)).not.toEqual(JSON.stringify(ii2));\n\n    // Compare with optimized inverted index.\n    let iio3 = new InvertedIndex();\n    iio3.insert(field1, 1);\n    iio3.insert(field3, 3);\n    expect(JSON.stringify(ii3.root)).toEqual(JSON.stringify(iio3.root));\n\n    ii1.remove(1);\n    ii1.remove(2);\n    ii2.remove(2);\n    ii3.remove(1);\n    expect(JSON.stringify(ii2)).toEqual(JSON.stringify(ii1));\n    expect(JSON.stringify(ii3)).toEqual(JSON.stringify(ii1));\n    expect(JSON.stringify(ii3)).toEqual(JSON.stringify(ii2));\n\n    ii2 = InvertedIndex.fromJSONObject(JSON.parse(JSON.stringify(ii1)));\n    expect(JSON.stringify(ii2)).toEqual(JSON.stringify(ii1));\n\n    ii1.insert(field5, 5);\n    expect(JSON.stringify(ii2)).not.toEqual(JSON.stringify(ii1));\n    expect(JSON.stringify(ii3)).not.toEqual(JSON.stringify(ii1));\n\n    ii1.remove(5);\n    expect(JSON.stringify(ii2)).toEqual(JSON.stringify(ii1));\n    expect(JSON.stringify(ii3)).toEqual(JSON.stringify(ii1));\n    expect(JSON.stringify(ii3)).toEqual(JSON.stringify(ii2));\n\n    // Check if still can be used\n    ii3.insert(field5, 6);\n    ii3.remove(6);\n  });\n});\n"
  },
  {
    "path": "packages/full-text-search/spec/generic/search/fuzzy.spec.ts",
    "content": "/* global describe, it, expect */\nimport { FullTextSearch } from \"../../../src/full_text_search\";\nimport { FuzzyQuery, MatchQuery, Query, QueryTypes } from \"../../../src/query_types\";\n\ndescribe(\"fuzzy query\", () => {\n  // from lucene 6.4.0 core: TestFuzzyQuery\n  let assertMatches = (searcher: FullTextSearch, subQuery: QueryTypes, docIds: number[] = [], query: Query = {\n    query: subQuery\n  }) => {\n    let res = searcher.search(query);\n    expect(Object.keys(res).length).toEqual(docIds.length);\n    for (let i = 0; i < docIds.length; i++) {\n      expect(res).toHaveMember(String(docIds[i]));\n      delete res[String(docIds[i])];\n    }\n    expect(res).toEqual({});\n  };\n\n  it(\"Fuzzy query (1).\", () => {\n    let docs = [\"aaaaa\", \"aaaab\", \"aaabb\", \"aabbb\", \"abbbb\", \"bbbbb\", \"ddddd\"];\n    let fts = new FullTextSearch([{field: \"body\"}], \"$loki\");\n    for (let i = 0; i < docs.length; i++) {\n      fts.addDocument({\n        $loki: i,\n        body: docs[i]\n      });\n    }\n    let fuzzyQuery: FuzzyQuery = {type: \"fuzzy\", field: \"body\", value: \"aaaaa\", prefix_length: 0, fuzziness: 2};\n    // With prefix.\n    assertMatches(fts, fuzzyQuery, [0, 1, 2]);\n    fuzzyQuery.prefix_length = 1;\n    assertMatches(fts, fuzzyQuery, [0, 1, 2]);\n    fuzzyQuery.prefix_length = 2;\n    assertMatches(fts, fuzzyQuery, [0, 1, 2]);\n    fuzzyQuery.prefix_length = 3;\n    assertMatches(fts, fuzzyQuery, [0, 1, 2]);\n    fuzzyQuery.prefix_length = 4;\n    assertMatches(fts, fuzzyQuery, [0, 1]);\n    fuzzyQuery.prefix_length = 5;\n    assertMatches(fts, fuzzyQuery, [0]);\n    fuzzyQuery.prefix_length = 6;\n    assertMatches(fts, fuzzyQuery, [0]);\n\n    // not similar enough:\n    delete fuzzyQuery.prefix_length;\n    fuzzyQuery.value = \"xxxxx\";\n    assertMatches(fts, fuzzyQuery);\n    fuzzyQuery.value = \"aaccc\";\n    assertMatches(fts, fuzzyQuery);\n\n    // query identical to a word in the index:\n    fuzzyQuery.value = \"aaaaa\";\n    assertMatches(fts, fuzzyQuery, [0, 1, 2]);\n\n    // query similar to a word in the index:\n    fuzzyQuery.value = \"aaaac\";\n    assertMatches(fts, fuzzyQuery, [0, 1, 2]);\n\n    // With prefix.\n    fuzzyQuery.prefix_length = 1;\n    assertMatches(fts, fuzzyQuery, [0, 1, 2]);\n    fuzzyQuery.prefix_length = 2;\n    assertMatches(fts, fuzzyQuery, [0, 1, 2]);\n    fuzzyQuery.prefix_length = 3;\n    assertMatches(fts, fuzzyQuery, [0, 1, 2]);\n    fuzzyQuery.prefix_length = 4;\n    assertMatches(fts, fuzzyQuery, [0, 1]);\n    fuzzyQuery.prefix_length = 5;\n    assertMatches(fts, fuzzyQuery);\n\n    // Something other.\n    delete fuzzyQuery.prefix_length;\n    fuzzyQuery.value = \"ddddx\";\n    assertMatches(fts, fuzzyQuery, [6]);\n\n    // With prefix\n    fuzzyQuery.prefix_length = 1;\n    assertMatches(fts, fuzzyQuery, [6]);\n    fuzzyQuery.prefix_length = 2;\n    assertMatches(fts, fuzzyQuery, [6]);\n    fuzzyQuery.prefix_length = 3;\n    assertMatches(fts, fuzzyQuery, [6]);\n    fuzzyQuery.prefix_length = 4;\n    assertMatches(fts, fuzzyQuery, [6]);\n    fuzzyQuery.prefix_length = 5;\n    assertMatches(fts, fuzzyQuery);\n\n    // Without prefix length (default should be 0).\n    delete fuzzyQuery.prefix_length;\n    fuzzyQuery.value = \"aaaab\";\n    assertMatches(fts, fuzzyQuery, [0, 1, 2, 3]);\n    fuzzyQuery.value = \"aaabb\";\n    assertMatches(fts, fuzzyQuery, [0, 1, 2, 3, 4]);\n    fuzzyQuery.value = \"abbbb\";\n    assertMatches(fts, fuzzyQuery, [2, 3, 4, 5]);\n\n    // Empty.\n    fuzzyQuery.value = \"\";\n    assertMatches(fts, fuzzyQuery);\n\n    // Other.\n    fuzzyQuery.fuzziness = 1;\n    fuzzyQuery.value = \"aaaaa\";\n    fuzzyQuery.prefix_length = 0;\n    assertMatches(fts, fuzzyQuery, [0, 1]);\n\n    fuzzyQuery.value = \"aaaab\";\n    fuzzyQuery.prefix_length = 0;\n    assertMatches(fts, fuzzyQuery, [0, 1, 2]);\n\n    fuzzyQuery.value = \"ababb\";\n    fuzzyQuery.prefix_length = 2;\n    assertMatches(fts, fuzzyQuery, [4]);\n\n    fuzzyQuery.value = \"aaaaa\";\n    fuzzyQuery.prefix_length = 5;\n    assertMatches(fts, fuzzyQuery, [0]);\n\n    fuzzyQuery.prefix_length = 6;\n    assertMatches(fts, fuzzyQuery, [0]);\n\n    fuzzyQuery.value = \"aaaaaa\";\n    assertMatches(fts, fuzzyQuery, []);\n  });\n\n  it(\"Fuzzy query (2).\", () => {\n    let docs = [\"lange\", \"lueth\", \"pirsing\", \"riegel\", \"trzecziak\", \"walker\", \"wbr\", \"we\", \"web\", \"webe\", \"weber\",\n      \"webere\", \"webree\", \"weberei\", \"wbre\", \"wittkopf\", \"wojnarowski\", \"wricke\"];\n    let fts = new FullTextSearch([{field: \"body\"}], \"$loki\");\n    for (let i = 0; i < docs.length; i++) {\n      fts.addDocument({\n        $loki: i,\n        body: docs[i]\n      });\n    }\n    let fuzzyQuery: FuzzyQuery = {type: \"fuzzy\", field: \"body\", value: \"weber\", prefix_length: 1, fuzziness: 2};\n    assertMatches(fts, fuzzyQuery, [6, 8, 9, 10, 11, 12, 13, 14]);\n\n    delete fuzzyQuery.prefix_length;\n    fuzzyQuery.fuzziness = 0;\n    assertMatches(fts, fuzzyQuery, [10]);\n  });\n\n  it(\"unicode\", () => {\n    let docs = [\"\\u{000169bb}\\u{000569bb}\\u{000969bb}\", \"\\u{000169bb}\\u{000569bb}\\u{000969be}\",\n      \"\\u{000169bb}\\u{000969be}\", \"\\u{000969bb}\", \"\\u{000569bb}\", \"\\u{000285ac}\\u{000969bb}\"];\n\n    let fts = new FullTextSearch([{field: \"body\"}], \"$loki\");\n    for (let i = 0; i < docs.length; i++) {\n      fts.addDocument({\n        $loki: i,\n        body: docs[i]\n      });\n    }\n    let fuzzyQuery: FuzzyQuery = {\n      type: \"fuzzy\", field: \"body\", value: \"\\u{000169bb}\\u{000969bb}\", prefix_length: 0,\n      fuzziness: 1\n    };\n    assertMatches(fts, fuzzyQuery, [0, 2, 3, 5]);\n  });\n\n  it(\"Fuzzy query extended.\", () => {\n    let docs = [\"walker\", \"wbr\", \"we\", \"web\", \"webe\", \"weber\", \"webere\", \"webree\", \"weberei\", \"wbes\", \"wbert\", \"wbb\",\n      \"xeb\", \"wrr\", \"wrr\"];\n    let fts = new FullTextSearch([{field: \"body\"}], \"$loki\");\n    for (let i = 0; i < docs.length; i++) {\n      fts.addDocument({\n        $loki: i,\n        body: docs[i]\n      });\n    }\n\n    let fuzzyQuery: FuzzyQuery = {\n      type: \"fuzzy\", field: \"body\", value: \"web\", prefix_length: 1, fuzziness: 1,\n      extended: true\n    };\n    assertMatches(fts, fuzzyQuery, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);\n\n    let matchQuery: MatchQuery = {\n      type: \"match\", field: \"body\", value: \"web\", prefix_length: 1, fuzziness: 1,\n      extended: true\n    };\n    assertMatches(fts, matchQuery, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);\n  });\n\n  it(\"Fuzzy query extended 2.\", () => {\n    let docs = [\"abca\", \"abcd\", \"abcde\"];\n    let fts = new FullTextSearch([{field: \"body\"}], \"$loki\");\n    for (let i = 0; i < docs.length; i++) {\n      fts.addDocument({\n        $loki: i,\n        body: docs[i]\n      });\n    }\n    let fuzzyQuery: FuzzyQuery = {\n      type: \"fuzzy\", field: \"body\", value: \"abcd\", prefix_length: 1, fuzziness: 0,\n      extended: true\n    };\n    assertMatches(fts, fuzzyQuery, [1, 2]);\n\n    assertMatches(fts, fuzzyQuery, [1, 2], {query: fuzzyQuery, calculate_scoring: false});\n  });\n});\n"
  },
  {
    "path": "packages/full-text-search/spec/generic/search/wildcard.spec.ts",
    "content": "/* global describe, it, expect */\nimport { FullTextSearch } from \"../../../src/full_text_search\";\nimport { Query, QueryTypes, WildcardQuery } from \"../../../src/query_types\";\nimport { Analyzer } from \"../../../src/analyzer/analyzer\";\n\ndescribe(\"wildcard query\", () => {\n  // from lucene 6.4.0 core: TestWildCard\n  let assertMatches = (searcher: FullTextSearch, subQuery: QueryTypes, docIds: number[] = [], query: Query = {\n    query: subQuery\n  }) => {\n    let res = searcher.search(query);\n    expect(Object.keys(res).length).toEqual(docIds.length);\n    for (let i = 0; i < docIds.length; i++) {\n      expect(res).toHaveMember(String(docIds[i]));\n      delete res[String(docIds[i])];\n    }\n    expect(res).toEqual({});\n  };\n\n  it(\"Tests Wildcard queries with an asterisk.\", () => {\n    let docs = [\"metal\", \"metals\", \"mXtals\", \"mXtXls\"];\n    let fts = new FullTextSearch([{field: \"body\"}], \"$loki\");\n    for (let i = 0; i < docs.length; i++) {\n      fts.addDocument({\n        $loki: i,\n        body: docs[i]\n      });\n    }\n    let wildcardQuery: WildcardQuery = {type: \"wildcard\", field: \"body\", value: \"metal*\"};\n    assertMatches(fts, wildcardQuery, [0, 1]);\n    wildcardQuery.value = \"metals*\";\n    assertMatches(fts, wildcardQuery, [1]);\n    wildcardQuery.value = \"mx*\";\n    assertMatches(fts, wildcardQuery, [2, 3]);\n    wildcardQuery.value = \"mX*\";\n    assertMatches(fts, wildcardQuery);\n    wildcardQuery.value = \"m*\";\n    assertMatches(fts, wildcardQuery, [0, 1, 2, 3]);\n    wildcardQuery.value = \"m*tal\";\n    assertMatches(fts, wildcardQuery, [0]);\n    wildcardQuery.value = \"m*tal*\";\n    assertMatches(fts, wildcardQuery, [0, 1, 2]);\n    wildcardQuery.value = \"m*tals\";\n    assertMatches(fts, wildcardQuery, [1, 2]);\n    wildcardQuery.value = \"*tall\";\n    assertMatches(fts, wildcardQuery, []);\n    wildcardQuery.value = \"*tal\";\n    assertMatches(fts, wildcardQuery, [0]);\n    wildcardQuery.value = \"*tal*\";\n    assertMatches(fts, wildcardQuery, [0, 1, 2]);\n  });\n\n  it(\"Tests Wildcard queries with a question mark.\", () => {\n    let docs = [\"metal\", \"metals\", \"mXtals\", \"mXtXls\"];\n    let fts = new FullTextSearch([{field: \"body\"}], \"$loki\");\n    for (let i = 0; i < docs.length; i++) {\n      fts.addDocument({\n        $loki: i,\n        body: docs[i]\n      });\n    }\n    let wildcardQuery: WildcardQuery = {type: \"wildcard\", field: \"body\", value: \"m?tal\"};\n    assertMatches(fts, wildcardQuery, [0]);\n    wildcardQuery.value = \"metal?\";\n    assertMatches(fts, wildcardQuery, [1]);\n    wildcardQuery.value = \"metals?\";\n    assertMatches(fts, wildcardQuery);\n    wildcardQuery.value = \"m?t?ls\";\n    assertMatches(fts, wildcardQuery, [1, 2, 3]);\n    wildcardQuery.value = \"M?t?ls\";\n    assertMatches(fts, wildcardQuery);\n    wildcardQuery.value = \"meta??\";\n    assertMatches(fts, wildcardQuery, [1]);\n  });\n\n  it(\"Tests if wildcard escaping works.\", () => {\n    let docs = [\"foo*bar\", \"foo??bar\", \"fooCDbar\", \"fooSOMETHINGbar\", \"foo\\\\\", \"foo\\\\\\\\\"];\n\n    const analyzer: Analyzer = {\n      // Don't split the text.\n      tokenizer: (text) => [text]\n    };\n\n    let fts = new FullTextSearch([{field: \"body\", analyzer: analyzer}], \"$loki\");\n    for (let i = 0; i < docs.length; i++) {\n      fts.addDocument({\n        $loki: i,\n        body: docs[i]\n      });\n    }\n    let wildcardQuery: WildcardQuery = {type: \"wildcard\", field: \"body\", value: \"foo*bar\"};\n    assertMatches(fts, wildcardQuery, [0, 1, 2, 3]);\n    wildcardQuery.value = \"foo\\\\*bar\";\n    assertMatches(fts, wildcardQuery, [0]);\n    wildcardQuery.value = \"foo??bar\";\n    assertMatches(fts, wildcardQuery, [1, 2]);\n    wildcardQuery.value = \"foo\\\\?\\\\?bar\";\n    assertMatches(fts, wildcardQuery, [1]);\n    wildcardQuery.value = \"foo\\\\\\\\\";\n    assertMatches(fts, wildcardQuery, [4]);\n    wildcardQuery.value = \"foo\\\\\\\\*\";\n    assertMatches(fts, wildcardQuery, [4, 5]);\n  });\n});\n"
  },
  {
    "path": "packages/full-text-search/spec/node/MOCK_DATA.ts",
    "content": "export const DATA = [\n  {\n    \"id\": 1,\n    \"msg\": \"varius nulla facilisi cras non velit nec nisi vulputate nonummy maecenas tincidunt lacus at velit vivamus vel nulla eget eros elementum pellentesque quisque porta volutpat erat quisque erat eros viverra eget congue eget semper rutrum nulla nunc purus \"\n  },\n  {\n    \"id\": 2,\n    \"msg\": \" sit amet eros suspendisse accumsan tortor quis turpis sed ante vivamus tortor duis mattis egestas metus aenean fermentum donec ut mauris eget massa tempor convallis nulla neque libero convallis eget eleifend luctus ultricies eu nibh quisque id \"\n  },\n  {\"id\": 3, \"msg\": \" augue a suscipit nulla elit ac nulla sed vel enim sit amet nunc viverra\"},\n  {\n    \"id\": 4,\n    \"msg\": \"non sodales sed tincidunt eu felis fusce posuere felis sed lacus morbi sem mauris laoreet ut rhoncus aliquet pulvinar sed nisl nunc rhoncus dui vel sem sed sagittis nam congue risus semper porta\"\n  },\n  {\n    \"id\": 5,\n    \"msg\": \"curabitur gravida nisi at nibh in hac habitasse platea dictumst aliquam augue quam sollicitudin vitae consectetuer eget rutrum at lorem integer tincidunt ante vel ipsum praesent blandit lacinia erat vestibulum sed magna at nunc commodo placerat praesent blandit nam nulla integer pede justo\"\n  },\n  {\n    \"id\": 6,\n    \"msg\": \"diam id ornare imperdiet sapien urna pretium nisl ut volutpat sapien arcu sed augue aliquam erat volutpat in congue etiam justo\"\n  },\n  {\n    \"id\": 7,\n    \"msg\": \"mi pede malesuada in imperdiet et commodo vulputate justo in blandit ultrices enim lorem ipsum dolor sit amet consectetuer adipiscing elit proin interdum mauris non ligula pellentesque ultrices phasellus id sapien in sapien iaculis congue vivamus\"\n  },\n  {\n    \"id\": 8,\n    \"msg\": \"maecenas pulvinar lobortis est phasellus sit amet erat nulla tempus vivamus in felis eu sapien cursus vestibulum proin eu mi\"\n  },\n  {\n    \"id\": 9,\n    \"msg\": \"tempor convallis nulla neque libero convallis eget eleifend luctus ultricies eu nibh quisque id justo sit amet sapien dignissim vestibulum vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae nulla dapibus dolor\"\n  },\n  {\n    \"id\": 10,\n    \"msg\": \"potenti nullam porttitor lacus at turpis donec posuere metus vitae ipsum aliquam non mauris morbi non lectus aliquam sit\"\n  },\n  {\n    \"id\": 11,\n    \"msg\": \"convallis nunc proin at turpis a pede posuere nonummy integer non velit donec diam neque vestibulum eget vulputate ut ultrices vel augue vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae donec pharetra magna vestibulum aliquet ultrices erat tortor sollicitudin mi sit amet lobortis\"\n  },\n  {\n    \"id\": 12,\n    \"msg\": \"vestibulum rutrum rutrum neque aenean auctor gravida sem praesent id massa id nisl venenatis lacinia aenean sit amet justo morbi ut odio cras mi pede malesuada in imperdiet et commodo vulputate justo in\"\n  },\n  {\n    \"id\": 13,\n    \"msg\": \"eros suspendisse accumsan tortor quis turpis sed ante vivamus tortor duis mattis egestas metus aenean fermentum donec ut mauris eget massa tempor convallis nulla neque libero convallis eget eleifend luctus\"\n  },\n  {\n    \"id\": 14,\n    \"msg\": \"nisl duis ac nibh fusce lacus purus aliquet at feugiat non pretium quis lectus suspendisse potenti in eleifend quam a odio\"\n  },\n  {\n    \"id\": 15,\n    \"msg\": \"praesent lectus vestibulum quam sapien varius ut blandit non interdum in ante vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae duis faucibus accumsan odio curabitur convallis duis consequat dui nec nisi volutpat eleifend\"\n  },\n  {\n    \"id\": 16,\n    \"msg\": \"nullam molestie nibh in lectus pellentesque at nulla suspendisse potenti cras in purus eu magna vulputate luctus cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus vivamus\"\n  },\n  {\n    \"id\": 17,\n    \"msg\": \"quam suspendisse potenti nullam porttitor lacus at turpis donec posuere metus vitae ipsum aliquam\"\n  },\n  {\n    \"id\": 18,\n    \"msg\": \"ut massa volutpat convallis morbi odio odio elementum eu interdum eu tincidunt in leo maecenas pulvinar lobortis est phasellus sit amet\"\n  },\n  {\n    \"id\": 19,\n    \"msg\": \"viverra dapibus nulla suscipit ligula in lacus curabitur at ipsum ac tellus semper interdum mauris ullamcorper purus\"\n  },\n  {\n    \"id\": 20,\n    \"msg\": \"maecenas pulvinar lobortis est phasellus sit amet erat nulla tempus vivamus in felis eu sapien cursus vestibulum proin eu mi nulla ac enim in tempor turpis nec euismod scelerisque quam turpis adipiscing lorem\"\n  },\n  {\n    \"id\": 21,\n    \"msg\": \"sollicitudin vitae consectetuer eget rutrum at lorem integer tincidunt ante vel ipsum praesent\"\n  },\n  {\n    \"id\": 22,\n    \"msg\": \"fermentum justo nec condimentum neque sapien placerat ante nulla justo aliquam quis turpis eget elit sodales scelerisque\"\n  },\n  {\n    \"id\": 23,\n    \"msg\": \"integer aliquet massa id lobortis convallis tortor risus dapibus augue vel accumsan tellus nisi eu orci mauris lacinia sapien quis libero nullam sit amet turpis elementum ligula vehicula consequat morbi a ipsum integer a nibh in quis justo maecenas\"\n  },\n  {\n    \"id\": 24,\n    \"msg\": \"nullam sit amet turpis elementum ligula vehicula consequat morbi a ipsum integer a nibh in quis justo maecenas rhoncus aliquam lacus morbi quis tortor id nulla ultrices aliquet maecenas leo odio condimentum id luctus nec molestie sed justo pellentesque viverra pede ac diam\"\n  },\n  {\n    \"id\": 25,\n    \"msg\": \"eget tempus vel pede morbi porttitor lorem id ligula suspendisse ornare consequat lectus in este risus auctor sed tristique in tempus sit amet sem fusce consequat nulla nisl\"\n  },\n  {\n    \"id\": 26,\n    \"msg\": \"eu mi nulla ac enim in tempor turpis nec euismod scelerisque quam turpis adipiscing lorem vitae mattis nibh ligula\"\n  },\n  {\n    \"id\": 27,\n    \"msg\": \"eget orci vehicula condimentum curabitur in libero ut massa volutpat convallis morbi odio odio elementum eu interdum eu tincidunt in leo maecenas pulvinar lobortis est phasellus sit amet erat nulla tempus vivamus in felis eu sapien cursus vestibulum proin eu mi nulla ac enim in tempor turpis\"\n  },\n  {\n    \"id\": 28,\n    \"msg\": \"amet lobortis sapien sapien non mi integer ac neque duis bibendum morbi non quam nec dui luctus rutrum nulla tellus in sagittis dui vel nisl duis ac nibh fusce lacus purus aliquet at feugiat non pretium quis lectus suspendisse potenti in\"\n  },\n  {\n    \"id\": 29,\n    \"msg\": \"in lacus curabitur at ipsum ac tellus semper interdum mauris ullamcorper purus sit amet nulla quisque arcu\"\n  },\n  {\n    \"id\": 30,\n    \"msg\": \"adipiscing elit proin interdum mauris non ligula pellentesque ultrices phasellus id sapien in sapien iaculis congue vivamus metus arcu adipiscing molestie hendrerit at vulputate vitae nisl aenean lectus pellentesque eget nunc donec quis orci eget orci vehicula condimentum curabitur\"\n  },\n  {\"id\": 31, \"msg\": \"volutpat quam pede lobortis ligula sit amet eleifend pede libero quis orci nullam molestie\"},\n  {\n    \"id\": 32,\n    \"msg\": \"metus arcu adipiscing molestie hendrerit at vulputate vitae nisl aenean lectus pellentesque eget nunc donec quis orci eget orci vehicula condimentum curabitur in libero\"\n  },\n  {\n    \"id\": 33,\n    \"msg\": \"sapien sapien non mi integer ac neque duis bibendum morbi non quam nec dui luctus rutrum nulla tellus in sagittis dui vel nisl duis ac nibh fusce lacus purus aliquet at feugiat non pretium quis lectus\"\n  },\n  {\n    \"id\": 34,\n    \"msg\": \"sollicitudin mi sit amet lobortis sapien sapien non mi integer ac neque duis bibendum morbi non quam nec dui luctus rutrum nulla tellus in\"\n  },\n  {\n    \"id\": 35,\n    \"msg\": \"vestibulum proin eu mi nulla ac enim in tempor turpis nec euismod scelerisque quam turpis adipiscing lorem vitae mattis nibh ligula nec sem duis aliquam convallis nunc proin at turpis a pede posuere nonummy integer\"\n  },\n  {\"id\": 36, \"msg\": \"quisque arcu libero rutrum ac lobortis vel dapibus at diam nam tristique\"},\n  {\n    \"id\": 37,\n    \"msg\": \"aliquam convallis nunc proin at turpis a pede posuere nonummy integer non velit donec diam neque vestibulum eget vulputate ut ultrices vel augue vestibulum ante ipsum primis\"\n  },\n  {\"id\": 38, \"msg\": \"convallis duis consequat dui nec nisi volutpat eleifend donec ut\"},\n  {\n    \"id\": 39,\n    \"msg\": \"eget rutrum at lorem integer tincidunt ante vel ipsum praesent blandit lacinia erat vestibulum sed magna at nunc commodo placerat praesent blandit nam nulla integer pede justo lacinia eget tincidunt eget tempus vel pede morbi porttitor lorem id ligula\"\n  },\n  {\n    \"id\": 40,\n    \"msg\": \"tincidunt ante vel ipsum praesent blandit lacinia erat vestibulum sed magna at nunc commodo placerat praesent blandit nam nulla integer pede justo lacinia eget tincidunt eget tempus vel\"\n  },\n  {\n    \"id\": 41,\n    \"msg\": \"sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus etiam vel augue vestibulum rutrum rutrum neque aenean auctor gravida sem praesent id massa id nisl venenatis lacinia aenean sit amet justo morbi\"\n  },\n  {\n    \"id\": 42,\n    \"msg\": \"enim in tempor turpis nec euismod scelerisque quam turpis adipiscing lorem vitae mattis nibh ligula nec sem duis aliquam convallis nunc proin at\"\n  },\n  {\"id\": 43, \"msg\": \"consequat ut nulla sed accumsan felis ut at dolor quis odio consequat varius integer ac\"},\n  {\n    \"id\": 44,\n    \"msg\": \"vitae nisi nam ultrices libero non mattis pulvinar nulla pede ullamcorper augue a suscipit nulla elit ac nulla sed vel enim sit amet nunc viverra dapibus nulla suscipit ligula in lacus curabitur at ipsum ac tellus semper interdum mauris ullamcorper purus sit amet\"\n  },\n  {\n    \"id\": 45,\n    \"msg\": \"posuere cubilia curae duis faucibus accumsan odio curabitur convallis duis consequat dui nec nisi volutpat eleifend donec ut dolor morbi vel lectus in quam fringilla rhoncus mauris enim leo rhoncus sed vestibulum sit amet cursus\"\n  },\n  {\n    \"id\": 46,\n    \"msg\": \"eros vestibulum ac est lacinia nisi venenatis tristique fusce congue diam id ornare imperdiet sapien urna pretium nisl ut volutpat sapien\"\n  },\n  {\n    \"id\": 47,\n    \"msg\": \"eleifend donec ut dolor morbi vel lectus in quam fringilla rhoncus mauris enim leo rhoncus sed vestibulum sit amet cursus id turpis integer aliquet massa id lobortis convallis tortor risus\"\n  },\n  {\n    \"id\": 48,\n    \"msg\": \"maecenas tincidunt lacus at velit vivamus vel nulla eget eros elementum pellentesque quisque porta volutpat erat quisque erat eros viverra eget congue eget semper rutrum nulla nunc purus phasellus in felis donec semper sapien a libero nam dui proin leo odio porttitor id consequat in consequat ut\"\n  },\n  {\n    \"id\": 49,\n    \"msg\": \"augue vestibulum rutrum rutrum neque aenean auctor gravida sem praesent id massa id nisl venenatis lacinia aenean sit amet justo morbi ut odio cras mi pede malesuada in imperdiet et commodo vulputate justo in blandit ultrices enim lorem ipsum dolor sit amet consectetuer adipiscing\"\n  },\n  {\n    \"id\": 50,\n    \"msg\": \"in consequat ut nulla sed accumsan felis ut at dolor quis odio consequat varius integer ac leo pellentesque ultrices mattis odio donec\"\n  },\n  {\n    \"id\": 51,\n    \"msg\": \"nam nulla integer pede justo lacinia eget tincidunt eget tempus vel pede morbi porttitor lorem id ligula suspendisse ornare\"\n  },\n  {\"id\": 52, \"msg\": \"nunc donec quis orci eget orci vehicula condimentum curabitur in libero\"},\n  {\n    \"id\": 53,\n    \"msg\": \"dolor morbi vel lectus in quam fringilla rhoncus mauris enim leo rhoncus sed vestibulum sit amet cursus id turpis integer aliquet massa id lobortis\"\n  },\n  {\"id\": 54, \"msg\": \"elit proin risus praesent lectus vestibulum quam sapien varius ut blandit\"},\n  {\n    \"id\": 55,\n    \"msg\": \"proin interdum mauris non ligula pellentesque ultrices phasellus id sapien in sapien iaculis congue vivamus metus arcu adipiscing molestie hendrerit at vulputate vitae\"\n  },\n  {\"id\": 56, \"msg\": \"etiam vel augue vestibulum rutrum rutrum neque aenean auctor gravida sem praesent\"},\n  {\"id\": 57, \"msg\": \"turpis elementum ligula vehicula consequat morbi a ipsum integer a\"},\n  {\n    \"id\": 58,\n    \"msg\": \"tincidunt nulla mollis molestie lorem quisque ut erat curabitur gravida nisi at nibh in hac habitasse platea dictumst aliquam\"\n  },\n  {\n    \"id\": 59,\n    \"msg\": \"pede posuere nonummy integer non velit donec diam neque vestibulum eget vulputate ut ultrices vel augue vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae donec pharetra magna vestibulum aliquet ultrices erat\"\n  },\n  {\n    \"id\": 60,\n    \"msg\": \"augue a suscipit nulla elit ac nulla sed vel enim sit amet nunc viverra dapibus nulla suscipit ligula in\"\n  },\n  {\"id\": 61, \"msg\": \"rutrum nulla tellus in sagittis dui vel nisl duis ac nibh\"},\n  {\n    \"id\": 62,\n    \"msg\": \"amet eleifend pede libero quis orci nullam molestie nibh in lectus pellentesque at nulla suspendisse potenti cras in purus eu magna vulputate luctus cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus\"\n  },\n  {\n    \"id\": 63,\n    \"msg\": \"amet consectetuer adipiscing elit proin risus praesent lectus vestibulum quam sapien varius ut blandit non interdum in ante vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae duis faucibus accumsan odio curabitur convallis duis consequat dui nec nisi volutpat eleifend donec ut dolor\"\n  },\n  {\n    \"id\": 64,\n    \"msg\": \"tempor turpis nec euismod scelerisque quam turpis adipiscing lorem vitae mattis nibh ligula nec sem duis aliquam convallis nunc proin at turpis a pede posuere nonummy integer non velit donec diam neque vestibulum eget vulputate ut ultrices vel augue vestibulum ante ipsum primis in faucibus orci luctus et ultrices\"\n  },\n  {\n    \"id\": 65,\n    \"msg\": \"dictumst morbi vestibulum velit id pretium iaculis diam erat fermentum justo nec condimentum neque sapien placerat ante nulla\"\n  },\n  {\n    \"id\": 66,\n    \"msg\": \"augue vel accumsan tellus nisi eu orci mauris lacinia sapien quis libero nullam sit amet turpis elementum ligula vehicula consequat morbi\"\n  },\n  {\n    \"id\": 67,\n    \"msg\": \"nascetur ridiculus mus etiam vel augue vestibulum rutrum rutrum neque aenean auctor gravida sem praesent id massa id nisl venenatis lacinia aenean sit amet justo morbi ut odio cras mi pede\"\n  },\n  {\n    \"id\": 68,\n    \"msg\": \"at turpis donec posuere metus vitae ipsum aliquam non mauris morbi non lectus aliquam sit amet diam in magna bibendum imperdiet nullam orci pede venenatis non sodales sed tincidunt eu\"\n  },\n  {\n    \"id\": 69,\n    \"msg\": \"sed lacus morbi sem mauris laoreet ut rhoncus aliquet pulvinar sed nisl nunc rhoncus dui vel sem sed sagittis nam congue risus semper porta volutpat quam pede lobortis ligula sit amet eleifend pede libero quis orci nullam molestie nibh in lectus pellentesque at nulla suspendisse potenti cras in purus\"\n  },\n  {\"id\": 70, \"msg\": \"justo aliquam quis turpis eget elit sodales scelerisque mauris sit amet eros\"},\n  {\n    \"id\": 71,\n    \"msg\": \"platea dictumst morbi vestibulum velit id pretium iaculis diam erat fermentum justo nec condimentum neque sapien placerat ante nulla justo aliquam quis turpis eget elit sodales scelerisque mauris sit amet eros suspendisse accumsan tortor quis turpis\"\n  },\n  {\n    \"id\": 72,\n    \"msg\": \"est lacinia nisi venenatis tristique fusce congue diam id ornare imperdiet sapien urna pretium nisl ut volutpat sapien\"\n  },\n  {\n    \"id\": 73,\n    \"msg\": \"in faucibus orci luctus et ultrices posuere cubilia curae donec pharetra magna vestibulum aliquet ultrices erat tortor sollicitudin mi sit amet lobortis\"\n  },\n  {\n    \"id\": 74,\n    \"msg\": \"vestibulum eget vulputate ut ultrices vel augue vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae donec pharetra magna vestibulum aliquet ultrices erat tortor sollicitudin mi sit amet lobortis sapien sapien non mi integer ac neque duis bibendum morbi non quam nec dui luctus\"\n  },\n  {\n    \"id\": 75,\n    \"msg\": \"leo pellentesque ultrices mattis odio donec vitae nisi nam ultrices libero non mattis pulvinar nulla pede ullamcorper augue a suscipit nulla elit ac nulla sed vel enim sit amet nunc viverra dapibus nulla suscipit ligula in lacus curabitur at ipsum ac tellus\"\n  },\n  {\n    \"id\": 76,\n    \"msg\": \"pellentesque ultrices phasellus id sapien in sapien iaculis congue vivamus metus arcu adipiscing molestie\"\n  },\n  {\n    \"id\": 77,\n    \"msg\": \"non mi integer ac neque duis bibendum morbi non quam nec dui luctus rutrum nulla tellus in sagittis dui vel nisl duis ac nibh fusce lacus purus aliquet at feugiat non pretium\"\n  },\n  {\n    \"id\": 78,\n    \"msg\": \"risus auctor sed tristique in tempus sit amet sem fusce consequat nulla nisl nunc nisl duis bibendum felis sed interdum venenatis turpis enim blandit mi in porttitor pede justo eu massa donec dapibus duis at velit eu est congue elementum in hac habitasse platea dictumst morbi vestibulum velit\"\n  },\n  {\n    \"id\": 79,\n    \"msg\": \"hendrerit at vulputate vitae nisl aenean lectus pellentesque eget nunc donec quis orci eget orci vehicula condimentum curabitur in libero ut massa volutpat convallis morbi odio odio elementum eu interdum eu tincidunt in leo\"\n  },\n  {\"id\": 80, \"msg\": \"dapibus nulla suscipit ligula in lacus curabitur at ipsum ac tellus semper interdum mauris\"},\n  {\n    \"id\": 81,\n    \"msg\": \"odio elementum eu interdum eu tincidunt in leo maecenas pulvinar lobortis est phasellus sit amet erat nulla tempus vivamus in felis eu sapien cursus vestibulum proin eu mi nulla ac enim in tempor turpis nec euismod scelerisque quam turpis adipiscing lorem\"\n  },\n  {\n    \"id\": 82,\n    \"msg\": \"vestibulum vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae nulla dapibus dolor vel est donec odio justo\"\n  },\n  {\n    \"id\": 83,\n    \"msg\": \"donec quis orci eget orci vehicula condimentum curabitur in libero ut massa volutpat convallis morbi odio odio elementum eu interdum eu tincidunt in leo maecenas pulvinar lobortis est phasellus\"\n  },\n  {\n    \"id\": 84,\n    \"msg\": \"pede malesuada in imperdiet et commodo vulputate justo in blandit ultrices enim lorem ipsum dolor sit amet consectetuer adipiscing elit proin\"\n  },\n  {\n    \"id\": 85,\n    \"msg\": \"vulputate elementum nullam varius nulla facilisi cras non velit nec nisi vulputate nonummy maecenas tincidunt lacus at velit\"\n  },\n  {\n    \"id\": 86,\n    \"msg\": \"praesent id massa id nisl venenatis lacinia aenean sit amet justo morbi ut odio cras mi pede malesuada in imperdiet et commodo vulputate justo in blandit ultrices enim lorem ipsum dolor sit amet consectetuer adipiscing elit proin interdum mauris non\"\n  },\n  {\n    \"id\": 87,\n    \"msg\": \"lacus at velit vivamus vel nulla eget eros elementum pellentesque quisque porta volutpat erat quisque erat eros viverra eget congue eget semper rutrum nulla nunc purus phasellus in felis donec semper sapien a libero nam dui proin leo odio porttitor id consequat in consequat ut nulla sed accumsan felis ut\"\n  },\n  {\n    \"id\": 88,\n    \"msg\": \"aenean fermentum donec ut mauris eget massa tempor convallis nulla neque libero convallis eget eleifend luctus ultricies eu nibh quisque id justo sit amet sapien dignissim vestibulum vestibulum ante ipsum primis in faucibus orci luctus et ultrices\"\n  },\n  {\n    \"id\": 89,\n    \"msg\": \"quis justo maecenas rhoncus aliquam lacus morbi quis tortor id nulla ultrices aliquet maecenas leo odio condimentum id luctus\"\n  },\n  {\n    \"id\": 90,\n    \"msg\": \"felis eu sapien cursus vestibulum proin eu mi nulla ac enim in tempor turpis nec euismod scelerisque quam turpis adipiscing lorem vitae mattis nibh ligula nec sem duis aliquam convallis nunc proin at turpis a pede posuere nonummy\"\n  },\n  {\n    \"id\": 91,\n    \"msg\": \"lorem ipsum dolor sit amet consectetuer adipiscing elit proin risus praesent lectus vestibulum quam sapien\"\n  },\n  {\n    \"id\": 92,\n    \"msg\": \"cubilia curae donec pharetra magna vestibulum aliquet ultrices erat tortor sollicitudin mi sit amet lobortis sapien sapien non mi integer ac neque duis bibendum morbi non quam nec dui luctus rutrum nulla tellus in sagittis\"\n  },\n  {\n    \"id\": 93,\n    \"msg\": \"eget semper rutrum nulla nunc purus phasellus in felis donec semper sapien a libero nam dui proin leo odio porttitor id consequat in consequat ut nulla sed accumsan felis ut at dolor quis odio consequat varius\"\n  },\n  {\n    \"id\": 94,\n    \"msg\": \"nibh in quis justo maecenas rhoncus aliquam lacus morbi quis tortor id nulla ultrices aliquet maecenas leo odio\"\n  },\n  {\"id\": 95, \"msg\": \"tristique fusce congue diam id ornare imperdiet sapien urna pretium nisl\"},\n  {\n    \"id\": 96,\n    \"msg\": \"aliquam sit amet diam in magna bibendum imperdiet nullam orci pede venenatis non sodales sed tincidunt eu felis fusce posuere\"\n  },\n  {\n    \"id\": 97,\n    \"msg\": \"in imperdiet et commodo vulputate justo in blandit ultrices enim lorem ipsum dolor sit amet consectetuer adipiscing elit proin interdum mauris non\"\n  },\n  {\n    \"id\": 98,\n    \"msg\": \"nisi vulputate nonummy maecenas tincidunt lacus at velit vivamus vel nulla eget eros elementum pellentesque quisque porta volutpat erat quisque erat eros viverra eget congue eget semper rutrum nulla nunc purus phasellus in felis\"\n  },\n  {\n    \"id\": 99,\n    \"msg\": \"hendrerit at vulputate vitae nisl aenean lectus pellentesque eget nunc donec quis orci eget orci vehicula condimentum curabitur in libero ut massa volutpat convallis morbi odio\"\n  },\n  {\n    \"id\": 100,\n    \"msg\": \"vel lectus in quam fringilla rhoncus mauris enim leo rhoncus sed vestibulum sit amet cursus id turpis integer aliquet massa id lobortis convallis tortor risus dapibus augue vel accumsan tellus nisi eu orci mauris lacinia sapien\"\n  },\n  {\n    \"id\": 101,\n    \"msg\": \"pharetra magna vestibulum aliquet ultrices erat tortor sollicitudin mi sit amet lobortis sapien sapien non mi integer ac neque duis bibendum morbi non quam nec dui luctus rutrum nulla tellus in sagittis dui vel nisl duis ac nibh fusce lacus purus aliquet at feugiat non pretium quis\"\n  },\n  {\n    \"id\": 102,\n    \"msg\": \"tellus nulla ut erat id mauris vulputate elementum nullam varius nulla facilisi cras non velit nec nisi vulputate nonummy maecenas tincidunt lacus at velit vivamus vel nulla\"\n  },\n  {\n    \"id\": 103,\n    \"msg\": \"luctus et ultrices posuere cubilia curae donec pharetra magna vestibulum aliquet ultrices erat tortor sollicitudin mi sit amet lobortis sapien sapien non mi integer ac neque duis bibendum morbi non quam nec dui luctus rutrum nulla tellus in sagittis dui vel nisl duis ac nibh fusce\"\n  },\n  {\n    \"id\": 104,\n    \"msg\": \"a odio in hac habitasse platea dictumst maecenas ut massa quis augue luctus tincidunt nulla mollis molestie lorem quisque ut erat curabitur gravida nisi at nibh in hac habitasse\"\n  },\n  {\n    \"id\": 105,\n    \"msg\": \"magna vestibulum aliquet ultrices erat tortor sollicitudin mi sit amet lobortis sapien sapien non mi\"\n  },\n  {\n    \"id\": 106,\n    \"msg\": \"nunc vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae mauris viverra diam vitae quam suspendisse potenti nullam porttitor lacus at turpis donec posuere metus vitae ipsum aliquam non mauris morbi non lectus\"\n  },\n  {\n    \"id\": 107,\n    \"msg\": \"porta volutpat erat quisque erat eros viverra eget congue eget semper rutrum nulla nunc purus phasellus in felis donec semper sapien a libero nam dui proin leo odio porttitor id consequat in consequat ut nulla sed accumsan felis ut at dolor quis odio consequat varius integer ac leo pellentesque\"\n  },\n  {\n    \"id\": 108,\n    \"msg\": \"elementum in hac habitasse platea dictumst morbi vestibulum velit id pretium iaculis diam erat fermentum justo\"\n  },\n  {\n    \"id\": 109,\n    \"msg\": \"pharetra magna vestibulum aliquet ultrices erat tortor sollicitudin mi sit amet lobortis sapien sapien non mi integer ac neque duis bibendum morbi non quam nec dui luctus rutrum nulla tellus in\"\n  },\n  {\n    \"id\": 110,\n    \"msg\": \"eget eros elementum pellentesque quisque porta volutpat erat quisque erat eros viverra eget congue eget semper rutrum nulla nunc purus phasellus in felis donec semper sapien a libero nam dui proin\"\n  },\n  {\"id\": 111, \"msg\": \"porttitor lorem id ligula suspendisse ornare consequat lectus in est risus auctor\"},\n  {\n    \"id\": 112,\n    \"msg\": \"quam turpis adipiscing lorem vitae mattis nibh ligula nec sem duis aliquam convallis nunc proin at turpis a pede posuere nonummy integer non velit donec diam neque vestibulum eget vulputate ut ultrices vel augue vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia\"\n  },\n  {\n    \"id\": 113,\n    \"msg\": \"eu tincidunt in leo maecenas pulvinar lobortis est phasellus sit amet erat nulla tempus vivamus in felis eu sapien cursus vestibulum proin eu mi nulla ac enim in tempor turpis nec euismod scelerisque quam\"\n  },\n  {\"id\": 114, \"msg\": \"interdum in ante vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere\"},\n  {\n    \"id\": 115,\n    \"msg\": \"tempus vivamus in felis eu sapien cursus vestibulum proin eu mi nulla ac enim in tempor turpis nec euismod scelerisque\"\n  },\n  {\n    \"id\": 116,\n    \"msg\": \"tempor convallis nulla neque libero convallis eget eleifend luctus ultricies eu nibh quisque id justo sit amet sapien dignissim vestibulum vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae nulla dapibus dolor\"\n  },\n  {\"id\": 117, \"msg\": \"nulla ac enim in tempor turpis nec euismod scelerisque quam\"},\n  {\n    \"id\": 118,\n    \"msg\": \"nunc commodo placerat praesent blandit nam nulla integer pede justo lacinia eget tincidunt eget tempus vel pede morbi porttitor lorem id ligula suspendisse ornare consequat lectus\"\n  },\n  {\n    \"id\": 119,\n    \"msg\": \"justo lacinia eget tincidunt eget tempus vel pede morbi porttitor lorem id ligula suspendisse ornare consequat lectus in est risus auctor sed tristique in tempus sit amet sem fusce consequat nulla nisl nunc nisl duis bibendum felis\"\n  },\n  {\"id\": 120, \"msg\": \"lobortis est phasellus sit amet erat nulla tempus vivamus in felis eu sapien cursus vestibulum\"},\n  {\n    \"id\": 121,\n    \"msg\": \"facilisi cras non velit nec nisi vulputate nonummy maecenas tincidunt lacus at velit vivamus vel nulla eget eros elementum pellentesque quisque porta volutpat erat quisque erat eros viverra eget congue eget semper rutrum nulla nunc purus phasellus\"\n  },\n  {\n    \"id\": 122,\n    \"msg\": \"nullam orci pede venenatis non sodales sed tincidunt eu felis fusce posuere felis sed lacus morbi sem mauris laoreet ut rhoncus aliquet pulvinar sed nisl nunc rhoncus dui vel sem\"\n  },\n  {\"id\": 123, \"msg\": \"faucibus orci luctus et ultrices posuere cubilia curae nulla dapibus dolor vel\"},\n  {\n    \"id\": 124,\n    \"msg\": \"orci eget orci vehicula condimentum curabitur in libero ut massa volutpat convallis morbi odio odio elementum eu interdum\"\n  },\n  {\n    \"id\": 125,\n    \"msg\": \"odio condimentum id luctus nec molestie sed justo pellentesque viverra pede ac diam cras pellentesque volutpat dui maecenas tristique est et tempus semper est quam pharetra magna ac consequat metus sapien ut nunc vestibulum ante ipsum primis in faucibus orci\"\n  },\n  {\n    \"id\": 126,\n    \"msg\": \"id turpis integer aliquet massa id lobortis convallis tortor risus dapibus augue vel accumsan tellus nisi eu orci\"\n  },\n  {\n    \"id\": 127,\n    \"msg\": \"erat eros viverra eget congue eget semper rutrum nulla nunc purus phasellus in felis donec semper sapien a libero nam dui proin leo odio porttitor id consequat in consequat ut nulla sed accumsan felis ut at dolor quis odio consequat varius integer ac leo pellentesque\"\n  },\n  {\n    \"id\": 128,\n    \"msg\": \"purus eu magna vulputate luctus cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus vivamus vestibulum sagittis sapien cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus etiam vel augue vestibulum rutrum rutrum neque aenean auctor gravida sem\"\n  },\n  {\n    \"id\": 129,\n    \"msg\": \"non mi integer ac neque duis bibendum morbi non quam nec dui luctus rutrum nulla tellus in sagittis dui vel nisl duis ac nibh fusce lacus purus\"\n  },\n  {\n    \"id\": 130,\n    \"msg\": \"nunc nisl duis bibendum felis sed interdum venenatis turpis enim blandit mi in porttitor pede justo eu massa donec dapibus duis at velit eu est congue elementum in hac habitasse platea dictumst morbi vestibulum velit id pretium iaculis diam erat fermentum justo nec condimentum neque sapien placerat ante nulla\"\n  },\n  {\n    \"id\": 131,\n    \"msg\": \"ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae nulla dapibus dolor vel est donec odio justo sollicitudin ut suscipit a feugiat et eros vestibulum ac est lacinia nisi venenatis tristique fusce congue diam id ornare imperdiet sapien urna pretium nisl ut\"\n  },\n  {\n    \"id\": 132,\n    \"msg\": \"curabitur at ipsum ac tellus semper interdum mauris ullamcorper purus sit amet nulla quisque arcu libero rutrum ac lobortis vel dapibus at diam\"\n  },\n  {\"id\": 133, \"msg\": \"sed lacus morbi sem mauris laoreet ut rhoncus aliquet pulvinar\"},\n  {\n    \"id\": 134,\n    \"msg\": \"fusce lacus purus aliquet at feugiat non pretium quis lectus suspendisse potenti in eleifend quam a odio in hac habitasse platea dictumst maecenas ut massa quis\"\n  },\n  {\n    \"id\": 135,\n    \"msg\": \"nec condimentum neque sapien placerat ante nulla justo aliquam quis turpis eget elit sodales scelerisque mauris sit amet eros suspendisse accumsan tortor\"\n  },\n  {\n    \"id\": 136,\n    \"msg\": \"duis bibendum felis sed interdum venenatis turpis enim blandit mi in porttitor pede justo eu massa donec dapibus duis at velit eu est congue elementum\"\n  },\n  {\n    \"id\": 137,\n    \"msg\": \"vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae duis faucibus accumsan odio curabitur convallis duis consequat dui nec nisi volutpat eleifend donec ut dolor morbi vel lectus in quam fringilla rhoncus mauris enim leo rhoncus sed vestibulum sit amet cursus id turpis integer aliquet\"\n  },\n  {\n    \"id\": 138,\n    \"msg\": \"pede venenatis non sodales sed tincidunt eu felis fusce posuere felis sed lacus morbi sem mauris laoreet ut rhoncus aliquet pulvinar sed nisl nunc rhoncus dui vel sem sed sagittis nam congue risus semper porta volutpat quam pede lobortis ligula sit amet eleifend pede libero\"\n  },\n  {\n    \"id\": 139,\n    \"msg\": \"est quam pharetra magna ac consequat metus sapien ut nunc vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae mauris viverra diam vitae quam suspendisse\"\n  },\n  {\n    \"id\": 140,\n    \"msg\": \"luctus et ultrices posuere cubilia curae mauris viverra diam vitae quam suspendisse potenti nullam porttitor lacus at\"\n  },\n  {\n    \"id\": 141,\n    \"msg\": \"id consequat in consequat ut nulla sed accumsan felis ut at dolor quis odio consequat varius integer ac\"\n  },\n  {\"id\": 142, \"msg\": \"pulvinar sed nisl nunc rhoncus dui vel sem sed sagittis nam congue risus\"},\n  {\n    \"id\": 143,\n    \"msg\": \"sollicitudin mi sit amet lobortis sapien sapien non mi integer ac neque duis bibendum morbi non quam nec dui luctus rutrum nulla tellus in sagittis dui vel nisl duis ac nibh fusce lacus\"\n  },\n  {\n    \"id\": 144,\n    \"msg\": \"pretium nisl ut volutpat sapien arcu sed augue aliquam erat volutpat in congue etiam justo etiam pretium iaculis justo in hac habitasse platea dictumst etiam faucibus cursus urna ut\"\n  },\n  {\n    \"id\": 145,\n    \"msg\": \"semper porta volutpat quam pede lobortis ligula sit amet eleifend pede libero quis orci nullam molestie nibh in lectus pellentesque at nulla suspendisse potenti cras in purus eu magna vulputate luctus cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus vivamus vestibulum\"\n  },\n  {\n    \"id\": 146,\n    \"msg\": \"est quam pharetra magna ac consequat metus sapien ut nunc vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae mauris viverra diam vitae quam suspendisse potenti nullam porttitor lacus at turpis donec posuere metus vitae ipsum aliquam non mauris morbi non\"\n  },\n  {\n    \"id\": 147,\n    \"msg\": \"varius nulla facilisi cras non velit nec nisi vulputate nonummy maecenas tincidunt lacus at velit vivamus vel nulla eget eros elementum pellentesque\"\n  },\n  {\n    \"id\": 148,\n    \"msg\": \"nulla integer pede justo lacinia eget tincidunt eget tempus vel pede morbi porttitor lorem id ligula suspendisse ornare consequat lectus in est risus auctor sed tristique in tempus sit amet sem fusce consequat nulla nisl nunc nisl duis bibendum felis sed interdum venenatis turpis enim blandit\"\n  },\n  {\n    \"id\": 149,\n    \"msg\": \"metus arcu adipiscing molestie hendrerit at vulputate vitae nisl aenean lectus pellentesque eget nunc donec quis orci eget\"\n  },\n  {\n    \"id\": 150,\n    \"msg\": \"turpis sed ante vivamus tortor duis mattis egestas metus aenean fermentum donec ut mauris eget massa tempor convallis nulla neque libero convallis eget eleifend luctus ultricies eu nibh quisque id justo sit amet sapien dignissim vestibulum vestibulum ante ipsum primis in faucibus orci luctus et ultrices\"\n  },\n  {\n    \"id\": 151,\n    \"msg\": \"sapien urna pretium nisl ut volutpat sapien arcu sed augue aliquam erat volutpat in congue etiam justo etiam pretium iaculis justo in hac\"\n  },\n  {\n    \"id\": 152,\n    \"msg\": \"duis faucibus accumsan odio curabitur convallis duis consequat dui nec nisi volutpat eleifend donec ut dolor morbi vel lectus in quam fringilla rhoncus mauris enim leo rhoncus sed vestibulum sit amet cursus id\"\n  },\n  {\"id\": 153, \"msg\": \"eleifend pede libero quis orci nullam molestie nibh in lectus pellentesque\"},\n  {\"id\": 154, \"msg\": \"aliquet ultrices erat tortor sollicitudin mi sit amet lobortis sapien sapien non mi\"},\n  {\n    \"id\": 155,\n    \"msg\": \"interdum in ante vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae duis faucibus accumsan odio curabitur convallis duis consequat dui nec nisi volutpat eleifend donec ut dolor morbi vel lectus in quam fringilla rhoncus mauris enim leo\"\n  },\n  {\n    \"id\": 156,\n    \"msg\": \"natoque penatibus et magnis dis parturient montes nascetur ridiculus mus vivamus vestibulum sagittis sapien cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus\"\n  },\n  {\n    \"id\": 157,\n    \"msg\": \"augue aliquam erat volutpat in congue etiam justo etiam pretium iaculis justo in hac habitasse platea dictumst etiam faucibus cursus urna ut\"\n  },\n  {\n    \"id\": 158,\n    \"msg\": \"tincidunt nulla mollis molestie lorem quisque ut erat curabitur gravida nisi at nibh in hac habitasse platea dictumst aliquam augue quam sollicitudin vitae consectetuer eget rutrum at lorem integer tincidunt ante vel ipsum praesent\"\n  },\n  {\n    \"id\": 159,\n    \"msg\": \"elit ac nulla sed vel enim sit amet nunc viverra dapibus nulla suscipit ligula in lacus curabitur at\"\n  },\n  {\n    \"id\": 160,\n    \"msg\": \"curae mauris viverra diam vitae quam suspendisse potenti nullam porttitor lacus at turpis donec posuere metus vitae ipsum aliquam non mauris morbi non lectus aliquam sit amet diam in magna bibendum imperdiet nullam orci pede\"\n  },\n  {\n    \"id\": 161,\n    \"msg\": \"quisque ut erat curabitur gravida nisi at nibh in hac habitasse platea dictumst aliquam augue quam sollicitudin vitae consectetuer eget rutrum at lorem integer tincidunt ante vel ipsum praesent blandit lacinia erat vestibulum sed magna at nunc commodo placerat praesent blandit nam nulla integer pede justo lacinia eget\"\n  },\n  {\n    \"id\": 162,\n    \"msg\": \"nisl duis ac nibh fusce lacus purus aliquet at feugiat non pretium quis lectus suspendisse potenti in eleifend quam a odio in hac habitasse platea dictumst maecenas ut massa quis augue luctus\"\n  },\n  {\"id\": 163, \"msg\": \"aliquam non mauris morbi non lectus aliquam sit amet diam in magna bibendum imperdiet\"},\n  {\n    \"id\": 164,\n    \"msg\": \"in tempor turpis nec euismod scelerisque quam turpis adipiscing lorem vitae mattis nibh ligula nec sem duis aliquam convallis nunc proin at turpis a pede posuere nonummy integer non velit donec diam neque vestibulum eget vulputate ut ultrices vel\"\n  },\n  {\n    \"id\": 165,\n    \"msg\": \"augue vel accumsan tellus nisi eu orci mauris lacinia sapien quis libero nullam sit amet turpis elementum ligula vehicula consequat morbi a ipsum integer a nibh in quis justo maecenas rhoncus aliquam\"\n  },\n  {\n    \"id\": 166,\n    \"msg\": \"turpis donec posuere metus vitae ipsum aliquam non mauris morbi non lectus aliquam sit amet diam in magna bibendum imperdiet nullam orci pede venenatis non sodales sed tincidunt eu felis fusce posuere felis sed\"\n  },\n  {\n    \"id\": 167,\n    \"msg\": \"tristique est et tempus semper est quam pharetra magna ac consequat metus sapien ut nunc vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae mauris viverra diam vitae quam suspendisse potenti nullam porttitor lacus at turpis donec posuere metus vitae ipsum aliquam non mauris morbi non\"\n  },\n  {\n    \"id\": 168,\n    \"msg\": \"lectus suspendisse potenti in eleifend quam a odio in hac habitasse platea dictumst maecenas ut massa quis augue luctus tincidunt nulla mollis molestie lorem quisque ut erat curabitur gravida nisi at nibh in hac habitasse platea dictumst aliquam augue quam sollicitudin vitae consectetuer eget rutrum at lorem integer tincidunt ante\"\n  },\n  {\"id\": 169, \"msg\": \"lectus suspendisse potenti in eleifend quam a odio in hac habitasse\"},\n  {\n    \"id\": 170,\n    \"msg\": \"eget tincidunt eget tempus vel pede morbi porttitor lorem id ligula suspendisse ornare consequat lectus in est risus auctor sed tristique in tempus sit amet sem fusce consequat nulla nisl nunc nisl duis bibendum felis sed interdum venenatis turpis enim\"\n  },\n  {\n    \"id\": 171,\n    \"msg\": \"non lectus aliquam sit amet diam in magna bibendum imperdiet nullam orci pede venenatis non sodales sed tincidunt eu felis fusce posuere felis sed lacus morbi sem mauris laoreet ut rhoncus aliquet pulvinar sed nisl nunc rhoncus dui vel sem sed sagittis nam congue risus semper porta volutpat\"\n  },\n  {\n    \"id\": 172,\n    \"msg\": \"curabitur gravida nisi at nibh in hac habitasse platea dictumst aliquam augue quam sollicitudin vitae consectetuer eget rutrum at lorem integer tincidunt ante vel ipsum praesent\"\n  },\n  {\n    \"id\": 173,\n    \"msg\": \"luctus et ultrices posuere cubilia curae donec pharetra magna vestibulum aliquet ultrices erat tortor sollicitudin mi sit amet lobortis sapien sapien non mi integer ac neque duis bibendum morbi non quam nec dui luctus rutrum nulla tellus in sagittis dui vel nisl duis ac nibh fusce\"\n  },\n  {\"id\": 174, \"msg\": \"lectus in est risus auctor sed tristique in tempus sit amet sem fusce consequat nulla\"},\n  {\n    \"id\": 175,\n    \"msg\": \"nullam sit amet turpis elementum ligula vehicula consequat morbi a ipsum integer a nibh in quis justo maecenas rhoncus aliquam lacus morbi quis tortor id nulla ultrices aliquet maecenas leo\"\n  },\n  {\n    \"id\": 176,\n    \"msg\": \"vestibulum ac est lacinia nisi venenatis tristique fusce congue diam id ornare imperdiet sapien urna pretium nisl ut volutpat sapien arcu sed augue aliquam erat volutpat in congue etiam justo etiam pretium iaculis justo in hac habitasse platea dictumst etiam faucibus cursus urna ut tellus nulla ut\"\n  },\n  {\n    \"id\": 177,\n    \"msg\": \"sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus etiam vel augue vestibulum rutrum rutrum neque aenean auctor gravida sem praesent id massa id nisl venenatis lacinia\"\n  },\n  {\n    \"id\": 178,\n    \"msg\": \"ut tellus nulla ut erat id mauris vulputate elementum nullam varius nulla facilisi cras non velit nec nisi vulputate nonummy maecenas tincidunt lacus at velit vivamus vel nulla\"\n  },\n  {\n    \"id\": 179,\n    \"msg\": \"aenean auctor gravida sem praesent id massa id nisl venenatis lacinia aenean sit amet justo morbi ut odio cras mi pede malesuada in imperdiet et commodo vulputate justo in blandit ultrices enim lorem ipsum dolor sit amet consectetuer adipiscing elit proin interdum mauris non ligula pellentesque ultrices phasellus id\"\n  },\n  {\n    \"id\": 180,\n    \"msg\": \"nec molestie sed justo pellentesque viverra pede ac diam cras pellentesque volutpat dui maecenas tristique est et tempus semper est quam pharetra magna ac consequat metus sapien ut nunc vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae mauris viverra\"\n  },\n  {\n    \"id\": 181,\n    \"msg\": \"mus vivamus vestibulum sagittis sapien cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus etiam vel augue vestibulum rutrum\"\n  },\n  {\n    \"id\": 182,\n    \"msg\": \"ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae nulla dapibus dolor vel est donec odio justo sollicitudin ut suscipit a feugiat et eros vestibulum ac est lacinia nisi venenatis tristique fusce congue diam id ornare imperdiet sapien urna pretium\"\n  },\n  {\n    \"id\": 183,\n    \"msg\": \"venenatis turpis enim blandit mi in porttitor pede justo eu massa donec dapibus duis at velit eu est congue elementum in hac habitasse platea dictumst morbi vestibulum velit id pretium iaculis diam erat fermentum justo nec condimentum neque sapien placerat ante nulla justo aliquam quis\"\n  },\n  {\n    \"id\": 184,\n    \"msg\": \"ultrices justns phasellus id sapien in sapien iaculis congue vivamus metus arcu adipiscing molestie hendrerit at vulputate vitae nisl aenean lectus pellentesque eget nunc donec\"\n  },\n  {\n    \"id\": 185,\n    \"msg\": \"pede jusnt malesuada in imperdiet et commodo vulputate justo in blandit ultrices enim lorem ipsum dolor sit amet consectetuer adipiscing elit proin interdum mauris non ligula pellentesque ultrices phasellus id\"\n  },\n  {\n    \"id\": 186,\n    \"msg\": \"lorem justn ipsum dolor sit amet consectetuer adipiscing elit proin interdum mauris non ligula pellentesque ultrices phasellus id sapien in sapien iaculis congue vivamus metus arcu adipiscing molestie hendrerit at vulputate vitae\"\n  },\n  {\n    \"id\": 187,\n    \"msg\": \"congue ous risus semper porta volutpat quam pede lobortis ligula sit amet eleifend pede libero quis orci nullam molestie nibh in lectus pellentesque at nulla suspendisse potenti cras in purus eu magna vulputate luctus cum sociis natoque penatibus et magnis dis\"\n  },\n  {\n    \"id\": 188,\n    \"msg\": \"in felis jsu eu sapien cursus vestibulum proin eu mi nulla ac enim in tempor turpis nec euismod scelerisque quam turpis adipiscing lorem vitae mattis nibh ligula nec sem duis aliquam convallis nunc proin at turpis a pede posuere nonummy integer non velit donec diam neque vestibulum eget vulputate\"\n  },\n  {\n    \"id\": 189,\n    \"msg\": \"est justo quam pharetra magna ac consequat metus sapien ut nunc vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae mauris viverra diam vitae\"\n  },\n  {\n    \"id\": 190,\n    \"msg\": \"a suscipit jus nulla elit ac nulla sed vel enim sit amet nunc viverra dapibus nulla suscipit ligula in lacus curabitur at ipsum ac\"\n  },\n  {\n    \"id\": 191,\n    \"msg\": \"et magnis xus dis parturient montes nascetur ridiculus mus etiam vel augue vestibulum rutrum rutrum neque aenean auctor gravida sem praesent id massa id nisl venenatis lacinia aenean sit amet justo morbi ut odio cras mi pede malesuada in imperdiet et commodo\"\n  },\n  {\n    \"id\": 192,\n    \"msg\": \"lacus eu morbi sem mauris laoreet ut rhoncus aliquet pulvinar sed nisl nunc rhoncus dui vel sem sed sagittis nam congue risus semper porta volutpat quam pede lobortis ligula sit amet eleifend pede libero quis orci nullam molestie nibh in lectus pellentesque at nulla suspendisse\"\n  },\n  {\n    \"id\": 193,\n    \"msg\": \"massa usx donec dapibus duis at velit eu est congue elementum in hac habitasse platea dictumst morbi vestibulum velit id pretium iaculis diam erat fermentum justo nec condimentum neque sapien placerat ante nulla justo aliquam quis turpis eget elit sodales scelerisque\"\n  },\n  {\n    \"id\": 194,\n    \"msg\": \"convallis js js jus nunc proin at turpis a pede posuere nonummy integer non velit donec diam neque vestibulum eget vulputate ut ultrices vel augue vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere\"\n  },\n  {\n    \"id\": 195,\n    \"msg\": \"augue luctus us tincidunt nulla mollis molestie lorem quisque ut erat curabitur gravida nisi at nibh in hac habitasse platea\"\n  },\n  {\"id\": 196, \"msg\": \"proin leo odio porttitor id consequat in consequat ut nulla sed accumsan\"},\n  {\n    \"id\": 197,\n    \"msg\": \"ut rhoncus just aliquet pulvinar sed nisl nunc rhoncus dui vel sem sed sagittis nam congue risus semper porta volutpat quam pede lobortis ligula sit amet eleifend pede libero quis orci nullam molestie nibh in lectus pellentesque at nulla suspendisse potenti cras\"\n  },\n  {\n    \"id\": 198,\n    \"msg\": \"donec semper jur sapien a libero nam dui proin leo odio porttitor id consequat in consequat ut nulla sed accumsan felis ut at dolor quis odio consequat\"\n  },\n  {\n    \"id\": 199,\n    \"msg\": \"pede jt massa donec dapibus duis at velit eu Est congue elementum in hac habitasse platea dictumst morbi vestibulum velit id pretium iaculis diam erat\"\n  },\n  {\n    \"id\": 200,\n    \"msg\": \"sagittis jut dui vel nisl duis ac nibh fusce lacus purus aliquet at feugiat non pretium quis lectus suspendisse potenti in eleifend quam\"\n  },\n  {\n    \"id\": 201,\n    \"msg\": \"\"\n  },\n  {\n    \"id\": 202,\n    \"msg\": null\n  },\n  {\n    \"id\": 203,\n    \"msg\": undefined\n  },\n  {\n    \"id\": 204,\n  },\n  {\n    \"id\": 205,\n    \"msg\": 123\n  },\n];\n"
  },
  {
    "path": "packages/full-text-search/spec/node/QUERIES.ts",
    "content": "import { QueryTypes } from \"../../src/query_types\";\n\nconst FIELD_NAME_1 = \"msg\";\n\nexport const QUERIES: { fts: QueryTypes, es: any, empty?: boolean, focus?: boolean }[] = [\n  {\n    fts: {\n      type: \"term\",\n      field: FIELD_NAME_1,\n      value: \"sollicitudin\"\n    },\n    es: {\n      term: {\n        [FIELD_NAME_1]: \"sollicitudin\"\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"constant_score\",\n      boost: 2.45,\n      filter: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"sollicitudin\",\n        }\n      ]\n    },\n    es: {\n      constant_score: {\n        filter: {\n          term: {\n            [FIELD_NAME_1]: \"sollicitudin\"\n          }\n        },\n        boost: 2.45\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"fuzzy\",\n      field: FIELD_NAME_1,\n      value: \"a\"\n    },\n    es: {\n      fuzzy: {\n        [FIELD_NAME_1]: {\n          value: \"a\",\n          transpositions: true\n        }\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"fuzzy\",\n      field: FIELD_NAME_1,\n      value: \"este\"\n    },\n    es: {\n      fuzzy: {\n        [FIELD_NAME_1]: {\n          value: \"este\",\n          transpositions: true\n        }\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"fuzzy\",\n      field: FIELD_NAME_1,\n      value: \"est\",\n      prefix_length: 3\n    },\n    es: {\n      fuzzy: {\n        [FIELD_NAME_1]: {\n          value: \"est\",\n          prefix_length: 3,\n          transpositions: true\n        }\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"fuzzy\",\n      field: FIELD_NAME_1,\n      value: \"ege\",\n      prefix_length: 3,\n      fuzziness: 2\n    },\n    es: {\n      fuzzy: {\n        [FIELD_NAME_1]: {\n          value: \"ege\",\n          prefix_length: 3,\n          fuzziness: 2,\n          transpositions: true\n        }\n      }\n    },\n    empty: true\n  },\n  {\n    fts: {\n      type: \"fuzzy\",\n      field: FIELD_NAME_1,\n      value: \"est\",\n      fuzziness: 0\n    },\n    es: {\n      fuzzy: {\n        [FIELD_NAME_1]: {\n          value: \"est\",\n          fuzziness: 0,\n          transpositions: true\n        }\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"fuzzy\",\n      field: FIELD_NAME_1,\n      value: \"just\",\n      fuzziness: 2\n    },\n    es: {\n      fuzzy: {\n        [FIELD_NAME_1]: {\n          value: \"just\",\n          fuzziness: 2,\n          transpositions: true\n        }\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"fuzzy\",\n      field: FIELD_NAME_1,\n      value: \"jus\",\n      fuzziness: 1\n    },\n    es: {\n      fuzzy: {\n        [FIELD_NAME_1]: {\n          value: \"jus\",\n          fuzziness: 1,\n          transpositions: true\n        }\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"fuzzy\",\n      field: FIELD_NAME_1,\n      value: \"jus\",\n      fuzziness: 2,\n      prefix_length: 1\n    },\n    es: {\n      fuzzy: {\n        [FIELD_NAME_1]: {\n          value: \"jus\",\n          fuzziness: 2,\n          prefix_length: 1,\n          transpositions: true\n        }\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"fuzzy\",\n      field: FIELD_NAME_1,\n      value: \"js\",\n      fuzziness: 2\n    },\n    es: {\n      fuzzy: {\n        [FIELD_NAME_1]: {\n          value: \"js\",\n          fuzziness: 2,\n          prefix_length: 0,\n          transpositions: true\n        }\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"fuzzy\",\n      field: FIELD_NAME_1,\n      value: \"js\",\n      fuzziness: 2,\n      boost: 5\n    },\n    es: {\n      fuzzy: {\n        [FIELD_NAME_1]: {\n          value: \"js\",\n          fuzziness: 2,\n          prefix_length: 0,\n          transpositions: true,\n          boost: 5\n        }\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"wildcard\",\n      field: FIELD_NAME_1,\n      value: \"a?\"\n    },\n    es: {\n      wildcard: {\n        [FIELD_NAME_1]: {\n          value: \"a?\"\n        }\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"wildcard\",\n      field: FIELD_NAME_1,\n      value: \"a?\",\n      enable_scoring: true\n    },\n    es: {\n      wildcard: {\n        [FIELD_NAME_1]: {\n          value: \"a?\",\n          rewrite: \"scoring_boolean\"\n        }\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"wildcard\",\n      field: FIELD_NAME_1,\n      value: \"so*\"\n    },\n    es: {\n      wildcard: {\n        [FIELD_NAME_1]: {\n          value: \"so*\"\n        }\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"wildcard\",\n      field: FIELD_NAME_1,\n      value: \"so*n\"\n    },\n    es: {\n      wildcard: {\n        [FIELD_NAME_1]: {\n          value: \"so*n\"\n        }\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"wildcard\",\n      field: FIELD_NAME_1,\n      value: \"e*t\"\n    },\n    es: {\n      wildcard: {\n        [FIELD_NAME_1]: {\n          value: \"e*t\"\n        }\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"term\",\n      boost: 2,\n      field: FIELD_NAME_1,\n      value: \"sollicitudin\"\n    },\n    es: {\n      term: {\n        [FIELD_NAME_1]: {\n          value: \"sollicitudin\",\n          boost: 2\n        }\n      }\n    }\n  },\n  {\n    fts: {type: \"match_all\"},\n    es: {\n      match_all: {}\n    }\n  },\n  {\n    fts: {\n      type: \"exists\",\n      field: FIELD_NAME_1\n    },\n    es: {\n      exists: {\n        \"field\": FIELD_NAME_1\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"prefix\",\n      boost: 3.5,\n      field: FIELD_NAME_1,\n      value: \"es\"\n    },\n    es: {\n      prefix: {\n        [FIELD_NAME_1]: {\n          value: \"es\",\n          boost: 3.5\n        },\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"prefix\",\n      field: FIELD_NAME_1,\n      value: \"es\",\n      enable_scoring: true\n    },\n    es: {\n      prefix: {\n        [FIELD_NAME_1]: {\n          value: \"es\",\n          rewrite: \"scoring_boolean\"\n        },\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"bool\",\n      must: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"a\",\n          boost: 2\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"ac\"\n        }\n      ],\n      boost: 10\n    },\n    es: {\n      bool: {\n        must: [\n          {\n            term: {\n              [FIELD_NAME_1]: {\n                value: \"a\",\n                boost: 2\n              }\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"ac\"\n            }\n          }\n        ],\n        boost: 10\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"bool\",\n      must: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"a\"\n        },\n        {\n          type: \"fuzzy\",\n          field: FIELD_NAME_1,\n          value: \"just\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"ac\"\n        }\n      ]\n    },\n    es: {\n      bool: {\n        must: [\n          {\n            term: {\n              [FIELD_NAME_1]: \"a\"\n            }\n          },\n          {\n            fuzzy: {\n              [FIELD_NAME_1]: \"just\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"ac\"\n            }\n          }\n        ]\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"bool\",\n      must: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"a\"\n        },\n        {\n          type: \"wildcard\",\n          field: FIELD_NAME_1,\n          value: \"j*\",\n          enable_scoring: true\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"ac\"\n        }\n      ]\n    },\n    es: {\n      bool: {\n        must: [\n          {\n            term: {\n              [FIELD_NAME_1]: \"a\"\n            }\n          },\n          {\n            wildcard: {\n              [FIELD_NAME_1]: {\n                value: \"j*\",\n                rewrite: \"scoring_boolean\"\n              }\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"ac\"\n            }\n          }\n        ]\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"bool\",\n      must: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"est\"\n        }\n      ],\n      not: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"ac\"\n        }\n      ]\n    },\n    es: {\n      bool: {\n        must: [\n          {\n            term: {\n              [FIELD_NAME_1]: \"est\"\n            }\n          }\n        ],\n        must_not: [\n          {\n            term: {\n              [FIELD_NAME_1]: \"ac\"\n            }\n          }\n        ]\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"bool\",\n      must: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"abc\"\n        }\n      ],\n      not: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"ac\"\n        }\n      ]\n    },\n    es: {\n      bool: {\n        must: [\n          {\n            term: {\n              [FIELD_NAME_1]: \"abc\"\n            }\n          }\n        ],\n        must_not: [\n          {\n            term: {\n              [FIELD_NAME_1]: \"ac\"\n            }\n          }\n        ]\n      }\n    },\n    empty: true\n  },\n  {\n    fts: {\n      type: \"bool\",\n      must: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"est\"\n        }\n      ],\n      filter: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"ac\"\n        }\n      ]\n    },\n    es: {\n      bool: {\n        must: [\n          {\n            term: {\n              [FIELD_NAME_1]: \"est\"\n            }\n          }\n        ],\n        filter: [\n          {\n            term: {\n              [FIELD_NAME_1]: \"ac\"\n            }\n          }\n        ]\n      }\n    },\n  },\n  {\n    fts: {\n      type: \"bool\",\n      filter: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"ac\"\n        }\n      ]\n    },\n    es: {\n      bool: {\n        filter: [\n          {\n            term: {\n              [FIELD_NAME_1]: \"ac\"\n            }\n          }\n        ]\n      }\n    },\n  },\n  {\n    fts: {\n      type: \"bool\",\n      must: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"est\"\n        }\n      ],\n      should: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"ac\"\n        }\n      ]\n    },\n    es: {\n      bool: {\n        must: [\n          {\n            term: {\n              [FIELD_NAME_1]: \"est\"\n            }\n          }\n        ],\n        should: [\n          {\n            term: {\n              [FIELD_NAME_1]: \"ac\"\n            }\n          }\n        ]\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"bool\",\n      should: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"ac\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"enim\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"est\"\n        }\n      ],\n      minimum_should_match: 2\n    },\n    es: {\n      bool: {\n        should: [\n          {\n            term: {\n              [FIELD_NAME_1]: \"ac\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"enim\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"est\"\n            }\n          }\n        ],\n        minimum_should_match: 2,\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"bool\",\n      should: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"ac\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"enim\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"est\"\n        }\n      ],\n      minimum_should_match: -2\n    },\n    es: {\n      bool: {\n        should: [\n          {\n            term: {\n              [FIELD_NAME_1]: \"ac\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"enim\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"est\"\n            }\n          }\n        ],\n        minimum_should_match: -2\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"bool\",\n      should: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"ac\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"enim\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"est\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"at\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"sed\"\n        },\n      ],\n      minimum_should_match: \"75%\"\n    },\n    es: {\n      bool: {\n        should: [\n          {\n            term: {\n              [FIELD_NAME_1]: \"ac\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"enim\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"est\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"at\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"sed\"\n            }\n          }\n        ],\n        minimum_should_match: \"75%\",\n      }\n    },\n  },\n  {\n    fts: {\n      type: \"bool\",\n      should: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"ac\",\n          boost: 10\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"enim\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"est\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"at\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"sed\"\n        },\n      ],\n      minimum_should_match: \"-25%\"\n    },\n    es: {\n      bool: {\n        should: [\n          {\n            term: {\n              [FIELD_NAME_1]: {\n                value: \"ac\",\n                boost: 10\n              }\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"enim\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"est\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"at\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"sed\"\n            }\n          }\n        ],\n        minimum_should_match: \"-25%\",\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"bool\",\n      should: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"ac\",\n          boost: 10\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"enim\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"est\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"at\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"sed\"\n        },\n      ],\n      minimum_should_match: \"3<50%\"\n    },\n    es: {\n      bool: {\n        should: [\n          {\n            term: {\n              [FIELD_NAME_1]: {\n                value: \"ac\",\n                boost: 10\n              }\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"enim\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"est\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"at\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"sed\"\n            }\n          }\n        ],\n        minimum_should_match: \"3<50%\",\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"bool\",\n      should: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"ac\",\n          boost: 10\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"enim\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"est\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"at\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"sed\"\n        },\n      ],\n      minimum_should_match: \"2<-2\"\n    },\n    es: {\n      bool: {\n        should: [\n          {\n            term: {\n              [FIELD_NAME_1]: {\n                value: \"ac\",\n                boost: 10\n              }\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"enim\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"est\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"at\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"sed\"\n            }\n          }\n        ],\n        minimum_should_match: \"2<-2\",\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"bool\",\n      should: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"ac\",\n          boost: 10\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"enim\"\n        }\n      ],\n      minimum_should_match: \"2<50%\"\n    },\n    es: {\n      bool: {\n        should: [\n          {\n            term: {\n              [FIELD_NAME_1]: {\n                value: \"ac\",\n                boost: 10\n              }\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"enim\"\n            }\n          },\n        ],\n        minimum_should_match: \"2<50%\",\n      }\n    },\n  },\n  {\n    fts: {\n      type: \"bool\",\n      should: [\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"ac\",\n          boost: 10\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"enim\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"est\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"at\"\n        },\n        {\n          type: \"term\",\n          field: FIELD_NAME_1,\n          value: \"sed\"\n        },\n      ],\n      minimum_should_match: \"3<50% 4<-4\"\n    },\n    es: {\n      bool: {\n        should: [\n          {\n            term: {\n              [FIELD_NAME_1]: {\n                value: \"ac\",\n                boost: 10\n              }\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"enim\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"est\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"at\"\n            }\n          },\n          {\n            term: {\n              [FIELD_NAME_1]: \"sed\"\n            }\n          }\n        ],\n        minimum_should_match: \"3<50% 4<-4\",\n      }\n    },\n  },\n  {\n    fts: {\n      type: \"bool\",\n      must: [{\n        type: \"match_all\"\n      }],\n      not: [{\n        type: \"term\",\n        field: FIELD_NAME_1,\n        value: \"ac\"\n      }],\n    },\n    es: {\n      bool: {\n        must: [\n          {\n            match_all: {}\n          }\n        ],\n        must_not: [\n          {\n            term: {\n              [FIELD_NAME_1]: \"ac\"\n            }\n          }\n        ]\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"bool\",\n      boost: 2,\n      not: [{\n        type: \"term\",\n        field: FIELD_NAME_1,\n        value: \"ac\"\n      }],\n    },\n    es: {\n      bool: {\n        must_not: [\n          {\n            term: {\n              [FIELD_NAME_1]: \"ac\"\n            }\n          }\n        ],\n        boost: 2\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"bool\",\n      boost: 2,\n    },\n    es: {\n      bool: {\n        boost: 2\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"bool\",\n      must: [{\n        type: \"term\",\n        field: FIELD_NAME_1,\n        value: \"ac\"\n      }],\n      should: [{\n        type: \"constant_score\",\n        filter: [{\n          type: \"wildcard\",\n          field: FIELD_NAME_1,\n          value: \"a?\"\n        }]\n      }],\n    },\n    es: {\n      bool: {\n        must: [\n          {\n            term: {\n              [FIELD_NAME_1]: \"ac\"\n            }\n          }\n        ],\n        should: [\n          {\n            constant_score: {\n              filter: {\n                wildcard: {\n                  [FIELD_NAME_1]: \"a?\"\n                }\n              }\n            }\n          }\n        ]\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"match\",\n      field: FIELD_NAME_1,\n      value: \"orci habitasse eget\"\n    },\n    es: {\n      match: {\n        [FIELD_NAME_1]: \"orci habitasse eget\"\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"match\",\n      field: FIELD_NAME_1,\n      value: \"orci habitasse eget\",\n      operator: \"and\"\n    },\n    es: {\n      match: {\n        [FIELD_NAME_1]: {\n          query: \"orci habitasse eget\",\n          operator: \"and\"\n        }\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"match\",\n      field: FIELD_NAME_1,\n      value: \"orca este\",\n      fuzziness: \"AUTO\"\n    },\n    es: {\n      match: {\n        [FIELD_NAME_1]: {\n          query: \"orca este\",\n          fuzziness: \"AUTO\"\n        }\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"match\",\n      field: FIELD_NAME_1,\n      value: \"orci est\",\n      operator: \"and\"\n    },\n    es: {\n      match: {\n        [FIELD_NAME_1]: {\n          query: \"orci est\",\n          operator:\n            \"and\"\n        }\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"match\",\n      field: FIELD_NAME_1,\n      value: \"orci est in\",\n      minimum_should_match: \"33%\"\n    },\n    es: {\n      match: {\n        [FIELD_NAME_1]: {\n          query: \"orci est in\",\n          minimum_should_match: \"33%\"\n        }\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"match\",\n      field: FIELD_NAME_1,\n      value: \"orci est in\",\n      boost: 10,\n    },\n    es: {\n      match: {\n        [FIELD_NAME_1]: {\n          query: \"orci est in\",\n          boost: 10\n        }\n      }\n    }\n  },\n  {\n    fts: {\n      type: \"wildcard\",\n      field: FIELD_NAME_1,\n      value: \"1?3\"\n    },\n    es: {\n      wildcard: {\n        [FIELD_NAME_1]: {\n          value: \"1?3\"\n        }\n      }\n    }\n  },\n];\n"
  },
  {
    "path": "packages/full-text-search/spec/node/elasticsearch.spec.ts",
    "content": "/* global describe, it, expect, beforeEach */\nimport { DATA } from \"./MOCK_DATA\";\nimport { QUERIES } from \"./QUERIES\";\nimport { FullTextSearch } from \"../../src/full_text_search\";\nimport { Client } from \"elasticsearch\";\nimport { Scorer } from \"../../src/scorer\";\nimport { Analyzer } from \"../../src/analyzer/analyzer\";\nimport { whitespaceTokenizer } from \"../../src/analyzer/tokenizer\";\nimport { lowercaseTokenFilter } from \"../../src/analyzer/token_filter\";\n\nconst INDEX_NAME = \"test_index\";\nconst INDEX_TYPE = \"MockUp\";\nconst FIELD_NAME_1 = \"msg\";\n\nfunction fieldLengthES5(fieldLength: number) {\n  // Lucene 5 uses a SmallFloat (size of 1 byte) to store the field length in scoring.\n  // This is useless in javascript, because every number is represented as a double (8 byte).\n  // To align the scoring result with lucene, this calculation is still needed.\n  // Lucene also includes the field boost, but field boost is deprecated and not supported by Loki.\n\n  // Find closest value in array.\n  const lockUp = [1, 1.30612242, 1.77777779, 2.55999994, 4, 5.22448969, 7.11111116, 10.2399998, 16, 20.8979588,\n    28.4444447, 40.9599991, 64, 83.591835, 113.777779, 163.839996, 256, 334.36734, 455.111115, 655.359985, 1024,\n    1337.46936, 1820.44446, 2621.43994, 4096, 5349.87744, 7281.77783, 10485.7598, 16384, 21399.5098, 29127.1113,\n    41943.0391, 65536, 85598.0391, 116508.445, 167772.156, 262144, 342392.156, 466033.781, 671088.625, 1048576,\n    1369568.62, 1864135.12, 2684354.5, 4194304, 5478274.5, 7456540.5, 10737418, 16777216, 21913098, 29826162,\n    42949672, 67108864, 87652392, 119304648, 171798688, 268435456, 350609568, 477218592, 687194752];\n\n  for (let i = 0; i < lockUp.length; i++) {\n    if (lockUp[i] >= fieldLength) {\n      return lockUp[i];\n    }\n  }\n  throw RangeError(\"Unsupported field length.\");\n}\n\nfunction fieldLengthES6(fieldLength: number) {\n  // Lucene 6 uses a SmallInteger (size of 1 byte) to store the field length in scoring.\n  // This is useless in javascript, because every number is represented as a double (8 byte).\n  // To align the scoring result with lucene, this calculation is still needed.\n  // Lucene also includes the field boost, but field boost is deprecated and not supported by Loki.\n\n  function leading(value: number) {\n    let result = 0; //could be a char or int8_t instead\n    if (value) {//this assumes the value is 64bit\n      if (0xFFFFFFFF00000000 & value) {\n        value >>= (1 << 5);\n        result |= (1 << 5);\n      }//if it is 32bit then remove this line\n      if (0x00000000FFFF0000 & value) {\n        value >>= (1 << 4);\n        result |= (1 << 4);\n      }//and remove the 32msb\n      if (0x000000000000FF00 & value) {\n        value >>= (1 << 3);\n        result |= (1 << 3);\n      }\n      if (0x00000000000000F0 & value) {\n        value >>= (1 << 2);\n        result |= (1 << 2);\n      }\n      if (0x000000000000000C & value) {\n        value >>= (1 << 1);\n        result |= (1 << 1);\n      }\n      if (0x0000000000000002 & value) {\n        result |= (1 << 0);\n      }\n    } else {\n      result = -1;\n    }\n    return 64 - result - 1;\n  }\n\n  function longToInt4(i: number) {\n    let numBits = 64 - leading(i);\n    if (numBits < 4) {\n      // subnormal value\n      return i;\n    } else {\n      // normal value\n      let shift = numBits - 4;\n      // only keep the 5 most significant bits\n      let encoded = (i >>> shift);\n      // clear the most significant bit, which is implicit\n      encoded &= 0x07;\n      // encode the shift, adding 1 because 0 is reserved for subnormal values\n      encoded |= (shift + 1) << 3;\n      return encoded;\n    }\n  }\n\n  function int4ToLong(i: number) {\n    let bits = i & 0x07;\n    let shift = (i >> 3) - 1;\n    let decoded;\n    if (shift === -1) {\n      // subnormal value\n      decoded = bits;\n    } else {\n      // normal value\n      decoded = (bits | 0x08) << shift;\n    }\n    return decoded;\n  }\n\n  const MAX_INT4 = longToInt4(Math.pow(2, 31) - 1);\n  const NUM_FREE_VALUES = 255 - MAX_INT4;\n\n  function intToByte4(i: number) {\n    if (i < NUM_FREE_VALUES) {\n      return i;\n    } else {\n      return (NUM_FREE_VALUES + longToInt4(i - NUM_FREE_VALUES));\n    }\n  }\n\n  function byte4ToInt(b: number) {\n    let i = b;\n    if (i < NUM_FREE_VALUES) {\n      return i;\n    } else {\n      return NUM_FREE_VALUES + int4ToLong(i - NUM_FREE_VALUES);\n    }\n  }\n\n  return byte4ToInt(intToByte4(fieldLength));\n}\n\ndescribe(\"Compare scoring against elasticsearch\", () => {\n\n  let client = new Client({\n    host: \"localhost:9200\",\n    log: \"error\"\n  });\n\n  // Flag to skip tests if elasticsearch is not available.\n  let es_not_available = false;\n\n  let fts = initFTS();\n  let es = initES();\n\n  beforeEach((done) => {\n    if (es_not_available) {\n      es.catch(() => {});\n      done();\n      return;\n    }\n    es.then(() => {\n      return client.info({});\n    }).then((body: any) => {\n      // Select correct field length function.\n      if (body.version.number.startsWith(\"5\")) {\n        Scorer[\"_calculateFieldLength\"] = fieldLengthES5;\n      } else {\n        Scorer[\"_calculateFieldLength\"] = fieldLengthES6;\n      }\n      done();\n    });\n  });\n\n  for (let i = 0; i < QUERIES.length; i++) {\n    let query = QUERIES[i];\n    (query.focus ? fit : it)(\" -> \" + i + \": \" + JSON.stringify(query), (done) => {\n      if (es_not_available) {\n        done();\n        return;\n      }\n      client.search({\n        index: INDEX_NAME,\n        type: INDEX_TYPE,\n        searchType: \"dfs_query_then_fetch\",\n        body: {\n          explain: true,\n          \"size\": 10000,\n          query: query.es\n        }\n      })\n        .then((body: any) => {\n          // Compare results with loki.\n          let esHits = body.hits.hits;\n          let ftsHits = fts.search({query: query.fts, explain: true});\n          let ftsHitDocs = Object.keys(ftsHits);\n\n          // Compare hit length.\n          expect(esHits.length).toEqual(ftsHitDocs.length);\n          if (esHits.length !== ftsHitDocs.length) {\n            done();\n            return;\n          }\n\n          // Check if esHits should be empty.\n          if (query.empty === true) {\n            expect(esHits.length).toEqual(0);\n            done();\n            return;\n          } else if (esHits.length === 0) {\n            expect(esHits.length).not.toEqual(0);\n            done();\n            return;\n          }\n\n          for (let j = 0; j < ftsHitDocs.length; j++) {\n            if (esHits[j] === undefined) {\n              fail(\"Missmatching documents:\" + ftsHitDocs[j]);\n              expect(false).toBe(true);\n            }\n            let esID = esHits[j]._id;\n            expect(ftsHits).toHaveMember(esID);\n            if (!ftsHits.hasOwnProperty(esID)) {\n              continue;\n            }\n\n            expect(ftsHits[esID].score).toBeCloseTo(esHits[j]._score, 4);\n          }\n          done();\n        })\n        .catch((e) => {\n          fail(e);\n          done();\n        });\n    });\n  }\n\n\n  function initES() {\n    // Reset client.\n    return client.indices.delete({\n      index: INDEX_NAME\n    }).then(create, create);\n\n\n    function create() {\n      // Add documents.\n      return client.indices.create({\n        index: INDEX_NAME,\n        body: {\n          mappings: {\n            [INDEX_TYPE]: {\n              properties: {\n                [FIELD_NAME_1]: {\n                  type: \"text\",\n                  index_options: \"freqs\",\n                  analyzer: \"my_analyzer\"\n                },\n              }\n            }\n          },\n          settings: {\n            number_of_shards: 1,\n            number_of_replicas: 1,\n            analysis: {\n              analyzer: {\n                my_analyzer: {\n                  type: \"standard\",\n                  stopwords: [\"habitasse\", \"morbi\"]\n                }\n              }\n            }\n          }\n        }\n      }).then(() => {\n        let createAction = (data: any) => client.index({\n          index: INDEX_NAME,\n          type: INDEX_TYPE,\n          id: data.id,\n          body: data\n        });\n        return Promise.all(DATA.map(createAction)).then(() => {\n          return client.indices.refresh({index: INDEX_NAME});\n        });\n      }).catch((e) => {\n        if (e.message === \"No Living connections\") {\n          es_not_available = true;\n        }\n      });\n    }\n  }\n\n  function initFTS() {\n    let myAnalyzer: Analyzer = {\n      tokenizer: whitespaceTokenizer,\n      token_filter: [lowercaseTokenFilter, (token) => (token !== \"habitasse\" && token !== \"morbi\") ? token : \"\"]\n    };\n\n    let fts = new FullTextSearch([{\n      field: FIELD_NAME_1,\n      analyzer: myAnalyzer\n    }], \"$loki\");\n\n    // Add documents.\n    for (let i = 0; i < DATA.length; i++) {\n      fts.addDocument({\n        $loki: DATA[i].id,\n        [FIELD_NAME_1]: DATA[i][FIELD_NAME_1]\n      });\n    }\n    return fts;\n  }\n});\n"
  },
  {
    "path": "packages/full-text-search/src/analyzer/analyzer.ts",
    "content": "import { CharacterFilter } from \"./character_filter\";\nimport { Tokenizer, whitespaceTokenizer } from \"./tokenizer\";\nimport { lowercaseTokenFilter, TokenFilter } from \"./token_filter\";\n\n/**\n * A analyzer converts a string into tokens which are added to the inverted index for searching.\n */\nexport interface Analyzer {\n  /**\n   * The character filters of the analyzer.\n   */\n  char_filter?: CharacterFilter[];\n  /**\n   * The tokenizer of the analyzer.\n   */\n  tokenizer: Tokenizer;\n  /**\n   * The token filters of the analyzer.\n   */\n  token_filter?: TokenFilter[];\n}\n\n/**\n * Analyzes a given string.\n * @param {Analyzer} analyzer - the analyzer\n * @param {string} str - the string\n * @returns {string[]} - the tokens\n */\nexport function analyze(analyzer: Analyzer, str: string): string[] {\n  if (analyzer.char_filter) {\n    for (let j = 0; j < analyzer.char_filter.length; j++) {\n      str = analyzer.char_filter[j](str);\n    }\n  }\n  const tokens = analyzer.tokenizer(str);\n  if (analyzer.token_filter) {\n    for (let i = 0; i < tokens.length; i++) {\n      for (let k = 0; k < analyzer.token_filter.length; k++) {\n        tokens[i] = analyzer.token_filter[k](tokens[i], i, tokens);\n      }\n    }\n  }\n  // Remove empty tokens.\n  return tokens.filter((token) => token);\n}\n\n/**\n * An analyzer with the whitespace tokenizer and the lowercase token filter.\n */\nexport class StandardAnalyzer implements Analyzer {\n  tokenizer = whitespaceTokenizer;\n  token_filter = [lowercaseTokenFilter];\n}\n"
  },
  {
    "path": "packages/full-text-search/src/analyzer/character_filter.ts",
    "content": "/**\n * A character filter is used to preprocess a string before it is passed to a tokenizer.\n */\nexport type CharacterFilter = (value: string) => string;\n\n\n"
  },
  {
    "path": "packages/full-text-search/src/analyzer/token_filter.ts",
    "content": "/**\n * A token filter takes tokens from a tokenizer and modify, delete or add tokens.\n */\nexport type TokenFilter = (value: string, index: number, array: string[]) => string;\n\n/**\n * Converts a token to lowercase.\n * @param {string} token - the token\n * @returns {string} - the lowercased token\n */\nexport function lowercaseTokenFilter(token: string): string {\n  return token.toLowerCase();\n}\n\n/**\n * Converts a token to uppercase.\n * @param {string} token - the token\n * @returns {string} - the uppercased token\n */\nexport function uppercaseTokenFilter(token: string): string {\n  return token.toUpperCase();\n}\n"
  },
  {
    "path": "packages/full-text-search/src/analyzer/tokenizer.ts",
    "content": "/**\n * A tokenizer splits a string into individual tokens.\n */\nexport type Tokenizer = (value: string) => string[];\n\n/**\n * Splits a string at whitespace characters into tokens.\n * @param {string} value - the string\n * @returns {string[]} - the tokens\n */\nexport function whitespaceTokenizer(value: string): string[] {\n  return value.split(/[\\s]+/);\n}\n\n"
  },
  {
    "path": "packages/full-text-search/src/full_text_search.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { IndexSearcher } from \"./index_searcher\";\nimport { Dict } from \"../../common/types\";\nimport { PLUGINS } from \"../../common/plugin\";\nimport { Query } from \"./query_types\";\nimport { Scorer } from \"./scorer\";\nimport { Analyzer } from \"./analyzer/analyzer\";\n\nexport class FullTextSearch {\n  /// The id field of each document.\n  private _id: string;\n  /// Set of ids of all indexed documents.\n  private _docs: Set<InvertedIndex.DocumentIndex>;\n  private _idxSearcher: IndexSearcher;\n  private _invIdxs: Dict<InvertedIndex> = {};\n\n  /**\n   * Registers the full-text search as plugin.\n   */\n  public static register(): void {\n    PLUGINS[\"FullTextSearch\"] = FullTextSearch;\n  }\n\n  /**\n   * Initialize the full-text search for the given fields.\n   * @param {object[]} fieldOptions - the field options\n   * @param {string} fieldOptions.field - the name of the property field\n   * @param {boolean=true} fieldOptions.store - flag to indicate if the full-text search should be stored on serialization or\n   *  rebuild on deserialization\n   * @param {boolean=true} fieldOptions.optimizeChanges - flag to optimize updating and deleting of documents\n   *    (requires more memory but performs faster)\n   * @param {Analyzer} fieldOptions.analyzer - an analyzer for the field\n   * @param {string} [id] - the property name of the document index\n   */\n  constructor(fieldOptions: FullTextSearch.FieldOptions[] = [], id?: string) {\n    // Create an inverted index for each field.\n    for (let i = 0; i < fieldOptions.length; i++) {\n      let fieldOption = fieldOptions[i];\n      this._invIdxs[fieldOption.field] = new InvertedIndex(fieldOption);\n    }\n    this._id = id;\n    this._docs = new Set();\n    this._idxSearcher = new IndexSearcher(this._invIdxs, this._docs);\n  }\n\n  public addDocument(doc: object, id: InvertedIndex.DocumentIndex = doc[this._id]): void {\n    let fieldNames = Object.keys(this._invIdxs);\n    for (let i = 0, fieldName; i < fieldNames.length, fieldName = fieldNames[i]; i++) {\n      let field = doc[fieldName];\n      // Skip null and undefined.\n      if (field === null || field === undefined) {\n        continue;\n      }\n      if (typeof field !== \"string\") {\n        // Convert number to string.\n        if (typeof field === \"number\") {\n          field = field.toString();\n        } else {\n          throw TypeError(\"Unsupported field type for full text search.\");\n        }\n      }\n      this._invIdxs[fieldName].insert(field, id);\n    }\n    this._docs.add(id);\n    this._idxSearcher.setDirty();\n  }\n\n  public removeDocument(doc: object, id: InvertedIndex.DocumentIndex = doc[this._id]): void {\n    let fieldNames = Object.keys(this._invIdxs);\n    for (let i = 0; i < fieldNames.length; i++) {\n      this._invIdxs[fieldNames[i]].remove(id);\n    }\n    this._docs.delete(id);\n    this._idxSearcher.setDirty();\n  }\n\n  public updateDocument(doc: object, id: InvertedIndex.DocumentIndex = doc[this._id]): void {\n    this.removeDocument(doc, id);\n    this.addDocument(doc, id);\n  }\n\n  public clear(): void {\n    for (let id of this._docs) {\n      this.removeDocument(null, id);\n    }\n  }\n\n  public search(query: Query): Scorer.ScoreResults {\n    return this._idxSearcher.search(query);\n  }\n\n  public toJSON(): FullTextSearch.Serialization {\n    let serialized = {id: this._id, ii: {}};\n    let fieldNames = Object.keys(this._invIdxs);\n    for (let i = 0; i < fieldNames.length; i++) {\n      const fieldName = fieldNames[i];\n      serialized.ii[fieldName] = this._invIdxs[fieldName].toJSON();\n    }\n    return serialized;\n  }\n\n  public static fromJSONObject(serialized: FullTextSearch.Serialization, analyzers: Dict<Analyzer> = {}): FullTextSearch {\n    let fts = new FullTextSearch([], serialized.id);\n    let fieldNames = Object.keys(serialized.ii);\n    for (let i = 0; i < fieldNames.length; i++) {\n      const fieldName = fieldNames[i];\n      fts._invIdxs[fieldName] = InvertedIndex.fromJSONObject(serialized.ii[fieldName], analyzers[fieldName]);\n    }\n    return fts;\n  }\n}\n\nexport namespace FullTextSearch {\n  export interface FieldOptions extends InvertedIndex.FieldOptions {\n    field: string;\n  }\n\n  export interface Serialization {\n    id: string;\n    ii: Dict<InvertedIndex.Serialization>;\n  }\n}\n"
  },
  {
    "path": "packages/full-text-search/src/fuzzy/automaton.ts",
    "content": "/**\n * Transition with dest, min and max.\n * @hidden\n */\nexport declare type Transition = [number, number, number];\n\n/**\n * @type {number}\n * @hidden\n */\nexport const MIN_CODE_POINT = 0;\n/**\n * @type {number}\n * @hidden\n */\nexport const MAX_CODE_POINT = 1114111;\n\nfunction sortByDestMinMax(a: Transition, b: Transition) {\n  if (a[0] < b[0]) {\n    return -1;\n  } else if (a[0] > b[0]) {\n    return 1;\n  }\n  if (a[1] < b[1]) {\n    return -1;\n  } else if (a[1] > b[1]) {\n    return 1;\n  }\n  if (a[2] < b[2]) {\n    return -1;\n  } else if (a[2] > b[2]) {\n    return 1;\n  }\n  return 0;\n}\n\nfunction sortByMinMaxDest(a: Transition, b: Transition) {\n  if (a[1] < b[1]) {\n    return -1;\n  } else if (a[1] > b[1]) {\n    return 1;\n  }\n  if (a[2] < b[2]) {\n    return -1;\n  } else if (a[2] > b[2]) {\n    return 1;\n  }\n  if (a[0] < b[0]) {\n    return -1;\n  } else if (a[0] > b[0]) {\n    return 1;\n  }\n  return 0;\n}\n\n/**\n * From org/apache/lucene/util/automaton/Automaton.java\n * @hidden\n */\nexport class Automaton {\n  private _stateTransitions: Transition[] = [];\n  private _accept: Set<number>;\n  private _nextState: number;\n  private _currState: number;\n  // public deterministic: boolean;\n  private _transitions: object;\n\n  constructor() {\n    this._stateTransitions = [];\n    this._accept = new Set();\n    this._nextState = 0;\n    this._currState = -1;\n    // this.deterministic = true;\n    this._transitions = {};\n  }\n\n  public isAccept(n: number): boolean {\n    return this._accept.has(n);\n  }\n\n  public createState(): number {\n    return this._nextState++;\n  }\n\n  public setAccept(state: number, accept: boolean): void {\n    if (accept) {\n      this._accept.add(state);\n    } else {\n      this._accept.delete(state);\n    }\n  }\n\n  public finishState(): void {\n    if (this._currState !== -1) {\n      this._finishCurrentState();\n      this._currState = -1;\n    }\n  }\n\n  private _finishCurrentState(): void {\n    // Sort all transitions.\n    this._stateTransitions.sort(sortByDestMinMax);\n\n    let upto = 0;\n    let p: Transition = [-1, -1, -1];\n\n    for (let i = 0, len = this._stateTransitions.length; i < len; i++) {\n      let t = this._stateTransitions[i];\n      if (p[0] === t[0]) {\n        if (t[1] <= p[2] + 1) {\n          if (t[2] > p[2]) {\n            p[2] = t[2];\n          }\n        } else {\n          if (p[0] !== -1) {\n            this._stateTransitions[upto][0] = p[0];\n            this._stateTransitions[upto][1] = p[1];\n            this._stateTransitions[upto][2] = p[2];\n            upto++;\n          }\n          p[1] = t[1];\n          p[2] = t[2];\n        }\n      } else {\n        if (p[0] !== -1) {\n          this._stateTransitions[upto][0] = p[0];\n          this._stateTransitions[upto][1] = p[1];\n          this._stateTransitions[upto][2] = p[2];\n          upto++;\n        }\n        p[0] = t[0];\n        p[1] = t[1];\n        p[2] = t[2];\n      }\n    }\n\n    if (p[0] !== -1) {\n      // Last transition\n      this._stateTransitions[upto][0] = p[0];\n      this._stateTransitions[upto][1] = p[1];\n      this._stateTransitions[upto][2] = p[2];\n      upto++;\n    }\n\n    this._transitions[this._currState] = this._stateTransitions.slice(0, upto).sort(sortByMinMaxDest);\n\n    // if (this.deterministic && upto > 1) {\n    //   let lastMax = this.stateTransitions[0][2];\n    //   for (let i = 1; i < upto; i++) {\n    //     let min = this.stateTransitions[i][1];\n    //     if (min <= lastMax) {\n    //       this.deterministic = false;\n    //       break;\n    //     }\n    //     lastMax = this.stateTransitions[i][2];\n    //   }\n    // }\n\n    this._stateTransitions = [];\n  }\n\n  public getStartPoints(): number[] {\n    const pointset = new Set();\n    pointset.add(MIN_CODE_POINT);\n\n    const states = Object.keys(this._transitions);\n    for (let i = 0; i < states.length; i++) {\n      let trans = this._transitions[states[i]];\n      for (let j = 0; j < trans.length; j++) {\n        let tran = trans[j];\n        pointset.add(tran[1]);\n        if (tran[2] < MAX_CODE_POINT) {\n          pointset.add(tran[2] + 1);\n        }\n      }\n    }\n    return Array.from(pointset).sort((a, b) => a - b);\n  }\n\n  public step(state: number, label: number): number {\n    let trans = this._transitions[state];\n    if (trans) {\n      for (let i = 0; i < trans.length; i++) {\n        let tran = trans[i];\n        if (tran[1] <= label && label <= tran[2]) {\n          return tran[0];\n        }\n      }\n    }\n    return -1;\n  }\n\n  public getNumStates(): number {\n    return this._nextState;\n  }\n\n  public addTransition(source: number, dest: number, min: number, max: number): void {\n    if (this._currState !== source) {\n      if (this._currState !== -1) {\n        this._finishCurrentState();\n      }\n      this._currState = source;\n    }\n    this._stateTransitions.push([dest, min, max]);\n  }\n}\n"
  },
  {
    "path": "packages/full-text-search/src/fuzzy/lev1t_parametric_description.ts",
    "content": "import { Long } from \"./long\";\nimport { ParametricDescription } from \"./parametric_description\";\n\n// 1 vectors; 2 states per vector; array length = 2\nconst toStates0 = [new Long(0x2)];\nconst offsetIncrs0 = [new Long(0x0)];\n\n// 2 vectors; 3 states per vector; array length = 6\nconst toStates1 = [new Long(0xa43)];\n\nconst offsetIncrs1 = [new Long(0x38)];\n\n// 4 vectors; 6 states per vector; array length = 24\nconst toStates2 = [new Long(0x82140003, 0x34534914), new Long(0x6d)];\nconst offsetIncrs2 = [new Long(0x55a20000, 0x5555)];\n\n// 8 vectors; 6 states per vector; array length = 48\nconst toStates3 = [new Long(0x900C0003, 0x21520854), new Long(0x4534916d, 0x5b4d19a2), new Long(0xda34)];\nconst offsetIncrs3 = [new Long(0x20fc0000, 0x5555ae0a), new Long(0x55555555)];\n\n// state map\n//   0 -> [(0, 0)]\n//   1 -> [(0, 1)]\n//   2 -> [(0, 1), (1, 1)]\n//   3 -> [(0, 1), (2, 1)]\n//   4 -> [t(0, 1), (0, 1), (1, 1), (2, 1)]\n//   5 -> [(0, 1), (1, 1), (2, 1)]\n\n/**\n * From org/apache/lucene/util/automaton/Lev1TParametricDescription.java\n * @hidden\n */\nexport class Lev1TParametricDescription extends ParametricDescription {\n  constructor(w: number) {\n    super(w, 1, [0, 1, 0, -1, -1, -1]);\n  }\n\n  public transition(absState: number, position: number, vector: number): number {\n    // null absState should never be passed in\n    //assert absState != -1;\n\n    // decode absState -> state, offset\n    let state = Math.floor(absState / (this._w + 1));\n    let offset = absState % (this._w + 1);\n    //assert offset >= 0;\n\n    if (position === this._w) {\n      if (state < 2) {\n        const loc = vector * 2 + state;\n        offset += ParametricDescription.unpack(offsetIncrs0, loc, 1);\n        state = ParametricDescription.unpack(toStates0, loc, 2) - 1;\n      }\n    } else if (position === this._w - 1) {\n      if (state < 3) {\n        const loc = vector * 3 + state;\n        offset += ParametricDescription.unpack(offsetIncrs1, loc, 1);\n        state = ParametricDescription.unpack(toStates1, loc, 2) - 1;\n      }\n    } else if (position === this._w - 2) {\n      if (state < 6) {\n        const loc = vector * 6 + state;\n        offset += ParametricDescription.unpack(offsetIncrs2, loc, 2);\n        state = ParametricDescription.unpack(toStates2, loc, 3) - 1;\n      }\n    } else {\n      if (state < 6) {\n        const loc = vector * 6 + state;\n        offset += ParametricDescription.unpack(offsetIncrs3, loc, 2);\n        state = ParametricDescription.unpack(toStates3, loc, 3) - 1;\n      }\n    }\n\n    if (state === -1) {\n      // null state\n      return -1;\n    } else {\n      // translate back to abs\n      return state * (this._w + 1) + offset;\n    }\n  }\n}\n"
  },
  {
    "path": "packages/full-text-search/src/fuzzy/lev2t_parametric_description.ts",
    "content": "import { Long } from \"./long\";\nimport { ParametricDescription } from \"./parametric_description\";\n\n// 1 vectors; 3 states per vector; array length = 3\nconst toStates0 = /*2 bits per value */ [\n  new Long(0x23)\n];\nconst offsetIncrs0 = /*1 bits per value */ [\n  new Long(0x0)\n];\n\n// 2 vectors; 5 states per vector; array length = 10\nconst toStates1 = /*3 bits per value */ [\n  new Long(0x13688b44)\n];\nconst offsetIncrs1 = /*1 bits per value */ [\n  new Long(0x3e0)\n];\n\n// 4 vectors; 13 states per vector; array length = 52\nconst toStates2 = /*4 bits per value */ [\n  new Long(0x5200b504, 0x60dbb0b0), new Long(0x27062227, 0x52332176), new Long(0x14323235, 0x23555432), new Long(0x4354)\n];\nconst offsetIncrs2 = /*2 bits per value */ [\n  new Long(0x00002000, 0x555080a8), new Long(0x55555555, 0x55)\n];\n\n// 8 vectors; 28 states per vector; array length = 224\nconst toStates3 = /*5 bits per value */ [\n  new Long(0x40059404, 0xe701c029), new Long(0x00a50000, 0xa0101620), new Long(0xa1416288, 0xb02c8c40), new Long(0x310858c0, 0xa821032),\n  new Long(0x0d28b201, 0x31442398), new Long(0x847788e0, 0x5281e528), new Long(0x08c2280e, 0xa23980d3), new Long(0xa962278c, 0x1e3294b1),\n  new Long(0x2288e528, 0x8c41309e), new Long(0x021aca21, 0x11444409), new Long(0x86b1086b, 0x11a46248), new Long(0x1d6240c4, 0x2a625894),\n  new Long(0x489074ad, 0x5024a50b), new Long(0x520c411a, 0x14821aca), new Long(0x0b594a44, 0x5888b589), new Long(0xc411a465, 0x941d6520),\n  new Long(0xad6a62d4, 0x8b589075), new Long(0x1a5055a4)\n];\nconst offsetIncrs3 = /*2 bits per value */ [\n  new Long(0x00002000, 0x30c302), new Long(0xc3fc333c, 0x2a0030f3), new Long(0x8282a820, 0x233a0032), new Long(0x32b283a8, 0x55555555),\n  new Long(0x55555555, 0x55555555), new Long(0x55555555, 0x55555555), new Long(0x55555555, 0x55555555)\n];\n\n// 16 vectors; 45 states per vector; array length = 720\nconst toStates4 = /*6 bits per value */ [\n  new Long(0x002c5004, 0x3801450), new Long(0x00000e38, 0xc500014b), new Long(0x51401402, 0x514), new Long(0x0),\n  new Long(0x14010000, 0x518000b), new Long(0x28e20230, 0x9f1c208), new Long(0x830a70c2, 0x219f0df0), new Long(0x08208200, 0x82000082),\n  new Long(0x60800800, 0x8050501), new Long(0x02602643, 0x30820986), new Long(0x50508064, 0x45640142), new Long(0x20000831, 0x8500514),\n  new Long(0x85002082, 0x41405820), new Long(0x0990c201, 0x45618098), new Long(0x50a01051, 0x8316d0c), new Long(0x050df0e0, 0x21451420),\n  new Long(0x14508214, 0xd142140), new Long(0x50821c60, 0x3c21c018), new Long(0xcb142087, 0x1cb1403), new Long(0x1851822c, 0x80082145),\n  new Long(0x20800020, 0x200208), new Long(0x87180345, 0xd0061820), new Long(0x24976b09, 0xcb0a81cb), new Long(0x624709d1, 0x8b1a60e),\n  new Long(0x82249089, 0x2490820), new Long(0x00d2c024, 0xc31421c6), new Long(0x15454423, 0x3c314515), new Long(0xc21cb140, 0x31853c22),\n  new Long(0x2c208214, 0x4514500b), new Long(0x508b0051, 0x8718034), new Long(0x5108f0c5, 0xb2cb4551), new Long(0x1cb0a810, 0xe824715d),\n  new Long(0x908b0e60, 0x1422cb14), new Long(0xc02cb145, 0x30812c22), new Long(0x0cb1420c, 0x84202202), new Long(0x20ce0850, 0x5c20ce08),\n  new Long(0x8b0d70c2, 0x20820820), new Long(0x14214208, 0x42085082), new Long(0x50830c20, 0x9208340), new Long(0x13653592, 0xc6134dc6),\n  new Long(0x6dc4db4d, 0xd309341c), new Long(0x54d34d34, 0x6424d908), new Long(0x030814c2, 0x92072c22), new Long(0x24a30930, 0x4220724b),\n  new Long(0x25c920e2, 0x2470d720), new Long(0x975c9082, 0x92c92d70), new Long(0x04924e08, 0xcb0880c2), new Long(0xc24c2481, 0x45739728),\n  new Long(0xda6174da, 0xc6da4db5), new Long(0x5d30971d, 0x4b5d35d7), new Long(0x93825ce2, 0x1030815c), new Long(0x020cb145, 0x51442051),\n  new Long(0x2c220e2c, 0xc538210e), new Long(0x52cb0d70, 0x8514214), new Long(0x85145142, 0x204b0850), new Long(0x4051440c, 0x92156083),\n  new Long(0xa60e6595, 0x4d660e4d), new Long(0x1c6dc658, 0x94d914e4), new Long(0x1454d365, 0x82642659), new Long(0x51030813, 0x2892072c),\n  new Long(0xcb2ca30b, 0xe2c22072), new Long(0x20538910, 0x452c70d7), new Long(0x708e3891, 0x8b2cb2d), new Long(0xc204b24e, 0x81cb1440),\n  new Long(0x28c2ca24, 0xda44e38e), new Long(0x85d660e4, 0x1dc6da65), new Long(0x8e5d914e, 0xe2cb5d33), new Long(0x38938238)\n];\nconst offsetIncrs4 = /*3 bits per value */ [\n  new Long(0x00080000, 0x30020000), new Long(0x20c060), new Long(0x04000000, 0x81490000), new Long(0x10824824, 0x40249241),\n  new Long(0x60002082, 0xdb6030c3), new Long(0x301b0d80, 0x6c36c06c), new Long(0x000db0db, 0xb01861b0), new Long(0x9188e06d, 0x1b703620),\n  new Long(0x06d86db7, 0x8009200), new Long(0x02402490, 0x4920c24), new Long(0x08249009, 0x490002), new Long(0x28124804, 0x49081281),\n  new Long(0x124a44a2, 0x34800104), new Long(0x0d24020c, 0xc3093090), new Long(0x24c24d24, 0x40009a09), new Long(0x9201061a, 0x4984a06),\n  new Long(0x71269262, 0x494d0492), new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249),\n  new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924),\n  new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492),\n  new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249),\n  new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x2492)\n];\n\n// 32 vectors; 45 states per vector; array length = 1440\nconst toStates5 = /*6 bits per value */ [\n  new Long(0x002c5004, 0x3801450), new Long(0x00000e38, 0xc500014b), new Long(0x51401402, 0x514), new Long(0x0),\n  new Long(0x14010000, 0x514000b), new Long(0x038e00e0, 0x550000), new Long(0x0600b180, 0x26451850), new Long(0x08208208, 0x82082082),\n  new Long(0x40820820, 0x2c500), new Long(0x808c0146, 0x70820a38), new Long(0x9c30827c, 0xc37c20c2), new Long(0x20800867, 0x208208),\n  new Long(0x02002080, 0xb1401020), new Long(0x00518000, 0x828e2023), new Long(0x209f1c20, 0x830a70c), new Long(0x853df0df, 0x51451450),\n  new Long(0x14508214, 0x16142142), new Long(0x30805050, 0x60260264), new Long(0x43082098, 0x25050806), new Long(0x14564014, 0x42000083),\n  new Long(0x20850051, 0x8500208), new Long(0x14140582, 0x80990c20), new Long(0x08261809, 0x82019202), new Long(0x90060941, 0x8920519),\n  new Long(0xc22cb242, 0x22492492), new Long(0x0162492c, 0x43080505), new Long(0x86026026, 0x80414515), new Long(0xc5b43142, 0x37c38020),\n  new Long(0x14508014, 0x42085085), new Long(0x50850051, 0x1414058), new Long(0x980990c2, 0x51456180), new Long(0x0c50a010, 0xe008316d),\n  new Long(0x508b21f0, 0x2c52cb2c), new Long(0xc22cb249, 0x600d2c92), new Long(0x1850821c, 0x873c21c0), new Long(0x03cb1420, 0x2c01cb14),\n  new Long(0x45185182, 0x20800821), new Long(0x08208000, 0x45002002), new Long(0x20871803, 0x8700614), new Long(0x050821cf, 0x740500f5),\n  new Long(0x18609000, 0x934d9646), new Long(0x30824d30, 0x4c24d34d), new Long(0xc600d642, 0x1860821), new Long(0x25dac274, 0xc2a072c9),\n  new Long(0x91c27472, 0x2c698398), new Long(0x89242242, 0x92420820), new Long(0x34b00900, 0x82087180), new Long(0xb09d0061, 0x1cb24976),\n  new Long(0x9d1cb0a8, 0x60e62470), new Long(0x1574ce3e, 0xd31455d7), new Long(0x25c25d74, 0x1c600d38), new Long(0x423c3142, 0x51515454),\n  new Long(0x1403c314, 0xc22c21cb), new Long(0x21431853, 0xb2c208), new Long(0x05145145, 0x34508b0), new Long(0x0c508718, 0x5515108f),\n  new Long(0xf2051454, 0x8740500), new Long(0x0618f090, 0xe2534d92), new Long(0x6592c238, 0x49382659), new Long(0x21c600d6, 0x4423c314),\n  new Long(0xcb2d1545, 0x72c2a042), new Long(0xa091c574, 0x422c3983), new Long(0x508b2c52, 0xb2c514), new Long(0x8034b08b, 0xf0c50871),\n  new Long(0x45515108, 0xa810b2cb), new Long(0x715d1cb0, 0x2260e824), new Long(0x8e2d74ce, 0xe6592c53), new Long(0x38938238, 0x420c3081),\n  new Long(0x22020cb1, 0x8508420), new Long(0xce0820ce, 0x70c25c20), new Long(0x08208b0d, 0x42082082), new Long(0x50821421, 0xc204208),\n  new Long(0x832c5083, 0x21080880), new Long(0x0838c214, 0xa5083882), new Long(0xa9c39430, 0xaaaaaaaa), new Long(0x9fa9faaa, 0x1aaa7eaa),\n  new Long(0x1420c308, 0x824820d0), new Long(0x84d94d64, 0x7184d371), new Long(0x1b7136d3, 0x34c24d07), new Long(0x1534d34d, 0x99093642),\n  new Long(0x30c20530, 0x8340508), new Long(0x53592092, 0x34dc6136), new Long(0x4db4dc61, 0xa479c6dc), new Long(0x4924924a, 0x920a9f92),\n  new Long(0x8192a82a, 0x72c22030), new Long(0x30930920, 0x724b24a), new Long(0x920e2422, 0xd72025c), new Long(0xc9082247, 0x92d70975),\n  new Long(0x24e0892c, 0x880c2049), new Long(0xc2481cb0, 0x2c928c24), new Long(0x89088749, 0x80a52488), new Long(0xaac74394, 0x6a861b2a),\n  new Long(0xab27b278, 0x81b2ca6), new Long(0x072c2203, 0xa3093092), new Long(0x6915ce5c, 0xd76985d3), new Long(0x771b6936, 0x5d74c25c),\n  new Long(0x892d74d7, 0x724e0973), new Long(0x0880c205, 0x4c2481cb), new Long(0x739728c2, 0x6174da45), new Long(0xda4db5da, 0x4aa175c6),\n  new Long(0x86486186, 0x6a869b27), new Long(0x308186ca, 0xcb14510), new Long(0x44205102, 0x220e2c51), new Long(0x38210e2c, 0xcb0d70c5),\n  new Long(0x51421452, 0x14514208), new Long(0x4b085085, 0x51440c20), new Long(0x1440832c, 0xcb145108), new Long(0x488b0888, 0x94316208),\n  new Long(0x9f7e79c3, 0xfaaa7dfa), new Long(0x7ea7df7d, 0x30819ea), new Long(0x20d01451, 0x65648558), new Long(0x93698399, 0x96135983),\n  new Long(0x39071b71, 0xd9653645), new Long(0x96451534, 0x4e09909), new Long(0x051440c2, 0x21560834), new Long(0x60e65959, 0xd660e4da),\n  new Long(0xc6dc6584, 0x9207e979), new Long(0xdf924820, 0xa82a8207), new Long(0x103081a6, 0x892072c5), new Long(0xb2ca30b2, 0x2c22072c),\n  new Long(0x0538910e, 0x52c70d72), new Long(0x08e38914, 0x8b2cb2d7), new Long(0x204b24e0, 0x1cb1440c), new Long(0x8c2ca248, 0x874b2cb2),\n  new Long(0x24488b08, 0x43948162), new Long(0x9b1f7e77, 0x9e786aa6), new Long(0xeca6a9e7, 0x51030819), new Long(0x2892072c, 0x8e38a30b),\n  new Long(0x83936913, 0x69961759), new Long(0x4538771b, 0x74ce3976), new Long(0x08e38b2d, 0xc204e24e), new Long(0x81cb1440, 0x28c2ca24),\n  new Long(0xda44e38e, 0x85d660e4), new Long(0x75c6da65, 0x698607e9), new Long(0x99e7864a, 0xa6ca6aa6)\n];\nconst offsetIncrs5 = /*3 bits per value */ [\n  new Long(0x00080000, 0x30020000), new Long(0x20c060), new Long(0x04000000, 0x1000000), new Long(0x50603018, 0xdb6db6db),\n  new Long(0x00002db6, 0xa4800002), new Long(0x41241240, 0x12492088), new Long(0x00104120, 0x40000100), new Long(0x92092052, 0x2492c420),\n  new Long(0x096592d9, 0xc30d800), new Long(0xc36036d8, 0xb01b0c06), new Long(0x6c36db0d, 0x186c0003), new Long(0xb01b6c06, 0xad860361),\n  new Long(0x5b6dd6dd, 0x360001b7), new Long(0x0db6030c, 0xc412311c), new Long(0xb6e36e06, 0xdb0d), new Long(0xdb01861b, 0x9188e06),\n  new Long(0x71b72b62, 0x6dd6db), new Long(0x00800920, 0x40240249), new Long(0x904920c2, 0x20824900), new Long(0x40049000, 0x12012480),\n  new Long(0xa4906120, 0x5524ad4a), new Long(0x02480015, 0x40924020), new Long(0x48409409, 0x92522512), new Long(0x24000820, 0x49201001),\n  new Long(0x204a04a0, 0x29128924), new Long(0x00055549, 0x900830d2), new Long(0x24c24034, 0x934930c), new Long(0x02682493, 0x4186900),\n  new Long(0x61201a48, 0x9a498612), new Long(0x355249d4, 0xc348001), new Long(0x940d2402, 0x24c40930), new Long(0x0924e24d, 0x1a40009a),\n  new Long(0x06920106, 0x6204984a), new Long(0x92712692, 0x92494d54), new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924),\n  new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492),\n  new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249),\n  new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924),\n  new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492),\n  new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249),\n  new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924),\n  new Long(0x49249249, 0x92492492), new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492),\n  new Long(0x24924924, 0x49249249), new Long(0x92492492, 0x24924924), new Long(0x49249249, 0x92492492), new Long(0x24924924)\n];\n\n// state map\n//   0 -> [(0, 0)]\n//   1 -> [(0, 2)]\n//   2 -> [(0, 1)]\n//   3 -> [(0, 1), (1, 1)]\n//   4 -> [(0, 2), (1, 2)]\n//   5 -> [t(0, 2), (0, 2), (1, 2), (2, 2)]\n//   6 -> [(0, 2), (2, 1)]\n//   7 -> [(0, 1), (2, 2)]\n//   8 -> [(0, 2), (2, 2)]\n//   9 -> [(0, 1), (1, 1), (2, 1)]\n//   10 -> [(0, 2), (1, 2), (2, 2)]\n//   11 -> [(0, 1), (2, 1)]\n//   12 -> [t(0, 1), (0, 1), (1, 1), (2, 1)]\n//   13 -> [(0, 2), (1, 2), (2, 2), (3, 2)]\n//   14 -> [t(0, 2), (0, 2), (1, 2), (2, 2), (3, 2)]\n//   15 -> [(0, 2), t(1, 2), (1, 2), (2, 2), (3, 2)]\n//   16 -> [(0, 2), (2, 1), (3, 1)]\n//   17 -> [(0, 1), t(1, 2), (2, 2), (3, 2)]\n//   18 -> [(0, 2), (3, 2)]\n//   19 -> [(0, 2), (1, 2), t(1, 2), (2, 2), (3, 2)]\n//   20 -> [t(0, 2), (0, 2), (1, 2), (3, 1)]\n//   21 -> [(0, 1), (1, 1), (3, 2)]\n//   22 -> [(0, 2), (2, 2), (3, 2)]\n//   23 -> [(0, 2), (1, 2), (3, 1)]\n//   24 -> [(0, 2), (1, 2), (3, 2)]\n//   25 -> [(0, 1), (2, 2), (3, 2)]\n//   26 -> [(0, 2), (3, 1)]\n//   27 -> [(0, 1), (3, 2)]\n//   28 -> [(0, 2), (2, 1), (4, 2)]\n//   29 -> [(0, 2), t(1, 2), (1, 2), (2, 2), (3, 2), (4, 2)]\n//   30 -> [(0, 2), (1, 2), (4, 2)]\n//   31 -> [(0, 2), (1, 2), (3, 2), (4, 2)]\n//   32 -> [(0, 2), (2, 2), (3, 2), (4, 2)]\n//   33 -> [(0, 2), (1, 2), t(2, 2), (2, 2), (3, 2), (4, 2)]\n//   34 -> [(0, 2), (1, 2), (2, 2), t(2, 2), (3, 2), (4, 2)]\n//   35 -> [(0, 2), (3, 2), (4, 2)]\n//   36 -> [(0, 2), t(2, 2), (2, 2), (3, 2), (4, 2)]\n//   37 -> [t(0, 2), (0, 2), (1, 2), (2, 2), (4, 2)]\n//   38 -> [(0, 2), (1, 2), (2, 2), (4, 2)]\n//   39 -> [t(0, 2), (0, 2), (1, 2), (2, 2), (3, 2), (4, 2)]\n//   40 -> [(0, 2), (1, 2), (2, 2), (3, 2), (4, 2)]\n//   41 -> [(0, 2), (4, 2)]\n//   42 -> [t(0, 2), (0, 2), (1, 2), (2, 2), t(2, 2), (3, 2), (4, 2)]\n//   43 -> [(0, 2), (2, 2), (4, 2)]\n//   44 -> [(0, 2), (1, 2), t(1, 2), (2, 2), (3, 2), (4, 2)]\n\n/**\n * From org/apache/lucene/util/automaton/Lev2TParametricDescription.java\n * @hidden\n */\nexport class Lev2TParametricDescription extends ParametricDescription {\n  constructor(w: number) {\n    super(w, 2, [0, 2, 1, 0, 1, 0, -1, 0, 0, -1, 0, -1, -1, -1, -1, -1, -2, -1, -1, -1, -2, -1, -1, -2, -1, -1, -2, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2]);\n  }\n\n  public transition(absState: number, position: number, vector: number): number {\n    // null absState should never be passed in\n    // assert absState != -1;\n\n    // decode absState -> state, offset\n    let state = Math.floor(absState / (this._w + 1));\n    let offset = absState % (this._w + 1);\n    // assert offset >= 0;\n\n    if (position === this._w) {\n      if (state < 3) {\n        const loc = vector * 3 + state;\n        offset += ParametricDescription.unpack(offsetIncrs0, loc, 1);\n        state = ParametricDescription.unpack(toStates0, loc, 2) - 1;\n      }\n    } else if (position === this._w - 1) {\n      if (state < 5) {\n        const loc = vector * 5 + state;\n        offset += ParametricDescription.unpack(offsetIncrs1, loc, 1);\n        state = ParametricDescription.unpack(toStates1, loc, 3) - 1;\n      }\n    } else if (position === this._w - 2) {\n      if (state < 13) {\n        const loc = vector * 13 + state;\n        offset += ParametricDescription.unpack(offsetIncrs2, loc, 2);\n        state = ParametricDescription.unpack(toStates2, loc, 4) - 1;\n      }\n    } else if (position === this._w - 3) {\n      if (state < 28) {\n        const loc = vector * 28 + state;\n        offset += ParametricDescription.unpack(offsetIncrs3, loc, 2);\n        state = ParametricDescription.unpack(toStates3, loc, 5) - 1;\n      }\n    } else if (position === this._w - 4) {\n      if (state < 45) {\n        const loc = vector * 45 + state;\n        offset += ParametricDescription.unpack(offsetIncrs4, loc, 3);\n        state = ParametricDescription.unpack(toStates4, loc, 6) - 1;\n      }\n    } else {\n      if (state < 45) {\n        const loc = vector * 45 + state;\n        offset += ParametricDescription.unpack(offsetIncrs5, loc, 3);\n        state = ParametricDescription.unpack(toStates5, loc, 6) - 1;\n      }\n    }\n\n    if (state === -1) {\n      // null state\n      return -1;\n    } else {\n      // translate back to abs\n      return state * (this._w + 1) + offset;\n    }\n  }\n}\n"
  },
  {
    "path": "packages/full-text-search/src/fuzzy/levenshtein_automata.ts",
    "content": "import { Automaton, MAX_CODE_POINT } from \"./automaton\";\nimport { Lev1TParametricDescription } from \"./lev1t_parametric_description\";\nimport { Lev2TParametricDescription } from \"./lev2t_parametric_description\";\n\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java\n * @hidden\n */\nexport class LevenshteinAutomata {\n  private _word: number[];\n  private _numRanges: number;\n  private _rangeLower: number[];\n  private _rangeUpper: number[];\n  private _description: Lev1TParametricDescription;\n  private _alphabet: number[];\n  private _editDistance: number;\n\n  constructor(input: number[], editDistance: number) {\n    this._word = input;\n    this._editDistance = editDistance;\n    this._alphabet = [...new Set(this._word)].sort((a: number, b: number) => a - b);\n\n    this._numRanges = 0;\n    this._rangeLower = new Array(this._alphabet.length + 2);\n    this._rangeUpper = new Array(this._alphabet.length + 2);\n    // calculate the unicode range intervals that exclude the alphabet\n    // these are the ranges for all unicode characters not in the alphabet\n    let lower = 0;\n    for (let i = 0; i < this._alphabet.length; i++) {\n      const higher = this._alphabet[i];\n      if (higher > lower) {\n        this._rangeLower[this._numRanges] = lower;\n        this._rangeUpper[this._numRanges] = higher - 1;\n        this._numRanges++;\n      }\n      lower = higher + 1;\n    }\n    /* add the final endpoint */\n    if (lower <= MAX_CODE_POINT) {\n      this._rangeLower[this._numRanges] = lower;\n      this._rangeUpper[this._numRanges] = MAX_CODE_POINT;\n      this._numRanges++;\n    }\n\n    if (editDistance === 1) {\n      this._description = new Lev1TParametricDescription(input.length);\n    } else {\n      this._description = new Lev2TParametricDescription(input.length);\n    }\n  }\n\n  /**\n   * Transforms the NDFA to a DFA.\n   * @returns {Automaton}\n   */\n  public toAutomaton(): Automaton {\n    let automat = new Automaton();\n    const range = 2 * this._editDistance + 1;\n\n    // the number of states is based on the length of the word and the edit distance\n    const numStates = this._description.size();\n\n    // Prefix is not needed to be handled by the automaton.\n    // stateOffset = 0;\n    automat.createState();\n\n    // create all states, and mark as accept states if appropriate\n    for (let i = 1; i < numStates; i++) {\n      let state = automat.createState();\n      automat.setAccept(state, this._description.isAccept(i));\n    }\n\n    for (let k = 0; k < numStates; k++) {\n      const xpos = this._description.getPosition(k);\n\n      if (xpos < 0) {\n        continue;\n      }\n\n      const end = xpos + Math.min(this._word.length - xpos, range);\n      for (let x = 0; x < this._alphabet.length; x++) {\n        const ch = this._alphabet[x];\n        const cvec = this._getVector(ch, xpos, end);\n        const dest = this._description.transition(k, xpos, cvec);\n\n        if (dest >= 0) {\n          automat.addTransition(k, dest, ch, ch);\n        }\n      }\n\n      const dest = this._description.transition(k, xpos, 0);\n      if (dest >= 0) {\n        for (let r = 0; r < this._numRanges; r++) {\n          automat.addTransition(k, dest, this._rangeLower[r], this._rangeUpper[r]);\n        }\n      }\n    }\n\n    // assert automat.deterministic;\n    automat.finishState();\n\n    return automat;\n  }\n\n  private _getVector(x: number, pos: number, end: number): number {\n    let vector = 0;\n    for (let i = pos; i < end; i++) {\n      vector <<= 1;\n      if (this._word[i] === x) {\n        vector |= 1;\n      }\n    }\n    return vector;\n  }\n}\n"
  },
  {
    "path": "packages/full-text-search/src/fuzzy/long.ts",
    "content": "/**\n * Class supports 64Bit integer operations.\n * A cut-down version of dcodeIO/long.js.\n * @hidden\n */\nexport class Long {\n  private _low: number;\n  private _high: number;\n\n  constructor(low: number = 0, high: number = 0) {\n    this._low = low;\n    this._high = high;\n  }\n\n  /**\n   * Returns this long with bits arithmetically shifted to the right by the given amount.\n   * @param {number} numBits - number of bits\n   * @returns {Long} the long\n   */\n  public shiftRight(numBits: number): Long {\n    if ((numBits &= 63) === 0)\n      return this;\n    else if (numBits < 32)\n      return new Long((this._low >>> numBits) | (this._high << (32 - numBits)), this._high >> numBits);\n    else\n      return new Long((this._high >> (numBits - 32)), this._high >= 0 ? 0 : -1);\n  }\n\n  /**\n   * Returns this long with bits arithmetically shifted to the left by the given amount.\n   * @param {number} numBits - number of bits\n   * @returns {Long} the long\n   */\n  public shiftLeft(numBits: number): Long {\n    if ((numBits &= 63) === 0)\n      return this;\n    else if (numBits < 32)\n      return new Long(this._low << numBits, (this._high << numBits) | (this._low >>> (32 - numBits)));\n    else\n      return new Long(0, this._low << (numBits - 32));\n  }\n\n  /**\n   * Returns the bitwise AND of this Long and the specified.\n   * @param {Long} other - the other Long\n   * @returns {Long} the long\n   */\n  public and(other: Long): Long {\n    return new Long(this._low & other._low, this._high & other._high);\n  }\n\n  /**\n   * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.\n   * @returns {number}\n   */\n  public toInt(): number {\n    return this._low;\n  }\n}\n"
  },
  {
    "path": "packages/full-text-search/src/fuzzy/parametric_description.ts",
    "content": "import { Long } from \"./long\";\n\nconst MASKS = [new Long(0x1), new Long(0x3), new Long(0x7), new Long(0xf),\n  new Long(0x1f), new Long(0x3f), new Long(0x7f), new Long(0xff),\n  new Long(0x1ff), new Long(0x3ff), new Long(0x7ff), new Long(0xfff),\n  new Long(0x1fff), new Long(0x3fff), new Long(0x7fff), new Long(0xffff),\n  new Long(0xf, 0x1fff), new Long(0xf, 0x3fff), new Long(0xf, 0x7fff), new Long(0xf, 0xffff),\n  new Long(0xff, 0x1fff), new Long(0xff, 0x3fff), new Long(0xff, 0x7fff), new Long(0xff, 0xffff),\n  new Long(0xfff, 0x1fff), new Long(0xfff, 0x3fff), new Long(0xfff, 0x7fff), new Long(0xfff, 0xffff),\n  new Long(0xffff, 0x1fff), new Long(0xffff, 0x3fff), new Long(0xffff, 0x7fff), new Long(0xffff, 0xffff),\n  new Long(0xfffff, 0x1fff), new Long(0xfffff, 0x3fff), new Long(0xfffff, 0x7fff), new Long(0xfffff, 0xffff),\n  new Long(0xffffff, 0x1fff), new Long(0xffffff, 0x3fff), new Long(0xffffff, 0x7fff), new Long(0xffffff, 0xffff),\n  new Long(0xfffffff, 0x1fff), new Long(0xfffffff, 0x3fff), new Long(0xfffffff, 0x7fff), new Long(0xfffffff, 0xffff),\n  new Long(0xffffffff, 0x1fff), new Long(0xffffffff, 0x3fff), new Long(0xffffffff, 0x7fff), new Long(0xffffffff, 0xffff),\n  new Long(0xfffffffff, 0x1fff), new Long(0xfffffffff, 0x3fff), new Long(0xfffffffff, 0x7fff), new Long(0xfffffffff, 0xffff),\n  new Long(0xffffffffff, 0x1fff), new Long(0xffffffffff, 0x3fff), new Long(0xffffffffff, 0x7fff), new Long(0xffffffffff, 0xffff),\n  new Long(0xfffffffffff, 0x1fff), new Long(0xfffffffffff, 0x3fff), new Long(0xfffffffffff, 0x7fff), new Long(0xfffffffffff, 0xffff),\n  new Long(0xffffffffffff, 0x1fff), new Long(0xffffffffffff, 0x3fff), new Long(0xffffffffffff, 0x7fff)];\n\n/**\n * From org/apache/lucene/util/automaton/LevenshteinAutomata.java#ParametricDescription\n * @hidden\n */\nexport class ParametricDescription {\n  protected _w: number;\n  private _n: number;\n  private _minErrors: number[];\n\n  constructor(w: number, n: number, minErrors: number[]) {\n    this._w = w;\n    this._n = n;\n    this._minErrors = minErrors;\n  }\n\n  /**\n   * Return the number of states needed to compute a Levenshtein DFA\n   */\n  public size(): number {\n    return this._minErrors.length * (this._w + 1);\n  }\n\n  /**\n   * Returns true if the <code>state</code> in any Levenshtein DFA is an accept state (final state).\n   */\n  public isAccept(absState: number): boolean {\n    // decode absState -> state, offset\n    let state = Math.floor(absState / (this._w + 1));\n    let offset = absState % (this._w + 1);\n    //assert offset >= 0;\n    return this._w - offset + this._minErrors[state] <= this._n;\n  }\n\n  /**\n   * Returns the position in the input word for a given <code>state</code>.\n   * This is the minimal boundary for the state.\n   */\n  public getPosition(absState: number): number {\n    return absState % (this._w + 1);\n  }\n\n  public static unpack(data: Long[], index: number, bitsPerValue: number): number {\n    const bitLoc = bitsPerValue * index;\n    const dataLoc = (bitLoc >> 6);\n    const bitStart = (bitLoc & 63);\n\n    if (bitStart + bitsPerValue <= 64) {\n      // not split\n      return data[dataLoc].shiftRight(bitStart).and(MASKS[bitsPerValue - 1]).toInt();\n    } else {\n      // split\n      const part = 64 - bitStart;\n      return (data[dataLoc].shiftRight(bitStart).and(MASKS[part - 1])).toInt()\n        + (data[1 + dataLoc].and(MASKS[bitsPerValue - part - 1]).shiftLeft(part)).toInt();\n    }\n  }\n}\n"
  },
  {
    "path": "packages/full-text-search/src/fuzzy/run_automaton.ts",
    "content": "import { Automaton } from \"./automaton\";\n\n/**\n * From org/apache/lucene/util/automaton/RunAutomaton.java\n * @hidden\n */\nexport class RunAutomaton {\n  private _points: number[];\n  private _accept: boolean[];\n  private _transitions: number[];\n  private _classmap: number[];\n\n  constructor(automaton: Automaton) {\n    const size = automaton.getNumStates();\n    this._points = automaton.getStartPoints();\n    this._accept = new Array(size);\n    this._transitions = new Array(size * this._points.length);\n\n    for (let n = 0; n < size; n++) {\n      this._accept[n] = automaton.isAccept(n);\n      for (let c = 0; c < this._points.length; c++) {\n        // assert dest === -1 || dest < size;\n        this._transitions[n * this._points.length + c] = automaton.step(n, this._points[c]);\n      }\n    }\n\n    this._classmap = new Array(256 /* alphaSize */);\n    for (let i = 0, j = 0; j < this._classmap.length; j++) {\n      if (i + 1 < this._points.length && j === this._points[i + 1]) {\n        i++;\n      }\n      this._classmap[j] = i;\n    }\n  }\n\n  public getCharClass(c: number): number {\n    // binary search\n    let a = 0;\n    let b = this._points.length;\n    while (b - a > 1) {\n      const d = (a + b) >>> 1;\n      if (this._points[d] > c) {\n        b = d;\n      } else if (this._points[d] < c) {\n        a = d;\n      } else {\n        return d;\n      }\n    }\n    return a;\n  }\n\n  public step(state: number, c: number): number {\n    if (c >= this._classmap.length) {\n      return this._transitions[state * this._points.length + this.getCharClass(c)];\n    } else {\n      return this._transitions[state * this._points.length + this._classmap[c]];\n    }\n  }\n\n  public isAccept(state: number): boolean {\n    return this._accept[state];\n  }\n}\n"
  },
  {
    "path": "packages/full-text-search/src/index.ts",
    "content": "import { FullTextSearch } from \"./full_text_search\";\nimport { analyze, StandardAnalyzer } from \"./analyzer/analyzer\";\nimport { whitespaceTokenizer } from \"./analyzer/tokenizer\";\nimport { lowercaseTokenFilter, uppercaseTokenFilter } from \"./analyzer/token_filter\";\n\nFullTextSearch[\"Analyzer\"] = {};\nFullTextSearch[\"Analyzer\"][\"analyze\"] = analyze;\nFullTextSearch[\"Analyzer\"][\"StandardAnalyzer\"] = StandardAnalyzer;\nFullTextSearch[\"Tokenizer\"] = {};\nFullTextSearch[\"Tokenizer\"][\"whitespaceTokenizer\"] = whitespaceTokenizer;\nFullTextSearch[\"TokenFilter\"] = {};\nFullTextSearch[\"TokenFilter\"][\"lowercaseTokenFilter\"] = lowercaseTokenFilter;\nFullTextSearch[\"TokenFilter\"][\"uppercaseTokenFilter\"] = uppercaseTokenFilter;\n\nexport {FullTextSearch,\n  analyze, StandardAnalyzer,\n  whitespaceTokenizer,\n  lowercaseTokenFilter, uppercaseTokenFilter\n};\nexport default FullTextSearch;\n"
  },
  {
    "path": "packages/full-text-search/src/index_searcher.ts",
    "content": "import { Scorer } from \"./scorer\";\nimport { InvertedIndex, toCodePoints } from \"./inverted_index\";\nimport { BoolQuery, FuzzyQuery, Query, QueryTypes, TermQuery, WildcardQuery } from \"./query_types\";\nimport { Dict } from \"../../common/types\";\nimport { RunAutomaton } from \"./fuzzy/run_automaton\";\nimport { LevenshteinAutomata } from \"./fuzzy/levenshtein_automata\";\nimport QueryResults = Scorer.QueryResults;\nimport Index = InvertedIndex.Index;\nimport { analyze, Analyzer } from \"./analyzer/analyzer\";\n\nfunction calculateMinShouldMatch(optionalClauseCount: number, spec: undefined | number | string): number {\n  if (spec === undefined) {\n    return 1;\n  }\n  if (typeof spec === \"number\") {\n    return (spec < 0) ? optionalClauseCount + spec : spec;\n  }\n\n  let result = optionalClauseCount;\n  if (spec.includes(\"<\")) {\n    // Parse conditional minimumShouldMatch.;\n    for (const s of spec.split(\" \")) {\n      const parts = s.split(\"<\");\n      const upperBound = parseInt(parts[0]);\n      if (optionalClauseCount <= upperBound) {\n        return result;\n      } else {\n        result = calculateMinShouldMatch(optionalClauseCount, parts[1]);\n      }\n    }\n    return result;\n  }\n\n  if (spec.includes(\"%\")) {\n    // Parse percentage.\n    const percent = parseInt(spec.slice(0, -1));\n    const calc = (result * percent) * (1 / 100);\n    result = (calc < 0) ? result + Math.ceil(calc) : Math.floor(calc);\n  } else {\n    const calc = parseInt(spec);\n    result = (calc < 0) ? result + calc : calc;\n  }\n\n  return (result < 1) ? 1 : result;\n}\n\n/**\n * @hidden\n */\nexport class IndexSearcher {\n  private _invIdxs: Dict<InvertedIndex>;\n  private _docs: Set<InvertedIndex.DocumentIndex>;\n  private _scorer: Scorer;\n\n  /**\n   * Constructs an index searcher.\n   * @param {Dict<InvertedIndex>} invIdxs - the inverted indexes\n   * @param {Set<number>} docs - the ids of the documents\n   */\n  constructor(invIdxs: Dict<InvertedIndex>, docs: Set<InvertedIndex.DocumentIndex>) {\n    this._invIdxs = invIdxs;\n    this._docs = docs;\n    this._scorer = new Scorer(this._invIdxs);\n  }\n\n  public search(query: Query): Scorer.ScoreResults {\n    let queryResults = this._recursive(query.query, true);\n\n    // Do final scoring.\n    if (query.calculate_scoring !== undefined ? query.calculate_scoring : true) {\n      return this._scorer.finalScore(query, queryResults);\n    }\n\n    const result: Scorer.ScoreResults = {};\n    for (const key of queryResults.keys()) {\n      result[key] = {score: 1};\n    }\n    return result;\n  }\n\n  public setDirty() {\n    this._scorer.setDirty();\n  }\n\n  private _recursive(query: any, doScoring: boolean | null) {\n    let queryResults: QueryResults = new Map();\n    const boost = query.boost !== undefined ? query.boost : 1;\n    const fieldName = query.field !== undefined ? query.field : null;\n\n    let root = null;\n    let analyzer: Analyzer = null;\n    if (this._invIdxs[fieldName] !== undefined) {\n      root = this._invIdxs[fieldName].root;\n      analyzer = this._invIdxs[fieldName].analyzer;\n    }\n\n    switch (query.type) {\n      case \"bool\": {\n        queryResults = null;\n        if (query.must !== undefined) {\n          queryResults = this._getUnique(query.must, doScoring, queryResults);\n        }\n        if (query.filter !== undefined) {\n          queryResults = this._getUnique(query.filter, null, queryResults);\n        }\n        if (query.should !== undefined) {\n          const shouldDocs = this._getAll(query.should, doScoring);\n\n          let empty = false;\n          if (queryResults === null) {\n            empty = true;\n            queryResults = new Map();\n          }\n\n          const msm = Math.max(1, calculateMinShouldMatch(query.should.length, query.minimum_should_match));\n          if (empty && msm === 1) {\n            // Take all documents.\n            queryResults = shouldDocs;\n          } else {\n            // Remove documents with fewer matches.\n            for (const [docId, res] of shouldDocs) {\n              if (res.length >= msm) {\n                if (queryResults.has(docId)) {\n                  queryResults.get(docId).push(...res);\n                } else if (empty) {\n                  queryResults.set(docId, res);\n                } else {\n                  queryResults.delete(docId);\n                }\n              }\n            }\n          }\n        }\n        // Match all documents if must/filter/should is not defined.\n        if (queryResults === null) {\n          queryResults = this._recursive({type: \"match_all\"}, false);\n        }\n        if (query.not !== undefined) {\n          let notDocs = this._getAll(query.not, null);\n          // Remove all matching documents.\n          for (const docId of notDocs.keys()) {\n            if (queryResults.has(docId)) {\n              queryResults.delete(docId);\n            }\n          }\n        }\n        // Boost query results afterwards.\n        if (boost !== 1) {\n          for (const [_, result] of queryResults) {\n            for (let i = 0; i < result.length; i++) {\n              result[i].boost *= boost;\n            }\n          }\n        }\n        break;\n      }\n      case \"term\": {\n        const cps = toCodePoints(query.value);\n        let termIdx = InvertedIndex.getTermIndex(cps, root);\n        this._scorer.score(fieldName, boost, termIdx, doScoring, queryResults, cps);\n        break;\n      }\n      case \"terms\": {\n        for (let i = 0; i < query.value.length; i++) {\n          const cps = toCodePoints(query.value[i]);\n          let termIdx = InvertedIndex.getTermIndex(cps, root);\n          this._scorer.score(fieldName, boost, termIdx, doScoring, queryResults, cps);\n        }\n        break;\n      }\n      case \"fuzzy\": {\n        const [f, idf] = fuzzySearch(query, root);\n        for (let i = 0; i < f.length; i++) {\n          this._scorer.score(fieldName, boost * f[i].boost, f[i].index, doScoring, queryResults, f[i].term, idf);\n        }\n        break;\n      }\n      case \"wildcard\": {\n        const enableScoring = query.enable_scoring !== undefined ? query.enable_scoring : false;\n        const w = wildcardSearch(query, root);\n        for (let i = 0; i < w.length; i++) {\n          this._scorer.score(fieldName, boost, w[i].index, doScoring && enableScoring, queryResults,\n            w[i].term);\n        }\n        break;\n      }\n      case \"match_all\": {\n        for (let docId of this._docs) {\n          this._scorer.scoreConstant(boost, docId, queryResults);\n        }\n        break;\n      }\n      case \"constant_score\": {\n        let tmpQueryResults = this._getAll(query.filter, false);\n        // Add to each document a constant score.\n        for (const docId of tmpQueryResults.keys()) {\n          this._scorer.scoreConstant(boost, docId, queryResults);\n        }\n        break;\n      }\n      case \"prefix\": {\n        const enableScoring = query.enable_scoring !== undefined ? query.enable_scoring : false;\n        const cps = toCodePoints(query.value);\n        const termIdx = InvertedIndex.getTermIndex(cps, root);\n        if (termIdx !== null) {\n          const termIdxs = InvertedIndex.extendTermIndex(termIdx);\n          for (let i = 0; i < termIdxs.length; i++) {\n            this._scorer.score(fieldName, boost, termIdxs[i].index, doScoring && enableScoring, queryResults,\n              [...cps, ...termIdxs[i].term]);\n          }\n        }\n        break;\n      }\n      case \"exists\": {\n        if (root !== null) {\n          for (const docId of this._invIdxs[fieldName].docStore.keys()) {\n            this._scorer.scoreConstant(boost, docId, queryResults);\n          }\n        }\n        break;\n      }\n      case \"match\": {\n        const terms = analyze(analyzer, query.value);\n        const operator = query.operator !== undefined ? query.operator : \"or\";\n\n        const boolQuery: BoolQuery = {type: \"bool\"};\n        const subQueries: QueryTypes[] = [];\n        if (operator === \"or\") {\n          if (query.minimum_should_match !== undefined) {\n            boolQuery.minimum_should_match = query.minimum_should_match;\n          }\n          // Create a should query.\n          boolQuery.should = subQueries;\n        } else {\n          // Create a must query.\n          boolQuery.must = subQueries;\n        }\n        boolQuery.boost = boost;\n\n        if (query.fuzziness !== undefined) {\n          let prefixLength = query.prefix_length !== undefined ? query.prefix_length : 2;\n          let extended = query.extended !== undefined ? query.extended : false;\n          // Add each fuzzy.\n          for (let i = 0; i < terms.length; i++) {\n            subQueries.push({\n              type: \"fuzzy\", field: fieldName, value: terms[i], fuzziness: query.fuzziness,\n              prefix_length: prefixLength, extended: extended\n            } as FuzzyQuery);\n          }\n        } else {\n          // Add each term.\n          for (let i = 0; i < terms.length; i++) {\n            subQueries.push({type: \"term\", field: fieldName, value: terms[i]} as TermQuery);\n          }\n        }\n        queryResults = this._recursive(boolQuery, doScoring);\n\n        break;\n      }\n      default:\n        break;\n    }\n    return queryResults;\n  }\n\n  private _getUnique(queries: any[], doScoring: boolean | null, queryResults: QueryResults): QueryResults {\n    if (queries.length === 0) {\n      return queryResults;\n    }\n\n    for (let i = 0; i < queries.length; i++) {\n      let currDocs = this._recursive(queries[i], doScoring);\n      if (queryResults === null) {\n        queryResults = this._recursive(queries[0], doScoring);\n        continue;\n      }\n\n      for (const docId of queryResults.keys()) {\n        if (!currDocs.has(docId)) {\n          queryResults.delete(docId);\n        } else {\n          queryResults.get(docId).push(...currDocs.get(docId));\n        }\n      }\n    }\n    return queryResults;\n  }\n\n  private _getAll(queries: any[], doScoring: boolean | null, queryResults: QueryResults = new Map()): QueryResults {\n    for (let i = 0; i < queries.length; i++) {\n      let currDocs = this._recursive(queries[i], doScoring);\n      for (const docId of currDocs.keys()) {\n        if (!queryResults.has(docId)) {\n          queryResults.set(docId, currDocs.get(docId));\n        } else {\n          queryResults.get(docId).push(...currDocs.get(docId));\n        }\n      }\n    }\n    return queryResults;\n  }\n}\n\ntype FuzzyResult = { index: Index, term: number[], boost: number };\n\n/**\n * Calculates the levenshtein distance. Specialized version.\n * Copyright Kigiri: https://github.com/kigiri\n *           Milot Mirdita: https://github.com/milot-mirdita\n *           Toni Neubert:  https://github.com/Viatorus/\n * @param {string} a - a string\n * @param {string} b - a string\n */\nfunction calculateLevenshteinDistance(a: number[], b: number[]): number {\n  let i;\n  let j;\n  let prev;\n  let val;\n\n  const row = Array(a.length + 1);\n  // init the row\n  for (i = 0; i <= a.length; i++) {\n    row[i] = i;\n  }\n\n  // fill in the rest\n  for (i = 1; i <= b.length; i++) {\n    prev = i;\n    for (j = 1; j <= a.length; j++) {\n      if (b[i - 1] === a[j - 1]) {\t// match\n        val = row[j - 1];\n      } else {\n        val = Math.min(row[j - 1] + 1, // substitution\n          Math.min(prev + 1,         // insertion\n            row[j] + 1));          // deletion\n\n        // transposition\n        if (i > 1 && j > 1 && b[i - 2] === a[j - 1] && a[j - 2] === b[i - 1]) {\n          val = Math.min(val, row[j - 1] - (a[j - 1] === b[i - 1] ? 1 : 0));\n        }\n      }\n      row[j - 1] = prev;\n      prev = val;\n    }\n    row[a.length] = prev;\n  }\n  return row[a.length];\n}\n\n/**\n * Performs a fuzzy search.\n * @param {FuzzyQuery} query - the fuzzy query\n * @param {Index} root - the root index\n * @returns {[FuzzyResult, number]} - the fuzzy results and the maximum df\n */\nfunction fuzzySearch(query: FuzzyQuery, root: Index): [FuzzyResult[], number] {\n  let value = toCodePoints(query.value);\n  let fuzziness = query.fuzziness !== undefined ? query.fuzziness : \"AUTO\";\n  if (fuzziness === \"AUTO\") {\n    if (value.length <= 2) {\n      fuzziness = 0;\n    } else if (value.length <= 5) {\n      fuzziness = 1;\n    } else {\n      fuzziness = 2;\n    }\n  }\n  let prefixLength = query.prefix_length !== undefined ? query.prefix_length : 0;\n  let extended = query.extended !== undefined ? query.extended : false;\n\n  // Do just a prefix search if zero fuzziness.\n  if (fuzziness === 0) {\n    prefixLength = value.length;\n  }\n\n  let result: FuzzyResult[] = [];\n  let startIdx = root;\n  let prefix = value.slice(0, prefixLength);\n  let fuzzy = value;\n  let df = 0;\n\n  // Perform a prefix search.\n  if (prefixLength !== 0) {\n    startIdx = InvertedIndex.getTermIndex(prefix, startIdx);\n    fuzzy = fuzzy.slice(prefixLength);\n  }\n\n  // No startIdx found.\n  if (startIdx === null) {\n    return [result, df];\n  }\n\n  // Fuzzy is not necessary anymore, because prefix search includes the whole query value.\n  if (fuzzy.length === 0) {\n    if (extended) {\n      // Add all terms down the index.\n      const all = InvertedIndex.extendTermIndex(startIdx);\n      for (let i = 0; i < all.length; i++) {\n        result.push({index: all[i].index, term: all[i].term, boost: 1});\n        df = Math.max(df, all[i].index.df);\n      }\n    } else if (startIdx.dc !== undefined) {\n      // Add prefix search result.\n      result.push({index: startIdx, term: value, boost: 1});\n      df = startIdx.df;\n    }\n    return [result, df];\n  }\n\n  // The matching term.\n  const term = [0];\n  // Create an automaton from the fuzzy.\n  const automaton = new RunAutomaton(new LevenshteinAutomata(fuzzy, fuzziness).toAutomaton());\n\n  function determineEditDistance(state: number, term: number[], fuzzy: number[]): number {\n    // Check how many edits this fuzzy can still do.\n    let ed = 0;\n    state = automaton.step(state, 0);\n    if (state !== -1 && automaton.isAccept(state)) {\n      ed++;\n      state = automaton.step(state, 0);\n      if (state !== -1 && automaton.isAccept(state)) {\n        ed++;\n      }\n      // Special handling for smaller terms.\n      if (term.length < fuzzy.length) {\n        if (ed !== fuzziness) {\n          return calculateLevenshteinDistance(term, fuzzy);\n        }\n        // Include the term and fuzzy length.\n        ed -= fuzzy.length - term.length;\n      }\n    }\n    return fuzziness as number - ed;\n  }\n\n  function recursive(state: number, key: number, idx: Index) {\n    term[term.length - 1] = key;\n\n    // Check the current key of term with the automaton.\n    state = automaton.step(state, key);\n    if (state === -1) {\n      return;\n    }\n\n    if (automaton.isAccept(state)) {\n      if (extended) {\n        // Add all terms down the index.\n        const all = InvertedIndex.extendTermIndex(idx);\n        for (let i = 0; i < all.length; i++) {\n          result.push({index: all[i].index, term: all[i].term, boost: 1});\n          df = Math.max(df, all[i].index.df);\n        }\n        return;\n      } else if (idx.df !== undefined) {\n        // Calculate boost.\n        const distance = determineEditDistance(state, term, fuzzy);\n        const boost = Math.max(0, 1 - distance / Math.min(prefix.length + term.length, value.length));\n        result.push({index: idx, term: [...prefix, ...term], boost});\n        df = Math.max(df, idx.df);\n      }\n    }\n\n    term.push(0);\n    for (const child of idx) {\n      recursive(state, child[0], child[1]);\n    }\n    term.pop();\n  }\n\n  for (const child of startIdx) {\n    recursive(0, child[0], child[1]);\n  }\n\n  return [result, df];\n}\n\ntype WildcardResult = { index: Index, term: number[] };\n\n/**\n * Performs a wildcard search.\n * @param {WildcardQuery} query - the wildcard query\n * @param {Index} root - the root index\n * @returns {Array} - the results\n */\nfunction wildcardSearch(query: WildcardQuery, root: Index): WildcardResult[] {\n  let wildcard = toCodePoints(query.value);\n  let result: WildcardResult[] = [];\n\n  function recursive(index: Index, idx: number = 0, term: number[] = [], escaped: boolean = false) {\n    if (index === null) {\n      return;\n    }\n\n    if (idx === wildcard.length) {\n      if (index.df !== undefined) {\n        result.push({index: index, term: term.slice()});\n      }\n      return;\n    }\n\n    // Escaped character.\n    if (!escaped && wildcard[idx] === 92 /* \\ */) {\n      recursive(index, idx + 1, term, true);\n    } else if (!escaped && wildcard[idx] === 63 /* ? */) {\n      for (const child of index) {\n        recursive(child[1], idx + 1, [...term, child[0]]);\n      }\n    } else if (!escaped && wildcard[idx] === 42 /* * */) {\n      // Check if asterisk is last wildcard character\n      if (idx + 1 === wildcard.length) {\n        const all = InvertedIndex.extendTermIndex(index);\n        for (let i = 0; i < all.length; i++) {\n          recursive(all[i].index, idx + 1, [...term, ...all[i].term]);\n        }\n      } else {\n        // Iterate over the whole tree.\n        recursive(index, idx + 1, term, false);\n        const indices: InvertedIndex.IndexTerm[] = [{index: index, term: []}];\n        do {\n          const index = indices.pop();\n          for (const child of index.index) {\n            recursive(child[1], idx + 1, [...term, ...index.term, child[0]]);\n            indices.push({index: child[1], term: [...index.term, child[0]]});\n          }\n        } while (indices.length !== 0);\n      }\n    } else {\n      recursive(InvertedIndex.getTermIndex([wildcard[idx]], index), idx + 1, [...term, wildcard[idx]]);\n    }\n  }\n\n  recursive(root);\n\n  return result;\n}\n"
  },
  {
    "path": "packages/full-text-search/src/inverted_index.ts",
    "content": "import { Analyzer, StandardAnalyzer, analyze } from \"./analyzer/analyzer\";\n\n/**\n * Converts a string into an array of code points.\n * @param str - the string\n * @returns {number[]} to code points\n * @hidden\n */\nexport function toCodePoints(str: string): number[] {\n  const r = [];\n  for (let i = 0; i < str.length;) {\n    const chr = str.charCodeAt(i++);\n    if (chr >= 0xD800 && chr <= 0xDBFF) {\n      // surrogate pair\n      const low = str.charCodeAt(i++);\n      r.push(0x10000 + ((chr - 0xD800) << 10) | (low - 0xDC00));\n    } else {\n      // ordinary character\n      r.push(chr);\n    }\n  }\n  return r;\n}\n\n/**\n * Inverted index class handles featured text search for specific document fields.\n * @hidden\n */\nexport class InvertedIndex {\n  public analyzer: Analyzer;\n  public docCount: number = 0;\n  public docStore: Map<InvertedIndex.DocumentIndex, InvertedIndex.DocStore> = new Map();\n  public totalFieldLength: number = 0;\n  public root: InvertedIndex.Index = new Map();\n\n  private _store: boolean;\n  private _optimizeChanges: boolean;\n\n  /**\n   * @param {boolean} [options.store=true] - inverted index will be stored at serialization rather than rebuilt on load\n   * @param {boolean} [options.optimizeChanges=true] - flag to store additional metadata inside the index for better\n   *  performance if an existing field is updated or removed\n   * @param {Analyzer} [options.analyzer=] - the analyzer of this inverted index\n   */\n  constructor(options: InvertedIndex.FieldOptions = {}) {\n    (\n      {\n        store: this._store = true,\n        optimizeChanges: this._optimizeChanges = true,\n        analyzer: this.analyzer = new StandardAnalyzer()\n      } = options\n    );\n  }\n\n  /**\n   * Adds defined fields of a document to the inverted index.\n   * @param {string} field - the field to add\n   * @param {number} docId - the doc id of the field\n   */\n  public insert(field: string, docId: InvertedIndex.DocumentIndex): void {\n    if (this.docStore.has(docId)) {\n      throw Error(\"Field already added.\");\n    }\n\n    // Tokenize document field.\n    const fieldTokens = analyze(this.analyzer, field);\n    if (fieldTokens.length == 0) {\n      // Add empty field at least to document store for query 'exists'.\n      this.docStore.set(docId, {fieldLength: 0});\n      return;\n    }\n    this.totalFieldLength += fieldTokens.length;\n    this.docCount += 1;\n    this.docStore.set(docId, {fieldLength: fieldTokens.length});\n\n    // Holds references to each index of a document.\n    const indexRef: InvertedIndex.Index[] = [];\n    if (this._optimizeChanges) {\n      Object.defineProperties(this.docStore.get(docId), {\n        indexRef: {enumerable: false, configurable: true, writable: true, value: indexRef}\n      });\n    }\n\n    // Iterate over all unique field terms.\n    for (const token of new Set(fieldTokens)) {\n      // Calculate term frequency.\n      let tf = 0;\n      for (let j = 0; j < fieldTokens.length; j++) {\n        if (fieldTokens[j] === token) {\n          ++tf;\n        }\n      }\n\n      // Add term to index tree.\n      let branch = this.root;\n\n      for (const c of toCodePoints(token)) {\n        let child = branch.get(c);\n        if (child === undefined) {\n          child = new Map();\n          if (this._optimizeChanges) {\n            child.pa = branch;\n          }\n          branch.set(c, child);\n        }\n        branch = child;\n      }\n      // Add term info to index leaf.\n      if (branch.dc === undefined) {\n        branch.dc = new Map();\n        branch.df = 0;\n      }\n      branch.dc.set(docId, tf);\n      branch.df += 1;\n\n      // Store index leaf for deletion.\n      indexRef.push(branch);\n    }\n  }\n\n  /**\n   * Removes all relevant terms of a document from the inverted index.\n   * @param {number} docId - the document.\n   */\n  public remove(docId: InvertedIndex.DocumentIndex): void {\n    if (!this.docStore.has(docId)) {\n      return;\n    }\n    const docStore = this.docStore.get(docId);\n    // Remove document.\n    this.docStore.delete(docId);\n    if (docStore.fieldLength === 0) {\n      return;\n    }\n    this.docCount -= 1;\n\n    // Reduce total field length.\n    this.totalFieldLength -= docStore.fieldLength;\n\n    if (this._optimizeChanges) {\n      // Iterate over all term references.\n      // Remove docId from docs and decrement document frequency.\n      const indexRef = docStore.indexRef;\n      for (let j = 0; j < indexRef.length; j++) {\n        let index = indexRef[j];\n        index.df -= 1;\n        index.dc.delete(docId);\n\n        // Check if no document is left for current tree.\n        if (index.df === 0) {\n          // Delete unused meta data of branch.\n          delete index.df;\n          delete index.dc;\n\n          // Check for sub branches.\n          if (index.size !== 0) {\n            continue;\n          }\n\n          // Delete term branch if not used anymore.\n          do {\n            // Go tree upwards.\n            const parent = index.pa;\n            // Delete parent reference for preventing memory leak (cycle reference).\n            delete index.pa;\n\n            // Iterate over all children.\n            for (const key of parent.keys()) {\n              // Remove previous child form parent.\n              if (parent.get(key) === index) {\n                parent.delete(key);\n                break;\n              }\n            }\n            index = parent;\n          } while (index.pa !== undefined && index.size === 0 && index.df === undefined);\n        }\n      }\n    } else {\n      this._remove(this.root, docId);\n    }\n  }\n\n  /**\n   * Gets the term index of a term.\n   * @param {string} term - the term\n   * @param {object} root - the term index to start from\n   * @param {number} start - the position of the term string to start from\n   * @return {object} - The term index or null if the term is not in the term tree.\n   */\n  public static getTermIndex(term: number[], root: InvertedIndex.Index, start: number = 0): InvertedIndex.Index {\n    if (start >= term.length) {\n      return null;\n    }\n    for (let i = start; i < term.length; i++) {\n      let child = root.get(term[i]);\n      if (child === undefined) {\n        return null;\n      }\n      root = child;\n    }\n    return root;\n  }\n\n  /**\n   * Extends a term index to all available term leafs.\n   * @param {object} idx - the term index to start from\n   * @param {number[]} [term=[]] - the current term\n   * @param {Array} termIndices - all extended indices with their term\n   * @returns {Array} - Array with term indices and extension\n   */\n  public static extendTermIndex(idx: InvertedIndex.Index, term: number[] = [],\n                                termIndices: InvertedIndex.IndexTerm[] = []): InvertedIndex.IndexTerm[] {\n    if (idx.df !== undefined) {\n      termIndices.push({index: idx, term: term.slice()});\n    }\n\n    term.push(0);\n    for (const child of idx) {\n      term[term.length - 1] = child[0];\n      InvertedIndex.extendTermIndex(child[1], term, termIndices);\n    }\n    term.pop();\n    return termIndices;\n  }\n\n  /**\n   * Serialize the inverted index.\n   * @returns {{docStore: *, _fields: *, index: *}}\n   */\n  public toJSON(): InvertedIndex.Serialization {\n    if (this._store) {\n      return {\n        _store: true,\n        _optimizeChanges: this._optimizeChanges,\n        docCount: this.docCount,\n        docStore: [...this.docStore],\n        totalFieldLength: this.totalFieldLength,\n        root: InvertedIndex._serializeIndex(this.root)\n      };\n    }\n    return {\n      _store: false,\n      _optimizeChanges: this._optimizeChanges,\n    };\n  }\n\n  /**\n   * Deserialize the inverted index.\n   * @param {{docStore: *, _fields: *, index: *}} serialized - The serialized inverted index.\n   * @param {Analyzer} analyzer[undefined] - an analyzer\n   */\n  public static fromJSONObject(serialized: InvertedIndex.Serialization, analyzer?: Analyzer): InvertedIndex {\n    const invIdx = new InvertedIndex({\n      store: serialized._store,\n      optimizeChanges: serialized._optimizeChanges,\n      analyzer: analyzer\n    });\n\n    if (serialized._store) {\n      invIdx.docCount = serialized.docCount;\n      invIdx.docStore = new Map(serialized.docStore);\n      invIdx.totalFieldLength = serialized.totalFieldLength;\n      invIdx.root = InvertedIndex._deserializeIndex(serialized.root);\n    }\n\n    if (invIdx._optimizeChanges) {\n      invIdx._regenerate(invIdx.root, null);\n    }\n\n    return invIdx;\n  }\n\n  private static _serializeIndex(idx: InvertedIndex.Index): InvertedIndex.SerializedIndex {\n    const serialized: InvertedIndex.SerializedIndex = {};\n    if (idx.dc !== undefined) {\n      serialized.d = {df: idx.df, dc: [...idx.dc]};\n    }\n\n    if (idx.size === 0) {\n      return serialized;\n    }\n\n    const keys = [];\n    const values = [];\n    for (const child of idx) {\n      keys.push(child[0]);\n      values.push(InvertedIndex._serializeIndex(child[1]));\n    }\n    serialized.k = keys;\n    serialized.v = values;\n\n    return serialized;\n  }\n\n  private static _deserializeIndex(serialized: InvertedIndex.SerializedIndex): InvertedIndex.Index {\n    const idx: InvertedIndex.Index = new Map();\n\n    if (serialized.k !== undefined) {\n      for (let i = 0; i < serialized.k.length; i++) {\n        idx.set(serialized.k[i], InvertedIndex._deserializeIndex(serialized.v[i]));\n      }\n    }\n    if (serialized.d !== undefined) {\n      idx.df = serialized.d.df;\n      idx.dc = new Map(serialized.d.dc);\n    }\n    return idx;\n  }\n\n  /**\n   * Set parent of to each index and regenerate the indexRef.\n   * @param {Index} index - the index\n   * @param {Index} parent - the parent\n   */\n  private _regenerate(index: InvertedIndex.Index, parent: InvertedIndex.Index): void {\n    // Set parent.\n    if (parent !== null) {\n      index.pa = parent;\n    }\n\n    // Iterate over subtree.\n    for (const child of index.values()) {\n      this._regenerate(child, index);\n    }\n\n    if (index.dc !== undefined) {\n      // Get documents of term.\n      for (const docId of index.dc.keys()) {\n        // Get document store at specific document/field.\n        const ref = this.docStore.get(docId);\n        if (ref.indexRef === undefined) {\n          Object.defineProperties(ref, {\n            indexRef: {enumerable: false, configurable: true, writable: true, value: []}\n          });\n        }\n        // Set reference to term index.\n        ref.indexRef.push(index);\n      }\n    }\n  }\n\n  /**\n   * Iterate over the whole inverted index and remove the document.\n   * Delete branch if not needed anymore.\n   * Function is needed if index is used without optimization.\n   * @param {Index} idx - the index\n   * @param {number} docId - the doc id\n   * @returns {boolean} true if index is empty\n   */\n  private _remove(idx: InvertedIndex.Index, docId: InvertedIndex.DocumentIndex): boolean {\n    for (const child of idx) {\n      // Checkout branch.\n      if (this._remove(child[1], docId)) {\n        idx.delete(child[0]);\n      }\n    }\n    // Remove docId from docs and decrement document frequency.\n    if (idx.df !== undefined) {\n      if (idx.dc.has(docId)) {\n        idx.df -= 1;\n        idx.dc.delete(docId);\n\n        // Delete unused meta data of branch.\n        if (idx.df === 0) {\n          delete idx.df;\n          delete idx.dc;\n        }\n      }\n    }\n    return idx.size === 0 && idx.dc === undefined;\n  }\n}\n\nexport namespace InvertedIndex {\n  export interface FieldOptions {\n    store?: boolean;\n    optimizeChanges?: boolean;\n    analyzer?: Analyzer;\n  }\n\n  export type Index = Map<number, any> & { dc?: Map<DocumentIndex, number>, df?: number, pa?: Index };\n\n  export type IndexTerm = { index: Index, term: number[] };\n\n  export interface SerializedIndex {\n    d?: {\n      df: number;\n      dc: [DocumentIndex, number][]\n    };\n    k?: number[];\n    v?: SerializedIndex[];\n  }\n\n  export type Serialization = SpareSerialization | FullSerialization;\n\n  export type SpareSerialization = {\n    _store: false;\n    _optimizeChanges: boolean;\n  };\n\n  export type FullSerialization = {\n    _store: true;\n    _optimizeChanges: boolean;\n    docCount: number;\n    docStore: [DocumentIndex, DocStore][];\n    totalFieldLength: number;\n    root: SerializedIndex;\n  };\n\n  export interface DocStore {\n    fieldLength?: number;\n    indexRef?: Index[];\n  }\n\n  export type DocumentIndex = number | string;\n}\n"
  },
  {
    "path": "packages/full-text-search/src/query_types.ts",
    "content": "/**\n * Base query to enable boost to a query type.\n */\nexport interface BaseQuery<Type> {\n  /// The query type.\n  type: Type;\n  /// The query boost.\n  boost?: number;\n}\n\n/**\n * A query which finds documents where a document field contains a term.\n */\nexport interface TermQuery extends BaseQuery<\"term\"> {\n  /// The field name.\n  field: string;\n  /// The term.\n  value: string;\n}\n\n/**\n * A query which finds documents where a document field contains any of the terms.\n */\nexport interface TermsQuery extends BaseQuery<\"terms\"> {\n  /// The field name.\n  field: string;\n  /// The terms.\n  value: string[];\n}\n\n/**\n * A query which finds documents where the wildcard term can be applied at an existing document field term.\n */\nexport interface WildcardQuery extends BaseQuery<\"wildcard\"> {\n  /// The field name.\n  field: string;\n  /// The wildcard term.\n  value: string;\n  /// Flag to enable scoring for wildcard queries.\n  enable_scoring?: boolean;\n}\n\n/**\n * A query which finds documents where the fuzzy term can be transformed into an existing document field term within a\n * given edit distance.\n */\nexport interface FuzzyQuery extends BaseQuery<\"fuzzy\"> {\n  /// The field name.\n  field: string;\n  /// The fuzzy term.\n  value: string;\n  /// The the maximal allowed fuzziness.\n  fuzziness?: 0 | 1 | 2 | \"AUTO\";\n  /// The initial word length.\n  prefix_length?: number;\n  /// Flag to match longer terms than the actual fuzzy term.\n  extended?: boolean;\n}\n\n/**\n * A query which matches documents containing the prefix of a term inside a field.\n */\nexport interface PrefixQuery extends BaseQuery<\"prefix\"> {\n  /// The field name.\n  field: string;\n  /// The prefix term.\n  value: string;\n  /// Flag to enable scoring for prefix queries.\n  enable_scoring?: boolean;\n}\n\n/**\n * A query which matches all documents with a given field.\n */\nexport interface ExistsQuery extends BaseQuery<\"exists\"> {\n  /// The field name.\n  field: string;\n}\n\n/**\n * A query which tokenizes the given text into tokens and performs a sub query for each token. The results are combined\n * using a boolean operator.\n */\nexport interface MatchQuery extends BaseQuery<\"match\"> {\n  /// The field name.\n  field: string;\n  /// The text.\n  value: string;\n  /// The amount of minimum matching sub queries.\n  minimum_should_match?: number | string;\n  /// The boolean operator.\n  operator?: \"and\" | \"or\";\n  /// The the maximal allowed fuzziness.\n  fuzziness?: 0 | 1 | 2 | \"AUTO\";\n  /// The initial word length.\n  prefix_length?: number;\n  /// Flag to match longer terms than the actual fuzzy term.\n  extended?: boolean;\n}\n\n/**\n * A query that matches all documents and giving them a constant score equal to the query boost.\n*/\nexport interface MatchQueryAll extends BaseQuery<\"match_all\"> {\n}\n\n/**\n * A query that wraps sub queries and returns a constant score equal to the query boost for every document in the filter.\n */\nexport interface ConstantScoreQuery extends BaseQuery<\"constant_score\"> {\n  filter: QueryTypes[];\n}\n\n/**\n * A query that matches documents matching boolean combinations of sub queries.\n */\nexport interface BoolQuery extends BaseQuery<\"bool\"> {\n  // The array of must queries.\n  must?: QueryTypes[];\n  // The array of filter queries.\n  filter?: QueryTypes[];\n  // The array of should queries.\n  should?: QueryTypes[];\n  // The array of not queries.\n  not?: QueryTypes[];\n  /// The amount of minimum matching sub queries.\n  minimum_should_match?: number | string;\n}\n\n/**\n * Union type of possible query types.\n */\nexport type QueryTypes = BoolQuery | ConstantScoreQuery | TermQuery | TermsQuery | WildcardQuery | FuzzyQuery\n  | MatchQuery | MatchQueryAll | PrefixQuery | ExistsQuery;\n\n/**\n * The main query with the actually full-text search query and the scoring parameters.\n */\nexport interface Query {\n  query: QueryTypes;\n  /// Flag to enable scoring calculation.\n  calculate_scoring?: boolean;\n  /// Flag to enable scoring explanation.\n  explain?: boolean;\n  /// BM25 parameter.\n  bm25?: {\n    /// The k1 parameter.\n    k1: number;\n    /// The b parameter.\n    b: number;\n  };\n}\n"
  },
  {
    "path": "packages/full-text-search/src/scorer.ts",
    "content": "import { InvertedIndex } from \"./inverted_index\";\nimport { Dict } from \"../../common/types\";\nimport { Query } from \"./query_types\";\n\n/**\n * @hidden\n */\nexport class Scorer {\n  private _invIdxs: Dict<InvertedIndex>;\n  private _cache: Dict<Scorer.IDFCache> = {};\n\n  constructor(invIdxs: Dict<InvertedIndex>) {\n    this._invIdxs = invIdxs;\n  }\n\n  public setDirty(): void {\n    this._cache = {};\n  }\n\n  public score(fieldName: string, boost: number, termIdx: InvertedIndex.Index, doScoring: boolean | null,\n               queryResults: Scorer.QueryResults, term: number[], df: number = 0): void {\n    if (termIdx === null || termIdx.dc === undefined) {\n      return;\n    }\n\n    const idf = this._idf(fieldName, df || termIdx.df);\n    for (const [docId, tf] of termIdx.dc) {\n      if (!queryResults.has(docId)) {\n        queryResults.set(docId, []);\n      }\n\n      if (doScoring === true) {\n        // BM25 scoring.\n        queryResults.get(docId).push({tf, idf, boost, fieldName, term});\n      } else if (doScoring === false) {\n        // Constant scoring.\n        queryResults.set(docId, [{boost}]);\n      } else {\n        // Zero scoring.\n        queryResults.set(docId, [{boost: 0}]);\n      }\n    }\n  }\n\n  public scoreConstant(boost: number, docId: InvertedIndex.DocumentIndex,\n                       queryResults: Scorer.QueryResults): Scorer.QueryResults {\n    if (!queryResults.has(docId)) {\n      queryResults.set(docId, []);\n    }\n    queryResults.get(docId).push({boost});\n    return queryResults;\n  }\n\n  public finalScore(query: Query, queryResults: Scorer.QueryResults): Scorer.ScoreResults {\n    const finalResult: Scorer.ScoreResults = {};\n    const k1 = query.bm25 !== undefined ? query.bm25.k1 : 1.2;\n    const b = query.bm25 !== undefined ? query.bm25.b : 0.75;\n    const explain = query.explain !== undefined ? query.explain : false;\n\n    for (const [docId, result] of queryResults) {\n      let docScore = 0;\n      let docExplanation: Scorer.ScoreExplanation[] = [];\n      for (let i = 0; i < result.length; i++) {\n        const queryResult = result[i];\n        let score = 0;\n        if (queryResult.tf !== undefined) {\n          // BM25 scoring.\n          const tf = queryResult.tf;\n          const fieldLength = Scorer._calculateFieldLength(this._invIdxs[queryResult.fieldName].docStore.get(docId)\n            .fieldLength);\n          const avgFieldLength = this._avgFieldLength(queryResult.fieldName);\n          const tfNorm = (tf * (k1 + 1)) / (tf + k1 * (1 - b + b * (fieldLength / avgFieldLength)));\n          score = queryResult.idf * tfNorm * queryResult.boost;\n          if (explain) {\n            docExplanation.push({\n              boost: queryResult.boost,\n              score: score,\n              docID: docId,\n              fieldName: queryResult.fieldName,\n              index: String.fromCharCode(...queryResult.term),\n              idf: queryResult.idf,\n              tfNorm: tfNorm,\n              tf: tf,\n              fieldLength: fieldLength,\n              avgFieldLength: avgFieldLength,\n            });\n          }\n        } else {\n          // Constant scoring.\n          score = queryResult.boost;\n\n          if (explain) {\n            docExplanation.push({\n              boost: queryResult.boost,\n              score: score\n            });\n          }\n        }\n        docScore += score;\n      }\n      if (explain) {\n        finalResult[docId] = {\n          score: docScore,\n          explanation: docExplanation\n        };\n      } else {\n        finalResult[docId] = {\n          score: docScore\n        };\n      }\n    }\n    return finalResult;\n  }\n\n  private static _calculateFieldLength(fieldLength: number): number {\n    // Dummy function to be compatible to lucene in unit tests.\n    return fieldLength;\n  }\n\n  private _getCache(fieldName: string): Scorer.IDFCache {\n    if (this._cache[fieldName] === undefined) {\n      const avgFieldLength = this._invIdxs[fieldName].totalFieldLength / this._invIdxs[fieldName].docCount;\n      this._cache[fieldName] = {idfs: {}, avgFieldLength};\n    }\n    return this._cache[fieldName];\n  }\n\n  /**\n   * Returns the idf by either calculate it or use a cached one.\n   * @param {string} fieldName - the name of the field\n   * @param {number} docFreq - the doc frequency of the term\n   * @returns {number} the idf\n   * @private\n   */\n  private _idf(fieldName: string, docFreq: number): number {\n    const cache = this._getCache(fieldName);\n    if (cache.idfs[docFreq] !== undefined) {\n      return cache.idfs[docFreq];\n    }\n    return cache.idfs[docFreq] = Math.log(1 + (this._invIdxs[fieldName].docCount - docFreq + 0.5) / (docFreq + 0.5));\n  }\n\n  private _avgFieldLength(fieldName: string): number {\n    return this._getCache(fieldName).avgFieldLength;\n  }\n}\n\nexport namespace Scorer {\n  export interface IDFCache {\n    idfs: Dict<number>;\n    avgFieldLength: number;\n  }\n\n  export interface QueryResult {\n    tf?: number; // Term frequency.\n    idf?: number; // Inverse document frequency\n    boost: number;\n    fieldName?: string;\n    term?: number[];\n  }\n\n  export type QueryResults = Map<InvertedIndex.DocumentIndex, QueryResult[]>;\n\n  export interface BM25Explanation {\n    boost: number;\n    score: number;\n    docID: number;\n    fieldName: string;\n    index: string;\n    idf: number;\n    tfNorm: number;\n    tf: number;\n    fieldLength: number;\n    avgFieldLength: number;\n  }\n\n  export interface ConstantExplanation {\n    boost: number;\n    score: number;\n  }\n\n  export type ScoreExplanation = BM25Explanation | ConstantExplanation;\n  export type ScoreResult = { score: number, explanation?: ScoreExplanation[] };\n  export type ScoreResults = Dict<ScoreResult>;\n}\n"
  },
  {
    "path": "packages/full-text-search/webpack.config.js",
    "content": "/* global __dirname, module, require */\nconst path = require(\"path\");\nconst webpackConigCreator = require('../../config/webpack-config-creator.js');\n\nmodule.exports = webpackConigCreator({\n  entry: path.join(__dirname, \"src\", \"index.ts\"),\n  filename: \"lokidb.full-text-search.js\",\n  library: \"@lokidb/full-text-search\",\n  externals: {\n    \"../../loki/src/loki\": \"@lokidb/loki\"\n  },\n});\n"
  },
  {
    "path": "packages/full-text-search-language/package.json",
    "content": "{\n  \"name\": \"@lokidb/full-text-search-language\",\n  \"description\": \"A language analyzer utility package.\",\n  \"author\": \"Various authors\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/LokiJS-Forge/LokiDB.git\"\n  },\n  \"main\": \"lokidb.full-text-search-language.js\",\n  \"types\": \"./types/full-text-search-language/src/index.d.ts\"\n}\n"
  },
  {
    "path": "packages/full-text-search-language/spec/helper/create_lanuage_test.helper.ts",
    "content": "import { FullTextSearch } from \"../../../full-text-search/src/index\";\nimport { Query } from \"../../../full-text-search/src/query_types\";\nimport { Analyzer } from \"../../../full-text-search/src/analyzer/analyzer\";\n\nexport interface LanguageTestData {\n  analyzer: Analyzer;\n  docs: string[];\n  tests: {\n    what: string;\n    search: string;\n    expected: number[];\n  }[];\n}\n\n/**\n * Performs unit tests for a language\n * @param {string} language - the language name\n * @param {LanguageTestData} data - the language data\n */\nexport function createLanguageTest(language: string, data: LanguageTestData) {\n  let assertMatches = (searcher: FullTextSearch, query: Query, docIds: number[] = []) => {\n    let res = searcher.search(query);\n    expect(Object.keys(res).length).toEqual(docIds.length);\n    for (let i = 0; i < docIds.length; i++) {\n      expect(res).toHaveMember(String(docIds[i]));\n      delete res[String(docIds[i])];\n    }\n    expect(res).toEqual({});\n  };\n\n  describe(\"language-\" + language + \":\", () => {\n    // Setup full-text search.\n    let fts = new FullTextSearch([{\n      field: \"body\",\n      analyzer: data.analyzer\n    }], \"$loki\");\n\n    // Add documents.\n    for (let i = 0; i < data.docs.length; i++) {\n      fts.addDocument({\n        $loki: i,\n        body: data.docs[i]\n      });\n    }\n\n    // Check each test.\n    for (let i = 0; i < data.tests.length; i++) {\n      let test = data.tests[i];\n      it(test.what + \" '\" + test.search + \"'\", () => {\n        assertMatches(fts, {query: {type: \"match\", field: \"body\", value: test.search}}, test.expected);\n      });\n    }\n  });\n}\n"
  },
  {
    "path": "packages/full-text-search-language/src/index.ts",
    "content": "export {generateStopWordFilter, generateTrimmer, Among, SnowballProgram} from \"./language\";\n"
  },
  {
    "path": "packages/full-text-search-language/src/language.ts",
    "content": "/*\n * From MihaiValentin/lunr-languages.\n * Last update from 2017/04/16 - 19af41fb9bd644d9081ad274f96f700b21464290\n */\nexport function generateTrimmer(wordCharacters: string) {\n  const regex = new RegExp(`^[^${wordCharacters}]+|[^${wordCharacters}]+$`, \"g\");\n  return (token: string) => token.replace(regex, \"\");\n}\n\nexport function generateStopWordFilter(stopWords: string[]) {\n  const words = new Set(stopWords);\n  return (token: string) => words.has(token) ? \"\" : token;\n}\n\nexport class Among {\n  s_size: number;\n  s: number[];\n  substring_i: number;\n  result: number;\n  method: any;\n\n  constructor(s: string, substring_i: number, result: number, method?: any) {\n    if ((!s && s !== \"\") || (!substring_i && (substring_i !== 0)) || !result) {\n      throw (\"Bad Among initialisation: s:\" + s + \", substring_i: \" + substring_i + \", result: \" + result);\n    }\n\n    this.s_size = s.length;\n    this.substring_i = substring_i;\n    this.result = result;\n    this.method = method;\n\n    // Split string into a numeric character array.\n    this.s = new Array(this.s_size);\n    for (let i = 0; i < this.s_size; i++) {\n      this.s[i] = +s.charCodeAt(i);\n    }\n  }\n}\n\nexport class SnowballProgram {\n  current: string;\n  bra: number;\n  ket: number;\n  limit: number;\n  cursor: number;\n  limit_backward: number;\n\n  constructor() {\n    this.current = null;\n    this.bra = 0;\n    this.ket = 0;\n    this.limit = 0;\n    this.cursor = 0;\n    this.limit_backward = 0;\n  }\n\n  setCurrent(word: string) {\n    this.current = word;\n    this.cursor = 0;\n    this.limit = word.length;\n    this.limit_backward = 0;\n    this.bra = this.cursor;\n    this.ket = this.limit;\n  }\n\n  getCurrent() {\n    let result = this.current;\n    this.current = null;\n    return result;\n  }\n\n  in_grouping(s: number[], min: number, max: number) {\n    if (this.cursor < this.limit) {\n      let ch = this.current.charCodeAt(this.cursor);\n      if (ch <= max && ch >= min) {\n        ch -= min;\n        if (s[ch >> 3] & (0X1 << (ch & 0X7))) {\n          this.cursor++;\n          return true;\n        }\n      }\n    }\n    return false;\n  }\n\n  in_grouping_b(s: number[], min: number, max: number) {\n    if (this.cursor > this.limit_backward) {\n      let ch = this.current.charCodeAt(this.cursor - 1);\n      if (ch <= max && ch >= min) {\n        ch -= min;\n        if (s[ch >> 3] & (0X1 << (ch & 0X7))) {\n          this.cursor--;\n          return true;\n        }\n      }\n    }\n    return false;\n  }\n\n  out_grouping(s: number[], min: number, max: number) {\n    if (this.cursor < this.limit) {\n      let ch = this.current.charCodeAt(this.cursor);\n      if (ch > max || ch < min) {\n        this.cursor++;\n        return true;\n      }\n      ch -= min;\n      if (!(s[ch >> 3] & (0X1 << (ch & 0X7)))) {\n        this.cursor++;\n        return true;\n      }\n    }\n    return false;\n  }\n\n  out_grouping_b(s: number[], min: number, max: number) {\n    if (this.cursor > this.limit_backward) {\n      let ch = this.current.charCodeAt(this.cursor - 1);\n      if (ch > max || ch < min) {\n        this.cursor--;\n        return true;\n      }\n      ch -= min;\n      if (!(s[ch >> 3] & (0X1 << (ch & 0X7)))) {\n        this.cursor--;\n        return true;\n      }\n    }\n    return false;\n  }\n\n  eq_s(s_size: number, s: string) {\n    if (this.limit - this.cursor < s_size) {\n      return false;\n    }\n    for (let i = 0; i < s_size; i++) {\n      if (this.current.charCodeAt(this.cursor + i) !== s.charCodeAt(i)) {\n        return false;\n      }\n    }\n    this.cursor += s_size;\n    return true;\n  }\n\n  eq_s_b(s_size: number, s: string) {\n    if (this.cursor - this.limit_backward < s_size) {\n      return false;\n    }\n    for (let i = 0; i < s_size; i++) {\n      if (this.current.charCodeAt(this.cursor - s_size + i) !== s.charCodeAt(i)) {\n        return false;\n      }\n    }\n    this.cursor -= s_size;\n    return true;\n  }\n\n  find_among(v: Among[], v_size: number) {\n    let i = 0;\n    let j = v_size;\n    let c = this.cursor;\n    let l = this.limit;\n    let common_i = 0;\n    let common_j = 0;\n    let first_key_inspected = false;\n    while (true) {\n      let k = i + ((j - i) >> 1);\n      let diff = 0;\n      let common = common_i < common_j ? common_i : common_j;\n\n      let w = v[k];\n      for (let i2 = common; i2 < w.s_size; i2++) {\n        if (c + common === l) {\n          diff = -1;\n          break;\n        }\n        diff = this.current.charCodeAt(c + common) - w.s[i2];\n        if (diff) {\n          break;\n        }\n        common++;\n      }\n      if (diff < 0) {\n        j = k;\n        common_j = common;\n      } else {\n        i = k;\n        common_i = common;\n      }\n      if (j - i <= 1) {\n        if (i > 0 || j === i || first_key_inspected) {\n          break;\n        }\n        first_key_inspected = true;\n      }\n    }\n    while (true) {\n      let w = v[i];\n      if (common_i >= w.s_size) {\n        this.cursor = c + w.s_size;\n        if (!w.method) {\n          return w.result;\n        }\n        let res = w.method();\n        this.cursor = c + w.s_size;\n        if (res) {\n          return w.result;\n        }\n      }\n      i = w.substring_i;\n      if (i < 0) {\n        return 0;\n      }\n    }\n  }\n\n  find_among_b(v: Among[], v_size: number) {\n    let i = 0;\n    let j = v_size;\n    let c = this.cursor;\n    let lb = this.limit_backward;\n    let common_i = 0;\n    let common_j = 0;\n    let first_key_inspected = false;\n    while (true) {\n      let k = i + ((j - i) >> 1);\n      let diff = 0;\n\n      let common = common_i < common_j\n        ? common_i\n        : common_j;\n\n      let w = v[k];\n      for (let i2 = w.s_size - 1 - common; i2 >= 0; i2--) {\n        if (c - common === lb) {\n          diff = -1;\n          break;\n        }\n        diff = this.current.charCodeAt(c - 1 - common) - w.s[i2];\n        if (diff)\n          break;\n        common++;\n      }\n      if (diff < 0) {\n        j = k;\n        common_j = common;\n      } else {\n        i = k;\n        common_i = common;\n      }\n      if (j - i <= 1) {\n        if (i > 0 || j === i || first_key_inspected)\n          break;\n        first_key_inspected = true;\n      }\n    }\n    while (true) {\n      let w = v[i];\n      if (common_i >= w.s_size) {\n        this.cursor = c - w.s_size;\n        if (!w.method)\n          return w.result;\n        let res = w.method();\n        this.cursor = c - w.s_size;\n        if (res)\n          return w.result;\n      }\n      i = w.substring_i;\n      if (i < 0)\n        return 0;\n    }\n  }\n\n  replace_s(c_bra: number, c_ket: number, s: string) {\n    let adjustment = s.length - (c_ket - c_bra);\n\n    let left = this.current\n      .substring(0, c_bra);\n\n    let right = this.current.substring(c_ket);\n    this.current = left + s + right;\n    this.limit += adjustment;\n    if (this.cursor >= c_ket)\n      this.cursor += adjustment;\n    else if (this.cursor > c_bra)\n      this.cursor = c_bra;\n    return adjustment;\n  }\n\n  slice_check() {\n    if (this.bra < 0 || this.bra > this.ket || this.ket > this.limit\n      || this.limit > this.current.length) {\n      throw (\"faulty slice operation\");\n    }\n  }\n\n  slice_from(s: string) {\n    this.slice_check();\n    this.replace_s(this.bra, this.ket, s);\n  }\n\n  slice_del() {\n    this.slice_from(\"\");\n  }\n\n  insert(c_bra: number, c_ket: number, s: string) {\n    let adjustment = this.replace_s(c_bra, c_ket, s);\n    if (c_bra <= this.bra)\n      this.bra += adjustment;\n    if (c_bra <= this.ket)\n      this.ket += adjustment;\n  }\n\n  slice_to() {\n    this.slice_check();\n    return this.current.substring(this.bra, this.ket);\n  }\n\n  eq_v_b(s: string) {\n    return this.eq_s_b(s.length, s);\n  }\n}\n"
  },
  {
    "path": "packages/full-text-search-language/webpack.config.js",
    "content": "/* global __dirname, module, require */\nconst path = require(\"path\");\nconst webpackConigCreator = require('../../config/webpack-config-creator.js');\n\nmodule.exports = webpackConigCreator({\n  entry: path.join(__dirname, \"src\", \"index.ts\"),\n  filename: \"lokidb.full-text-search-language.js\",\n  library: \"@lokidb/full-text-search-language\"\n});\n"
  },
  {
    "path": "packages/full-text-search-language-de/package.json",
    "content": "{\n  \"name\": \"@lokidb/full-text-search-language-de\",\n  \"description\": \"A german language analyzer.\",\n  \"author\": \"Various authors\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/LokiJS-Forge/LokiDB.git\"\n  },\n  \"main\": \"lokidb.full-text-search-language-de.js\",\n  \"types\": \"./types/full-text-search-language-de/src/index.d.ts\",\n  \"dependencies\": {\n    \"@lokidb/full-text-search\": \"0\",\n    \"@lokidb/full-text-search-language\": \"0\"\n  }\n}\n"
  },
  {
    "path": "packages/full-text-search-language-de/spec/generic/german_analyzer.spec.ts",
    "content": "import { GermanAnalyzer } from \"../../src/german_analyzer\";\nimport { createLanguageTest, LanguageTestData } from \"../../../full-text-search-language/spec/helper/create_lanuage_test.helper\";\n\nexport const de: LanguageTestData = {\n  analyzer: new GermanAnalyzer(),\n  docs: [\n    \"An Deutschland grenzen neun Nachbarländer und naturräumlich im Norden die Gewässer der Nord- und Ostsee, im Süden das Bergland der Alpen. Es liegt in der gemäßigten Klimazone, zählt mit rund 80 Millionen Einwohnern zu den dicht besiedelten Flächenstaaten und gilt international als das Land mit der dritthöchsten Zahl von Einwanderern. aufeinanderfolgenden. auffassen.\",\n    \"Deutschland als Urlaubsziel verfügt über günstige Voraussetzungen: Gebirgslandschaften (Alpen und Mittelgebirge), See- und Flusslandschaften, die Küsten und Inseln der Nord- und Ostsee, zahlreiche Kulturdenkmäler und eine Vielzahl geschichtsträchtiger Städte sowie gut ausgebaute Infrastruktur. Vorteilhaft ist die zentrale Lage in Europa.\"\n  ],\n  tests: [{\n    what: \"find the word\",\n    search: \"deutschland\",\n    expected: [0, 1]\n  }, {\n    what: \"find the word\",\n    search: \"urlaubsziel\",\n    expected: [1]\n  }, {\n    what: \"find the word\",\n    search: \"gewass\",\n    expected: [0]\n  }, {\n    what: \"find the word\",\n    search: \"verfugt\",\n    expected: [1]\n  }, {\n    what: \"never find a word that does not exist, like\",\n    search: \"inexistent\",\n    expected: []\n  }, {\n    what: \"never find a stop word like\",\n    search: \"und\",\n    expected: []\n  }, {\n    what: \"find a correctly stemmed word\",\n    search: \"auffass\",\n    expected: [0]\n  }]\n};\n\ncreateLanguageTest(\"de\", de);\n"
  },
  {
    "path": "packages/full-text-search-language-de/src/german_analyzer.ts",
    "content": "/*\n * From MihaiValentin/lunr-languages.\n * Last update from 2017/04/16 - 19af41fb9bd644d9081ad274f96f700b21464290\n */\nimport { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nimport {\n  generateTrimmer,\n  generateStopWordFilter,\n  Among,\n  SnowballProgram\n} from \"../../full-text-search-language/src/language\";\n\nclass GermanStemmer {\n  public getCurrent: () => string;\n  public setCurrent: (word: string) => void;\n  public stem: () => void;\n\n  constructor() {\n    // Write everything in the constructor to reduce code size and increase performance.\n    // The original implementation uses a ES5 anonymous function class.\n    let a_0 = [new Among(\"\", -1, 6), new Among(\"U\", 0, 2),\n      new Among(\"Y\", 0, 1), new Among(\"\\u00E4\", 0, 3),\n      new Among(\"\\u00F6\", 0, 4), new Among(\"\\u00FC\", 0, 5)\n    ];\n\n    let a_1 = [\n      new Among(\"e\", -1, 2), new Among(\"em\", -1, 1),\n      new Among(\"en\", -1, 2), new Among(\"ern\", -1, 1),\n      new Among(\"er\", -1, 1), new Among(\"s\", -1, 3),\n      new Among(\"es\", 5, 2)\n    ];\n\n    let a_2 = [new Among(\"en\", -1, 1),\n      new Among(\"er\", -1, 1), new Among(\"st\", -1, 2),\n      new Among(\"est\", 2, 1)\n    ];\n\n    let a_3 = [new Among(\"ig\", -1, 1),\n      new Among(\"lich\", -1, 1)\n    ];\n\n    let a_4 = [new Among(\"end\", -1, 1),\n      new Among(\"ig\", -1, 2), new Among(\"ung\", -1, 1),\n      new Among(\"lich\", -1, 3), new Among(\"isch\", -1, 2),\n      new Among(\"ik\", -1, 2), new Among(\"heit\", -1, 3),\n      new Among(\"keit\", -1, 4)\n    ];\n\n    let g_v = [17, 65, 16, 1, 0, 0, 0, 0, 0, 0,\n      0, 0, 0, 0, 0, 0, 8, 0, 32, 8\n    ];\n\n    let g_s_ending = [117, 30, 5];\n\n    let g_st_ending = [\n      117, 30, 4\n    ];\n\n    let I_x: number;\n    let I_p2: number;\n    let I_p1: number;\n    let sbp = new SnowballProgram();\n\n    this.setCurrent = (word: string) => {\n      sbp.setCurrent(word);\n    };\n    this.getCurrent = () => sbp.getCurrent();\n\n    function habr1(c1: string, c2: string, v_1: number) {\n      if (sbp.eq_s(1, c1)) {\n        sbp.ket = sbp.cursor;\n        if (sbp.in_grouping(g_v, 97, 252)) {\n          sbp.slice_from(c2);\n          sbp.cursor = v_1;\n          return true;\n        }\n      }\n      return false;\n    }\n\n    function r_prelude() {\n      let v_1 = sbp.cursor;\n      let v_2;\n      let v_3;\n      let v_4;\n      let v_5;\n      while (true) {\n        v_2 = sbp.cursor;\n        sbp.bra = v_2;\n        if (sbp.eq_s(1, \"\\u00DF\")) {\n          sbp.ket = sbp.cursor;\n          sbp.slice_from(\"ss\");\n        } else {\n          if (v_2 >= sbp.limit)\n            break;\n          sbp.cursor = v_2 + 1;\n        }\n      }\n      sbp.cursor = v_1;\n      while (true) {\n        v_3 = sbp.cursor;\n        while (true) {\n          v_4 = sbp.cursor;\n          if (sbp.in_grouping(g_v, 97, 252)) {\n            v_5 = sbp.cursor;\n            sbp.bra = v_5;\n            if (habr1(\"u\", \"U\", v_4))\n              break;\n            sbp.cursor = v_5;\n            if (habr1(\"y\", \"Y\", v_4))\n              break;\n          }\n          if (v_4 >= sbp.limit) {\n            sbp.cursor = v_3;\n            return;\n          }\n          sbp.cursor = v_4 + 1;\n        }\n      }\n    }\n\n    function habr2() {\n      while (!sbp.in_grouping(g_v, 97, 252)) {\n        if (sbp.cursor >= sbp.limit)\n          return true;\n        sbp.cursor++;\n      }\n      while (!sbp.out_grouping(g_v, 97, 252)) {\n        if (sbp.cursor >= sbp.limit)\n          return true;\n        sbp.cursor++;\n      }\n      return false;\n    }\n\n    function r_mark_regions() {\n      I_p1 = sbp.limit;\n      I_p2 = I_p1;\n      let c = sbp.cursor + 3;\n      if (0 <= c && c <= sbp.limit) {\n        I_x = c;\n        if (!habr2()) {\n          I_p1 = sbp.cursor;\n          if (I_p1 < I_x)\n            I_p1 = I_x;\n          if (!habr2())\n            I_p2 = sbp.cursor;\n        }\n      }\n    }\n\n    function r_postlude() {\n      let among_var;\n      let v_1;\n      while (true) {\n        v_1 = sbp.cursor;\n        sbp.bra = v_1;\n        among_var = sbp.find_among(a_0, 6);\n        if (!among_var)\n          return;\n        sbp.ket = sbp.cursor;\n        switch (among_var) {\n          case 1:\n            sbp.slice_from(\"y\");\n            break;\n          case 2:\n          case 5:\n            sbp.slice_from(\"u\");\n            break;\n          case 3:\n            sbp.slice_from(\"a\");\n            break;\n          case 4:\n            sbp.slice_from(\"o\");\n            break;\n          case 6:\n            if (sbp.cursor >= sbp.limit)\n              return;\n            sbp.cursor++;\n            break;\n        }\n      }\n    }\n\n    function r_R1() {\n      return I_p1 <= sbp.cursor;\n    }\n\n    function r_R2() {\n      return I_p2 <= sbp.cursor;\n    }\n\n    function r_standard_suffix() {\n      let among_var;\n      let v_1 = sbp.limit - sbp.cursor;\n      let v_2;\n      let v_3;\n      let v_4;\n      sbp.ket = sbp.cursor;\n      among_var = sbp.find_among_b(a_1, 7);\n      if (among_var) {\n        sbp.bra = sbp.cursor;\n        if (r_R1()) {\n          switch (among_var) {\n            case 1:\n              sbp.slice_del();\n              break;\n            case 2:\n              sbp.slice_del();\n              sbp.ket = sbp.cursor;\n              if (sbp.eq_s_b(1, \"s\")) {\n                sbp.bra = sbp.cursor;\n                if (sbp.eq_s_b(3, \"nis\"))\n                  sbp.slice_del();\n              }\n              break;\n            case 3:\n              if (sbp.in_grouping_b(g_s_ending, 98, 116))\n                sbp.slice_del();\n              break;\n          }\n        }\n      }\n      sbp.cursor = sbp.limit - v_1;\n      sbp.ket = sbp.cursor;\n      among_var = sbp.find_among_b(a_2, 4);\n      if (among_var) {\n        sbp.bra = sbp.cursor;\n        if (r_R1()) {\n          switch (among_var) {\n            case 1:\n              sbp.slice_del();\n              break;\n            case 2:\n              if (sbp.in_grouping_b(g_st_ending, 98, 116)) {\n                let c = sbp.cursor - 3;\n                if (sbp.limit_backward <= c && c <= sbp.limit) {\n                  sbp.cursor = c;\n                  sbp.slice_del();\n                }\n              }\n              break;\n          }\n        }\n      }\n      sbp.cursor = sbp.limit - v_1;\n      sbp.ket = sbp.cursor;\n      among_var = sbp.find_among_b(a_4, 8);\n      if (among_var) {\n        sbp.bra = sbp.cursor;\n        if (r_R2()) {\n          switch (among_var) {\n            case 1:\n              sbp.slice_del();\n              sbp.ket = sbp.cursor;\n              if (sbp.eq_s_b(2, \"ig\")) {\n                sbp.bra = sbp.cursor;\n                v_2 = sbp.limit - sbp.cursor;\n                if (!sbp.eq_s_b(1, \"e\")) {\n                  sbp.cursor = sbp.limit - v_2;\n                  if (r_R2())\n                    sbp.slice_del();\n                }\n              }\n              break;\n            case 2:\n              v_3 = sbp.limit - sbp.cursor;\n              if (!sbp.eq_s_b(1, \"e\")) {\n                sbp.cursor = sbp.limit - v_3;\n                sbp.slice_del();\n              }\n              break;\n            case 3:\n              sbp.slice_del();\n              sbp.ket = sbp.cursor;\n              v_4 = sbp.limit - sbp.cursor;\n              if (!sbp.eq_s_b(2, \"er\")) {\n                sbp.cursor = sbp.limit - v_4;\n                if (!sbp.eq_s_b(2, \"en\"))\n                  break;\n              }\n              sbp.bra = sbp.cursor;\n              if (r_R1())\n                sbp.slice_del();\n              break;\n            case 4:\n              sbp.slice_del();\n              sbp.ket = sbp.cursor;\n              among_var = sbp.find_among_b(a_3, 2);\n              if (among_var) {\n                sbp.bra = sbp.cursor;\n                if (r_R2() && among_var === 1)\n                  sbp.slice_del();\n              }\n              break;\n          }\n        }\n      }\n    }\n\n    this.stem = () => {\n      let v_1 = sbp.cursor;\n      r_prelude();\n      sbp.cursor = v_1;\n      r_mark_regions();\n      sbp.limit_backward = v_1;\n      sbp.cursor = sbp.limit;\n      r_standard_suffix();\n      sbp.cursor = sbp.limit_backward;\n      r_postlude();\n    };\n  }\n}\n\n// Split at whitespace and dashes.\nfunction splitter(str: string) {\n  let trimmedTokens = [];\n  let tokens = str.split(/[\\s-]+/);\n  for (let i = 0; i < tokens.length; i++) {\n    if (tokens[i] !== \"\") {\n      trimmedTokens.push(tokens[i].toLowerCase());\n    }\n  }\n  return trimmedTokens;\n}\n\nconst st = new GermanStemmer();\n\nfunction stemmer(token: string) {\n  st.setCurrent(token);\n  st.stem();\n  return st.getCurrent();\n}\n\nconst trimmer = generateTrimmer(\"A-Za-z\\xAA\\xBA\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\u02B8\\u02E0-\\u02E4\\u1D00-\\u1D25\\u1D2C-\\u1D5C\\u1D62-\\u1D65\\u1D6B-\\u1D77\\u1D79-\\u1DBE\\u1E00-\\u1EFF\\u2071\\u207F\\u2090-\\u209C\\u212A\\u212B\\u2132\\u214E\\u2160-\\u2188\\u2C60-\\u2C7F\\uA722-\\uA787\\uA78B-\\uA7AD\\uA7B0-\\uA7B7\\uA7F7-\\uA7FF\\uAB30-\\uAB5A\\uAB5C-\\uAB64\\uFB00-\\uFB06\\uFF21-\\uFF3A\\uFF41-\\uFF5A\");\nconst stopWordFilter = generateStopWordFilter([\"aber\", \"alle\", \"allem\", \"allen\", \"aller\", \"alles\", \"als\", \"also\", \"am\", \"an\", \"ander\", \"andere\", \"anderem\", \"anderen\", \"anderer\", \"anderes\", \"anderm\", \"andern\", \"anderr\", \"anders\", \"auch\", \"auf\", \"aus\", \"bei\", \"bin\", \"bis\", \"bist\", \"da\", \"damit\", \"dann\", \"das\", \"dasselbe\", \"dazu\", \"daß\", \"dein\", \"deine\", \"deinem\", \"deinen\", \"deiner\", \"deines\", \"dem\", \"demselben\", \"den\", \"denn\", \"denselben\", \"der\", \"derer\", \"derselbe\", \"derselben\", \"des\", \"desselben\", \"dessen\", \"dich\", \"die\", \"dies\", \"diese\", \"dieselbe\", \"dieselben\", \"diesem\", \"diesen\", \"dieser\", \"dieses\", \"dir\", \"doch\", \"dort\", \"du\", \"durch\", \"ein\", \"eine\", \"einem\", \"einen\", \"einer\", \"eines\", \"einig\", \"einige\", \"einigem\", \"einigen\", \"einiger\", \"einiges\", \"einmal\", \"er\", \"es\", \"etwas\", \"euch\", \"euer\", \"eure\", \"eurem\", \"euren\", \"eurer\", \"eures\", \"für\", \"gegen\", \"gewesen\", \"hab\", \"habe\", \"haben\", \"hat\", \"hatte\", \"hatten\", \"hier\", \"hin\", \"hinter\", \"ich\", \"ihm\", \"ihn\", \"ihnen\", \"ihr\", \"ihre\", \"ihrem\", \"ihren\", \"ihrer\", \"ihres\", \"im\", \"in\", \"indem\", \"ins\", \"ist\", \"jede\", \"jedem\", \"jeden\", \"jeder\", \"jedes\", \"jene\", \"jenem\", \"jenen\", \"jener\", \"jenes\", \"jetzt\", \"kann\", \"kein\", \"keine\", \"keinem\", \"keinen\", \"keiner\", \"keines\", \"können\", \"könnte\", \"machen\", \"man\", \"manche\", \"manchem\", \"manchen\", \"mancher\", \"manches\", \"mein\", \"meine\", \"meinem\", \"meinen\", \"meiner\", \"meines\", \"mich\", \"mir\", \"mit\", \"muss\", \"musste\", \"nach\", \"nicht\", \"nichts\", \"noch\", \"nun\", \"nur\", \"ob\", \"oder\", \"ohne\", \"sehr\", \"sein\", \"seine\", \"seinem\", \"seinen\", \"seiner\", \"seines\", \"selbst\", \"sich\", \"sie\", \"sind\", \"so\", \"solche\", \"solchem\", \"solchen\", \"solcher\", \"solches\", \"soll\", \"sollte\", \"sondern\", \"sonst\", \"um\", \"und\", \"uns\", \"unse\", \"unsem\", \"unsen\", \"unser\", \"unses\", \"unter\", \"viel\", \"vom\", \"von\", \"vor\", \"war\", \"waren\", \"warst\", \"was\", \"weg\", \"weil\", \"weiter\", \"welche\", \"welchem\", \"welchen\", \"welcher\", \"welches\", \"wenn\", \"werde\", \"werden\", \"wie\", \"wieder\", \"will\", \"wir\", \"wird\", \"wirst\", \"wo\", \"wollen\", \"wollte\", \"während\", \"würde\", \"würden\", \"zu\", \"zum\", \"zur\", \"zwar\", \"zwischen\", \"über\"]);\n\n// Export the analyzer.\nexport class GermanAnalyzer implements Analyzer {\n  tokenizer = splitter;\n  token_filter = [trimmer, stemmer, stopWordFilter];\n}\n"
  },
  {
    "path": "packages/full-text-search-language-de/src/index.ts",
    "content": "import { GermanAnalyzer } from \"./german_analyzer\";\nexport {GermanAnalyzer};\nexport default GermanAnalyzer;\n"
  },
  {
    "path": "packages/full-text-search-language-de/webpack.config.js",
    "content": "/* global __dirname, module, require */\nconst path = require(\"path\");\nconst webpackConigCreator = require('../../config/webpack-config-creator.js');\n\nmodule.exports = webpackConigCreator({\n  entry: path.join(__dirname, \"src\", \"index.ts\"),\n  filename: \"lokidb.full-text-search-language-de.js\",\n  library: \"@lokidb/full-text-search-language-de\",\n  externals: {\n    \"../../full-text-search-language/src/language\": \"@lokidb/full-text-search-language\",\n    \"../../full-text-search/src/index\": \"@lokidb/full-text-search\"\n  },\n});\n"
  },
  {
    "path": "packages/full-text-search-language-en/package.json",
    "content": "{\n  \"name\": \"@lokidb/full-text-search-language-en\",\n  \"description\": \"An English language analyzer.\",\n  \"author\": \"Various authors\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/LokiJS-Forge/LokiDB.git\"\n  },\n  \"main\": \"lokidb.full-text-search-language-en.js\",\n  \"types\": \"./types/full-text-search-language-en/src/index.d.ts\",\n  \"dependencies\": {\n    \"@lokidb/full-text-search\": \"0\",\n    \"@lokidb/full-text-search-language\": \"0\"\n  }\n}\n"
  },
  {
    "path": "packages/full-text-search-language-en/spec/generic/english_analyzer.spec.ts",
    "content": "import { EnglishAnalyzer } from \"../../src/english_analyzer\";\nimport { createLanguageTest, LanguageTestData } from \"../../../full-text-search-language/spec/helper/create_lanuage_test.helper\";\n\nexport const en: LanguageTestData = {\n  analyzer: new EnglishAnalyzer(),\n  docs: [\n    \"In on announcing if of comparison pianoforte projection. Maids hoped gay yet bed asked blind dried point. On abroad danger likely regret twenty edward do. Too horrible consider followed may differed age.\",\n    \"By so delight of showing neither believe he present. Deal sigh up in shew away when. Pursuit considering express no or prepare replied.\"\n  ],\n  tests: [{\n    what: \"find the word\",\n    search: \"announcing\",\n    expected: [0]\n  }, {\n    what: \"find the word\",\n    search: \"believe\",\n    expected: [1]\n  }, {\n    what: \"find the word\",\n    search: \"consider\",\n    expected: [0, 1]\n  }, {\n    what: \"find the word\",\n    search: \"show\",\n    expected: [1]\n  }, {\n    what: \"never find a word that does not exist, like\",\n    search: \"inexistent\",\n    expected: []\n  }, {\n    what: \"never find a stop word like\",\n    search: \"neither\",\n    expected: []\n  }, {\n    what: \"find a correctly stemmed word\",\n    search: \"show\",\n    expected: [1]\n  }]\n};\n\ncreateLanguageTest(\"en\", en);\n"
  },
  {
    "path": "packages/full-text-search-language-en/src/english_analyzer.ts",
    "content": "/*\n * From olivernn/lunr.js.\n * Last update from 2017/10/14 - 2dc9c6c6c41b1f5850f2bed0a82d8cd45835d166\n */\nimport { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\nimport {\n  generateTrimmer,\n  generateStopWordFilter,\n} from \"../../full-text-search-language/src/language\";\n\nclass EnglishStemmer {\n  public porterStemmer: (token: string) => string;\n\n  constructor() {\n    // Write everything in the constructor to reduce code size and increase performance.\n    // The original implementation uses a ES5 anonymous function class.\n    const step2list = {\n      \"ational\": \"ate\",\n      \"tional\": \"tion\",\n      \"enci\": \"ence\",\n      \"anci\": \"ance\",\n      \"izer\": \"ize\",\n      \"bli\": \"ble\",\n      \"alli\": \"al\",\n      \"entli\": \"ent\",\n      \"eli\": \"e\",\n      \"ousli\": \"ous\",\n      \"ization\": \"ize\",\n      \"ation\": \"ate\",\n      \"ator\": \"ate\",\n      \"alism\": \"al\",\n      \"iveness\": \"ive\",\n      \"fulness\": \"ful\",\n      \"ousness\": \"ous\",\n      \"aliti\": \"al\",\n      \"iviti\": \"ive\",\n      \"biliti\": \"ble\",\n      \"logi\": \"log\"\n    };\n\n    const step3list = {\n      \"icate\": \"ic\",\n      \"ative\": \"\",\n      \"alize\": \"al\",\n      \"iciti\": \"ic\",\n      \"ical\": \"ic\",\n      \"ful\": \"\",\n      \"ness\": \"\"\n    };\n\n    const c = \"[^aeiou]\";          // consonant\n    const v = \"[aeiouy]\";          // vowel\n    const C = c + \"[^aeiouy]*\";    // consonant sequence\n    const V = v + \"[aeiou]*\";      // vowel sequence\n\n    const mgr0 = \"^(\" + C + \")?\" + V + C;                    // [C]VC... is m>0\n    const meq1 = \"^(\" + C + \")?\" + V + C + \"(\" + V + \")?$\";  // [C]VC[V] is m=1\n    const mgr1 = \"^(\" + C + \")?\" + V + C + V + C;            // [C]VCVC... is m>1\n    const s_v = \"^(\" + C + \")?\" + v;                         // vowel in stem\n\n    const re_mgr0 = new RegExp(mgr0);\n    const re_mgr1 = new RegExp(mgr1);\n    const re_meq1 = new RegExp(meq1);\n    const re_s_v = new RegExp(s_v);\n\n    const re_1a = /^(.+?)(ss|i)es$/;\n    const re2_1a = /^(.+?)([^s])s$/;\n    const re_1b = /^(.+?)eed$/;\n    const re2_1b = /^(.+?)(ed|ing)$/;\n    const re_1b_2 = /.$/;\n    const re2_1b_2 = /(at|bl|iz)$/;\n    const re3_1b_2 = new RegExp(\"([^aeiouylsz])\\\\1$\");\n    const re4_1b_2 = new RegExp(`^${C}${v}[^aeiouwxy]$`);\n\n    const re_1c = /^(.+?[^aeiou])y$/;\n    const re_2 = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;\n\n    const re_3 = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;\n\n    const re_4 = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;\n    const re2_4 = /^(.+?)([st])(ion)$/;\n\n    const re_5 = /^(.+?)e$/;\n    const re_5_1 = /ll$/;\n    const re3_5 = new RegExp(\"^\" + C + v + \"[^aeiouwxy]$\");\n\n    this.porterStemmer = (w: string) => {\n      let stem;\n      let suffix;\n      let firstch;\n      let re;\n      let re2;\n      let re3;\n      let re4;\n\n      if (w.length < 3) {\n        return w;\n      }\n\n      firstch = w.substr(0, 1);\n      if (firstch === \"y\") {\n        w = firstch.toUpperCase() + w.substr(1);\n      }\n\n      // Step 1a\n      re = re_1a;\n      re2 = re2_1a;\n\n      if (re.test(w)) {\n        w = w.replace(re, \"$1$2\");\n      }\n      else if (re2.test(w)) {\n        w = w.replace(re2, \"$1$2\");\n      }\n\n      // Step 1b\n      re = re_1b;\n      re2 = re2_1b;\n      if (re.test(w)) {\n        const fp = re.exec(w);\n        re = re_mgr0;\n        if (re.test(fp[1])) {\n          re = re_1b_2;\n          w = w.replace(re, \"\");\n        }\n      } else if (re2.test(w)) {\n        const fp = re2.exec(w);\n        stem = fp[1];\n        re2 = re_s_v;\n        if (re2.test(stem)) {\n          w = stem;\n          re2 = re2_1b_2;\n          re3 = re3_1b_2;\n          re4 = re4_1b_2;\n          if (re2.test(w)) {\n            w = w + \"e\";\n          }\n          else if (re3.test(w)) {\n            re = re_1b_2;\n            w = w.replace(re, \"\");\n          }\n          else if (re4.test(w)) {\n            w = w + \"e\";\n          }\n        }\n      }\n\n      // Step 1c - replace suffix y or Y by i if preceded by a non-vowel which is not the first letter of the word (so cry -> cri, by -> by, say -> say)\n      re = re_1c;\n      if (re.test(w)) {\n        const fp = re.exec(w);\n        stem = fp[1];\n        w = stem + \"i\";\n      }\n\n      // Step 2\n      re = re_2;\n      if (re.test(w)) {\n        const fp = re.exec(w);\n        stem = fp[1];\n        suffix = fp[2];\n        re = re_mgr0;\n        if (re.test(stem)) {\n          w = stem + step2list[suffix];\n        }\n      }\n\n      // Step 3\n      re = re_3;\n      if (re.test(w)) {\n        const fp = re.exec(w);\n        stem = fp[1];\n        suffix = fp[2];\n        re = re_mgr0;\n        if (re.test(stem)) {\n          w = stem + step3list[suffix];\n        }\n      }\n\n      // Step 4\n      re = re_4;\n      re2 = re2_4;\n      if (re.test(w)) {\n        const fp = re.exec(w);\n        stem = fp[1];\n        re = re_mgr1;\n        if (re.test(stem)) {\n          w = stem;\n        }\n      } else if (re2.test(w)) {\n        const fp = re2.exec(w);\n        stem = fp[1] + fp[2];\n        re2 = re_mgr1;\n        if (re2.test(stem)) {\n          w = stem;\n        }\n      }\n\n      // Step 5\n      re = re_5;\n      if (re.test(w)) {\n        const fp = re.exec(w);\n        stem = fp[1];\n        re = re_mgr1;\n        re2 = re_meq1;\n        re3 = re3_5;\n        if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) {\n          w = stem;\n        }\n      }\n\n      re = re_5_1;\n      re2 = re_mgr1;\n      if (re.test(w) && re2.test(w)) {\n        re = re_1b_2;\n        w = w.replace(re, \"\");\n      }\n\n      // and turn initial Y back to y\n\n      if (firstch === \"y\") {\n        w = firstch.toLowerCase() + w.substr(1);\n      }\n\n      return w;\n    };\n  }\n}\n\n// Split at whitespace and dashes.\nfunction splitter(str: string) {\n  let trimmedTokens = [];\n  let tokens = str.split(/[\\s-]+/);\n  for (let i = 0; i < tokens.length; i++) {\n    if (tokens[i] !== \"\") {\n      trimmedTokens.push(tokens[i].toLowerCase());\n    }\n  }\n  return trimmedTokens;\n}\n\nconst st = new EnglishStemmer();\n\nfunction stemmer(token: string) {\n  return st.porterStemmer(token);\n}\n\nconst trimmer = generateTrimmer(\"A-Za-z\\xAA\\xBA\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\u02B8\\u02E0-\\u02E4\\u1D00-\\u1D25\\u1D2C-\\u1D5C\\u1D62-\\u1D65\\u1D6B-\\u1D77\\u1D79-\\u1DBE\\u1E00-\\u1EFF\\u2071\\u207F\\u2090-\\u209C\\u212A\\u212B\\u2132\\u214E\\u2160-\\u2188\\u2C60-\\u2C7F\\uA722-\\uA787\\uA78B-\\uA7AD\\uA7B0-\\uA7B7\\uA7F7-\\uA7FF\\uAB30-\\uAB5A\\uAB5C-\\uAB64\\uFB00-\\uFB06\\uFF21-\\uFF3A\\uFF41-\\uFF5A\");\nconst stopWordFilter = generateStopWordFilter([\"a\", \"able\", \"about\", \"across\", \"after\", \"all\", \"almost\", \"also\", \"am\", \"among\", \"an\", \"and\", \"any\", \"are\", \"as\", \"at\", \"be\", \"because\", \"been\", \"but\", \"by\", \"can\", \"cannot\", \"could\", \"dear\", \"did\", \"do\", \"does\", \"either\", \"else\", \"ever\", \"every\", \"for\", \"from\", \"get\", \"got\", \"had\", \"has\", \"have\", \"he\", \"her\", \"hers\", \"him\", \"his\", \"how\", \"however\", \"i\", \"if\", \"in\", \"into\", \"is\", \"it\", \"its\", \"just\", \"least\", \"let\", \"like\", \"likely\", \"may\", \"me\", \"might\", \"most\", \"must\", \"my\", \"neither\", \"no\", \"nor\", \"not\", \"of\", \"off\", \"often\", \"on\", \"only\", \"or\", \"other\", \"our\", \"own\", \"rather\", \"said\", \"say\", \"says\", \"she\", \"should\", \"since\", \"so\", \"some\", \"than\", \"that\", \"the\", \"their\", \"them\", \"then\", \"there\", \"these\", \"they\", \"this\", \"tis\", \"to\", \"too\", \"twas\", \"us\", \"wants\", \"was\", \"we\", \"were\", \"what\", \"when\", \"where\", \"which\", \"while\", \"who\", \"whom\", \"why\", \"will\", \"with\", \"would\", \"yet\", \"you\", \"your\"]);\n\n// Export the analyzer.\nexport class EnglishAnalyzer implements Analyzer {\n  tokenizer = splitter;\n  token_filter = [trimmer, stemmer, stopWordFilter];\n}\n"
  },
  {
    "path": "packages/full-text-search-language-en/src/index.ts",
    "content": "import { EnglishAnalyzer } from \"./english_analyzer\";\nexport {EnglishAnalyzer};\nexport default EnglishAnalyzer;\n"
  },
  {
    "path": "packages/full-text-search-language-en/webpack.config.js",
    "content": "/* global __dirname, module, require */\nconst path = require(\"path\");\nconst webpackConigCreator = require('../../config/webpack-config-creator.js');\n\nmodule.exports = webpackConigCreator({\n  entry: path.join(__dirname, \"src\", \"index.ts\"),\n  filename: \"lokidb.full-text-search-language-en.js\",\n  library: \"@lokidb/full-text-search-language-en\",\n  externals: {\n    \"../../full-text-search-language/src/language\": \"@lokidb/full-text-search-language\",\n    \"../../full-text-search/src/index\": \"@lokidb/full-text-search\"\n  },\n});\n"
  },
  {
    "path": "packages/indexed-storage/package.json",
    "content": "{\n  \"name\": \"@lokidb/indexed-storage\",\n  \"description\": \"A persistence adapter which persists to web browser's indexed db storage.\",\n  \"author\": \"Various authors\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/LokiJS-Forge/LokiDB.git\"\n  },\n  \"main\": \"lokidb.indexed-storage.js\",\n  \"types\": \"./types/indexed-storage/src/index.d.ts\",\n  \"dependencies\": {\n    \"@lokidb/loki\": \"0\"\n  }\n}\n"
  },
  {
    "path": "packages/indexed-storage/spec/web/indexed_storage.spec.ts",
    "content": "/* global describe, it, expect */\nimport { Loki } from \"../../../loki/src/loki\";\nimport { IndexedStorage } from \"../../src/indexed_storage\";\n\ndescribe(\"testing indexed storage\", function () {\n\n  interface Name {\n    name: string;\n  }\n\n  beforeAll(() => {\n    IndexedStorage.register();\n  });\n\n  afterAll(() => {\n    IndexedStorage.deregister();\n  });\n\n  it(\"LokiIndexedStorage\", function (done) {\n    const db = new Loki(\"myTestApp\");\n    const adapter = {adapter: new IndexedStorage()};\n    db.initializePersistence(adapter)\n      .then(() => {\n        db.addCollection<Name>(\"myColl\").insert({name: \"Hello World\"});\n        return db.saveDatabase();\n      })\n      .then(() => {\n        const db2 = new Loki(\"myTestApp\");\n        return db2.initializePersistence()\n          .then(() => {\n            return db2.loadDatabase();\n          }).then(() => {\n            expect(db2.getCollection<Name>(\"myColl\").find()[0].name).toEqual(\"Hello World\");\n          });\n      })\n      .then(() => {\n        const db2 = new Loki(\"myTestApp\");\n        return db2.initializePersistence({persistenceMethod: \"indexed-storage\"})\n          .then(() => {\n            return db2.loadDatabase();\n          }).then(() => {\n            expect(db2.getCollection<Name>(\"myColl\").find()[0].name).toEqual(\"Hello World\");\n          });\n      })\n      .then(() => {\n        const db3 = new Loki(\"other\");\n        return db3.initializePersistence()\n          .then(() => {\n            return db3.loadDatabase();\n          }).then(() => {\n            expect(false).toEqual(true);\n          }, () => {\n            expect(true).toEqual(true);\n          });\n      })\n      .then(() => {\n        return db.deleteDatabase();\n      })\n      .then(() => {\n        return db.loadDatabase()\n          .then(() => {\n            expect(db.getCollection<Name>(\"myColl\").find()[0].name).toEqual(\"Hello World\");\n            expect(false).toEqual(true);\n            done();\n          }, () => {\n            expect(true).toEqual(true);\n            done();\n          });\n      });\n  });\n\n  it(\"auto save and auto load\", function (done) {\n    const db = new Loki(\"myTestApp2\");\n\n    db.initializePersistence({autosave: true, autoload: true})\n      .then(() => {\n        db.addCollection<Name>(\"myColl\").insert({name: \"Hello World\"});\n        return db.close();\n      })\n      .then(() => {\n        const db2 = new Loki(\"myTestApp2\");\n        return db2.initializePersistence({autosave: true, autoload: true})\n          .then(() => {\n            expect(db2.getCollection<Name>(\"myColl\").find()[0].name).toEqual(\"Hello World\");\n          });\n      })\n      .catch(e => {\n        fail(e);\n      })\n      .then(() => {\n        done();\n      });\n  });\n});\n"
  },
  {
    "path": "packages/indexed-storage/src/index.ts",
    "content": "import { IndexedStorage } from \"./indexed_storage\";\n\nexport {IndexedStorage};\nexport default IndexedStorage;\n"
  },
  {
    "path": "packages/indexed-storage/src/indexed_storage.ts",
    "content": "import { PLUGINS } from \"../../common/plugin\";\nimport { StorageAdapter } from \"../../common/types\";\n\n/*\n Loki IndexedDb Adapter (need to include this script to use it)\n\n Console Usage can be used for management/diagnostic, here are a few examples :\n adapter.getDatabaseList(); // with no callback passed, this method will log results to console\n adapter.saveDatabase(\"UserDatabase\", JSON.stringify(myDb));\n adapter.loadDatabase(\"UserDatabase\"); // will log the serialized db to console\n adapter.deleteDatabase(\"UserDatabase\");\n\n Should usercallback be still used?\n */\n\n/**\n * @hidden\n */\ndeclare type ANY = any;\n\n/**\n * Loki persistence adapter class for indexedDb.\n *     This class fulfills abstract adapter interface which can be applied to other storage methods.\n *     Utilizes the included LokiCatalog app/key/value database for actual database persistence.\n *     IndexedDb storage is provided per-domain, so we implement app/key/value database to\n *     allow separate contexts for separate apps within a domain.\n */\nexport class IndexedStorage implements StorageAdapter {\n  private _appname: string;\n  private catalog: any;\n\n  /**\n   * Registers the indexed storage as plugin.\n   */\n  static register(): void {\n    PLUGINS[\"IndexedStorage\"] = IndexedStorage;\n  }\n\n  /**\n   * Deregisters the indexed storage as plugin.\n   */\n  static deregister(): void {\n    delete PLUGINS[\"IndexedStorage\"];\n  }\n\n  /**\n   * @param {string} [appname=loki] - Application name context can be used to distinguish subdomains, \"loki\" by default\n   */\n  constructor(appname: string = \"loki\") {\n    this._appname = appname;\n\n    // keep reference to catalog class for base AKV operations\n    this.catalog = null;\n  }\n\n  /**\n   * Retrieves a serialized db string from the catalog.\n   *\n   * @example\n   * // LOAD\n   * var idbAdapter = new LokiIndexedAdapter(\"finance\");\n   * var db = new loki(\"test\", { adapter: idbAdapter });\n   *   db.base(function(result) {\n\t *   console.log(\"done\");\n\t * });\n   *\n   * @param {string} dbname - the name of the database to retrieve.\n   * @returns {Promise} a Promise that resolves after the database was loaded\n   */\n  loadDatabase(dbname: string) {\n    const appName = this._appname;\n    const adapter = this;\n\n    // lazy open/create db reference so dont -need- callback in constructor\n    if (this.catalog === null || this.catalog.db === null) {\n      return new Promise((resolve) => {\n        adapter.catalog = new LokiCatalog((cat: LokiCatalog) => {\n          adapter.catalog = cat;\n          resolve(adapter.loadDatabase(dbname));\n        });\n      });\n    }\n    // lookup up db string in AKV db\n    return new Promise((resolve, reject) => {\n      this.catalog.getAppKey(appName, dbname, (result: ANY) => {\n        if (result.id === 0) {\n          reject(null);\n          return;\n        }\n        resolve(result.val);\n      });\n    });\n  }\n\n  /**\n   * Saves a serialized db to the catalog.\n   *\n   * @example\n   * // SAVE : will save App/Key/Val as \"finance\"/\"test\"/{serializedDb}\n   * let idbAdapter = new LokiIndexedAdapter(\"finance\");\n   * let db = new loki(\"test\", { adapter: idbAdapter });\n   * let coll = db.addCollection(\"testColl\");\n   * coll.insert({test: \"val\"});\n   * db.saveDatabase();  // could pass callback if needed for async complete\n   *\n   * @param {string} dbname - the name to give the serialized database within the catalog.\n   * @param {string} dbstring - the serialized db string to save.\n   * @returns {Promise} a Promise that resolves after the database was persisted\n   */\n  saveDatabase(dbname: string, dbstring: string): Promise<void> {\n    const appName = this._appname;\n    const adapter = this;\n\n    let resolve: ANY;\n    let reject: ANY;\n    const result = new Promise<void>((res: ANY, rej: ANY) => {\n      resolve = res;\n      reject = rej;\n    });\n\n    function saveCallback(result: ANY) {\n      if (result && result.success === true) {\n        resolve();\n      } else {\n        reject(new Error(\"Error saving database\"));\n      }\n    }\n\n    // lazy open/create db reference so dont -need- callback in constructor\n    if (this.catalog === null || this.catalog.db === null) {\n      this.catalog = new LokiCatalog((cat: LokiCatalog) => {\n        adapter.catalog = cat;\n\n        // now that catalog has been initialized, set (add/update) the AKV entry\n        cat.setAppKey(appName, dbname, dbstring, saveCallback);\n      });\n\n      return result;\n    }\n\n    // set (add/update) entry to AKV database\n    this.catalog.setAppKey(appName, dbname, dbstring, saveCallback);\n\n    return result;\n  }\n\n  /**\n   * Deletes a serialized db from the catalog.\n   *\n   * @example\n   * // DELETE DATABASE\n   * // delete \"finance\"/\"test\" value from catalog\n   * idbAdapter.deleteDatabase(\"test\", function {\n\t *   // database deleted\n\t * });\n   *\n   * @param {string} dbname - the name of the database to delete from the catalog.\n   * @returns {Promise} a Promise that resolves after the database was deleted\n   */\n  deleteDatabase(dbname: string): Promise<void> {\n    const appName = this._appname;\n    const adapter = this;\n\n    // lazy open/create db reference and pass callback ahead\n    if (this.catalog === null || this.catalog.db === null) {\n      return new Promise((resolve) => {\n        adapter.catalog = new LokiCatalog((cat: LokiCatalog) => {\n          adapter.catalog = cat;\n\n          resolve(adapter.deleteDatabase(dbname));\n        });\n      });\n    }\n\n    // catalog was already initialized, so just lookup object and delete by id\n    return new Promise((resolve) => {\n      this.catalog.getAppKey(appName, dbname, (result: ANY) => {\n        const id = result.id;\n\n        if (id !== 0) {\n          adapter.catalog.deleteAppKey(id);\n        }\n\n        resolve();\n      });\n    });\n  }\n\n  /**\n   * Removes all database partitions and pages with the base filename passed in.\n   * This utility method does not (yet) guarantee async deletions will be completed before returning\n   *\n   * @param {string} dbname - the base filename which container, partitions, or pages are derived\n   */\n  deleteDatabasePartitions(dbname: string) {\n    this.getDatabaseList((result: string[]) => {\n      result.forEach((str) => {\n        if (str.startsWith(dbname)) {\n          this.deleteDatabase(str);\n        }\n      });\n    });\n  }\n\n  /**\n   * Retrieves object array of catalog entries for current app.\n   *\n   * @example\n   * idbAdapter.getDatabaseList(function(result) {\n\t *   // result is array of string names for that appcontext (\"finance\")\n\t *   result.forEach(function(str) {\n\t *     console.log(str);\n\t *   });\n\t * });\n   *\n   * @param {function} callback - should accept array of database names in the catalog for current app.\n   */\n  getDatabaseList(callback: (names: string[]) => void) {\n    const appName = this._appname;\n    const adapter = this;\n\n    // lazy open/create db reference so dont -need- callback in constructor\n    if (this.catalog === null || this.catalog.db === null) {\n      this.catalog = new LokiCatalog((cat: LokiCatalog) => {\n        adapter.catalog = cat;\n\n        adapter.getDatabaseList(callback);\n      });\n\n      return;\n    }\n\n    // catalog already initialized\n    // get all keys for current appName, and transpose results so just string array\n    this.catalog.getAppKeys(appName, (results: ANY) => {\n      const names = [];\n\n      for (let idx = 0; idx < results.length; idx++) {\n        names.push(results[idx].key);\n      }\n\n      if (typeof(callback) === \"function\") {\n        callback(names);\n      } else {\n        names.forEach(() => {\n          // console.log(obj);\n        });\n      }\n    });\n  }\n\n  /**\n   * Allows retrieval of list of all keys in catalog along with size\n   * @param {function} callback - (Optional) callback to accept result array.\n   */\n  public getCatalogSummary(callback: (entry: Entry[]) => void) {\n    const adapter = this;\n\n    // lazy open/create db reference\n    if (this.catalog === null || this.catalog.db === null) {\n      this.catalog = new LokiCatalog((cat: LokiCatalog) => {\n        adapter.catalog = cat;\n\n        adapter.getCatalogSummary(callback);\n      });\n\n      return;\n    }\n\n    // catalog already initialized\n    // get all keys for current appName, and transpose results so just string array\n    this.catalog.getAllKeys((results: ANY) => {\n      const entries = [];\n      let obj;\n      let size;\n      let oapp;\n      let okey;\n      let oval;\n\n      for (let idx = 0; idx < results.length; idx++) {\n        obj = results[idx];\n        oapp = obj.app || \"\";\n        okey = obj.key || \"\";\n        oval = obj.val || \"\";\n\n        // app and key are composited into an appkey column so we will mult by 2\n        size = oapp.length * 2 + okey.length * 2 + oval.length + 1;\n\n        entries.push({\n          \"app\": obj.app,\n          \"key\": obj.key,\n          \"size\": size\n        });\n      }\n\n      if (typeof(callback) === \"function\") {\n        callback(entries);\n      } else {\n        entries.forEach(() => {\n          // console.log(obj);\n        });\n      }\n    });\n  }\n}\n\nexport interface Entry {\n  app: string;\n  key: string;\n  size: number;\n}\n\n/**\n * LokiCatalog - underlying App/Key/Value catalog persistence\n *    This non-interface class implements the actual persistence.\n *    Used by the LokiIndexedStorage class.\n */\nclass LokiCatalog {\n  public db: ANY;\n\n  constructor(callback: any) {\n    this.db = null;\n    this.initializeLokiCatalog(callback);\n  }\n\n  initializeLokiCatalog(callback: any) {\n    const openRequest = indexedDB.open(\"LokiCatalog\", 1);\n    const cat = this;\n\n    // If database doesn't exist yet or its version is lower than our version specified above (2nd param in line above)\n    openRequest.onupgradeneeded = (e: ANY) => {\n      const thisDB = e.target.result;\n      if (thisDB.objectStoreNames.contains(\"LokiAKV\")) {\n        thisDB.deleteObjectStore(\"LokiAKV\");\n      }\n\n      if (!thisDB.objectStoreNames.contains(\"LokiAKV\")) {\n        const objectStore = thisDB.createObjectStore(\"LokiAKV\", {\n          keyPath: \"id\",\n          autoIncrement: true\n        });\n        objectStore.createIndex(\"app\", \"app\", {\n          unique: false\n        });\n        objectStore.createIndex(\"key\", \"key\", {\n          unique: false\n        });\n        // hack to simulate composite key since overhead is low (main size should be in val field)\n        // user (me) required to duplicate the app and key into comma delimited appkey field off object\n        // This will allow retrieving single record with that composite key as well as\n        // still supporting opening cursors on app or key alone\n        objectStore.createIndex(\"appkey\", \"appkey\", {\n          unique: true\n        });\n      }\n    };\n\n    openRequest.onsuccess = (e: ANY) => {\n      cat.db = e.target.result;\n\n      if (typeof(callback) === \"function\")\n        callback(cat);\n    };\n\n    openRequest.onerror = (e: ANY) => {\n      throw e;\n    };\n  }\n\n  getAppKey(app: string, key: string, callback: any) {\n    const transaction = this.db.transaction([\"LokiAKV\"], \"readonly\");\n    const store = transaction.objectStore(\"LokiAKV\");\n    const index = store.index(\"appkey\");\n    const appkey = app + \",\" + key;\n    const request = index.get(appkey);\n\n    request.onsuccess = (((usercallback) => (e: ANY) => {\n      let lres = e.target.result;\n\n      if (lres === null || lres === undefined) {\n        lres = {\n          id: 0,\n          success: false\n        };\n      }\n\n      if (typeof(usercallback) === \"function\") {\n        usercallback(lres);\n      } else {\n        // console.log(lres);\n      }\n    }))(callback);\n\n    request.onerror = (((usercallback) => (e: ANY) => {\n      if (typeof(usercallback) === \"function\") {\n        usercallback({\n          id: 0,\n          success: false\n        });\n      } else {\n        throw e;\n      }\n    }))(callback);\n  }\n\n  getAppKeyById(id: string, callback: ANY, data: ANY) {\n    const transaction = this.db.transaction([\"LokiAKV\"], \"readonly\");\n    const store = transaction.objectStore(\"LokiAKV\");\n    const request = store.get(id);\n\n    request.onsuccess = (((data, usercallback) => (e: ANY) => {\n      if (typeof(usercallback) === \"function\") {\n        usercallback(e.target.result, data);\n      } else {\n        // console.log(e.target.result);\n      }\n    }))(data, callback);\n  }\n\n  setAppKey(app: string, key: string, val: string, callback: any) {\n    const transaction = this.db.transaction([\"LokiAKV\"], \"readwrite\");\n    const store = transaction.objectStore(\"LokiAKV\");\n    const index = store.index(\"appkey\");\n    const appkey = app + \",\" + key;\n    const request = index.get(appkey);\n\n    // first try to retrieve an existing object by that key\n    // need to do this because to update an object you need to have id in object, otherwise it will append id with new autocounter and clash the unique index appkey\n    request.onsuccess = (e: ANY) => {\n      let res = e.target.result;\n\n      if (res === null || res === undefined) {\n        res = {\n          app,\n          key,\n          appkey: app + \",\" + key,\n          val\n        };\n      } else {\n        res.val = val;\n      }\n\n      const requestPut = store.put(res);\n\n      requestPut.onerror = (((usercallback) => () => {\n        if (typeof(usercallback) === \"function\") {\n          usercallback({\n            success: false\n          });\n        } else {\n          // console.error(\"LokiCatalog.setAppKey (set) onerror\");\n          // console.error(request.error);\n        }\n      }))(callback);\n\n      requestPut.onsuccess = (((usercallback) => () => {\n        if (typeof(usercallback) === \"function\") {\n          usercallback({\n            success: true\n          });\n        }\n      }))(callback);\n    };\n\n    request.onerror = (((usercallback) => () => {\n      if (typeof(usercallback) === \"function\") {\n        usercallback({\n          success: false\n        });\n      } else {\n        // console.error(\"LokiCatalog.setAppKey (get) onerror\");\n        // console.error(request.error);\n      }\n    }))(callback);\n  }\n\n  deleteAppKey(id: string, callback: any) {\n    const transaction = this.db.transaction([\"LokiAKV\"], \"readwrite\");\n    const store = transaction.objectStore(\"LokiAKV\");\n    const request = store.delete(id);\n\n    request.onsuccess = (((usercallback) => () => {\n      if (typeof(usercallback) === \"function\") usercallback({\n        success: true\n      });\n    }))(callback);\n\n    request.onerror = (((usercallback) => () => {\n      if (typeof(usercallback) === \"function\") {\n        usercallback(false);\n      } else {\n        // console.error(\"LokiCatalog.deleteAppKey raised onerror\");\n        // console.error(request.error);\n      }\n    }))(callback);\n  }\n\n  getAppKeys(app: string, callback: any) {\n    const transaction = this.db.transaction([\"LokiAKV\"], \"readonly\");\n    const store = transaction.objectStore(\"LokiAKV\");\n    const index = store.index(\"app\");\n\n    // We want cursor to all values matching our (single) app param\n    const singleKeyRange = IDBKeyRange.only(app);\n\n    // To use one of the key ranges, pass it in as the first argument of openCursor()/openKeyCursor()\n    const cursor = index.openCursor(singleKeyRange);\n\n    // cursor internally, pushing results into this.data[] and return\n    // this.data[] when done (similar to service)\n    const localdata: any[] = [];\n\n    cursor.onsuccess = (((data, callback) => (e: ANY) => {\n      const cursor = e.target.result;\n      if (cursor) {\n        const currObject = cursor.value;\n\n        data.push(currObject);\n\n        cursor.continue();\n      } else {\n        if (typeof(callback) === \"function\") {\n          callback(data);\n        } else {\n          // console.log(data);\n        }\n      }\n    }))(localdata, callback);\n\n    cursor.onerror = (((usercallback) => () => {\n      if (typeof(usercallback) === \"function\") {\n        usercallback(null);\n      } else {\n        // console.error(\"LokiCatalog.getAppKeys raised onerror\");\n        // console.error(e);\n      }\n    }))(callback);\n\n  }\n\n  // Hide \"cursoring\" and return array of { id: id, key: key }\n  getAllKeys(callback: any) {\n    const transaction = this.db.transaction([\"LokiAKV\"], \"readonly\");\n    const store = transaction.objectStore(\"LokiAKV\");\n    const cursor = store.openCursor();\n\n    const localdata: ANY[] = [];\n\n    cursor.onsuccess = (((data, callback) => (e: ANY) => {\n      const cursor = e.target.result;\n      if (cursor) {\n        const currObject = cursor.value;\n\n        data.push(currObject);\n\n        cursor.continue();\n      } else {\n        if (typeof(callback) === \"function\") {\n          callback(data);\n        } else {\n          // console.log(data);\n        }\n      }\n    }))(localdata, callback);\n\n    cursor.onerror = (((usercallback) => () => {\n      if (typeof(usercallback) === \"function\") usercallback(null);\n    }))(callback);\n  }\n}\n\nexport default IndexedStorage;\n"
  },
  {
    "path": "packages/indexed-storage/webpack.config.js",
    "content": "/* global __dirname, module, require */\nconst path = require(\"path\");\nconst webpackConigCreator = require('../../config/webpack-config-creator.js');\n\nmodule.exports = webpackConigCreator({\n  entry: path.join(__dirname, \"src\", \"index.ts\"),\n  filename: \"lokidb.indexed-storage.js\",\n  library: \"@lokidb/indexed-storage\",\n  externals: {\n    \"../../loki/src/loki\": \"@lokidb/loki\"\n  },\n});\n"
  },
  {
    "path": "packages/local-storage/package.json",
    "content": "{\n  \"name\": \"@lokidb/local-storage\",\n  \"description\": \"A persistence adapter which persists to web browser's local storage.\",\n  \"author\": \"Various authors\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/LokiJS-Forge/LokiDB.git\"\n  },\n  \"main\": \"lokidb.local-storage.js\",\n  \"types\": \"./types/local-storage/src/index.d.ts\",\n  \"dependencies\": {\n    \"@lokidb/loki\": \"0\"\n  }\n}\n"
  },
  {
    "path": "packages/local-storage/spec/web/local_storage.spec.ts",
    "content": "/* global describe, it, expect */\nimport { Loki } from \"../../../loki/src/loki\";\nimport { LocalStorage } from \"../../src/local_storage\";\n\ndescribe(\"testing local storage\", function () {\n\n  interface Name {\n    name: string;\n  }\n\n  beforeAll(() => {\n    LocalStorage.register();\n  });\n\n  afterAll(() => {\n    LocalStorage.deregister();\n  });\n\n  it(\"LokiLocalStorage\", function (done) {\n    const db = new Loki(\"myTestApp\");\n    const adapter = {adapter: new LocalStorage()};\n    db.initializePersistence(adapter)\n      .then(() => {\n        db.addCollection<Name>(\"myColl\").insert({name: \"Hello World\"});\n        return db.saveDatabase();\n      })\n      .then(() => {\n        const db2 = new Loki(\"myTestApp\");\n        return db2.initializePersistence()\n          .then(() => {\n            return db2.loadDatabase();\n          }).then(() => {\n            expect(db2.getCollection<Name>(\"myColl\").find()[0].name).toEqual(\"Hello World\");\n          });\n      })\n      .then(() => {\n        const db2 = new Loki(\"myTestApp\");\n        return db2.initializePersistence({persistenceMethod: \"local-storage\"})\n          .then(() => {\n            return db2.loadDatabase();\n          }).then(() => {\n            expect(db2.getCollection<Name>(\"myColl\").find()[0].name).toEqual(\"Hello World\");\n          });\n      })\n      .then(() => {\n        const db3 = new Loki(\"other\");\n        return db3.initializePersistence()\n          .then(() => {\n            return db3.loadDatabase();\n          }).then(() => {\n            expect(false).toEqual(true);\n          }, () => {\n            expect(true).toEqual(true);\n          });\n      })\n      .then(() => {\n        return db.deleteDatabase();\n      })\n      .then(() => {\n        return db.loadDatabase()\n          .then(() => {\n            expect(db.getCollection<Name>(\"myColl\").find()[0].name).toEqual(\"Hello World\");\n            expect(false).toEqual(true);\n            done();\n          }, () => {\n            expect(true).toEqual(true);\n            done();\n          });\n      });\n  });\n\n\n  it(\"auto save and auto load\", function (done) {\n    const db = new Loki(\"myTestApp2\");\n\n    db.initializePersistence({autosave: true, autoload: true})\n      .then(() => {\n        db.addCollection<Name>(\"myColl\").insert({name: \"Hello World\"});\n        return db.close();\n      })\n      .then(() => {\n        const db2 = new Loki(\"myTestApp2\");\n        return db2.initializePersistence({autosave: true, autoload: true})\n          .then(() => {\n            expect(db2.getCollection<Name>(\"myColl\").find()[0].name).toEqual(\"Hello World\");\n          });\n      })\n      .catch(e => {\n        fail(e);\n      })\n      .then(() => {\n        done();\n      });\n  });\n});\n"
  },
  {
    "path": "packages/local-storage/src/index.ts",
    "content": "import { LocalStorage } from \"./local_storage\";\n\nexport {LocalStorage};\nexport default LocalStorage;\n"
  },
  {
    "path": "packages/local-storage/src/local_storage.ts",
    "content": "import { PLUGINS } from \"../../common/plugin\";\nimport { StorageAdapter } from \"../../common/types\";\n\n/**\n * A loki persistence adapter which persists to web browser's local storage object\n * @constructor LocalStorageAdapter\n */\nexport class LocalStorage implements StorageAdapter {\n  /**\n   * Registers the local storage as plugin.\n   */\n  static register(): void {\n    PLUGINS[\"LocalStorage\"] = LocalStorage;\n  }\n\n  /**\n   * Deregisters the local storage as plugin.\n   */\n  static deregister(): void {\n    delete PLUGINS[\"LocalStorage\"];\n  }\n\n  /**\n   * loadDatabase() - Load data from localstorage\n   * @param {string} dbname - the name of the database to load\n   * @returns {Promise} a Promise that resolves after the database was loaded\n   */\n  loadDatabase(dbname: string) {\n    return Promise.resolve(localStorage.getItem(dbname));\n  }\n\n  /**\n   * saveDatabase() - save data to localstorage, will throw an error if the file can't be saved\n   * might want to expand this to avoid dataloss on partial save\n   * @param {string} dbname - the filename of the database to load\n   * @returns {Promise} a Promise that resolves after the database was saved\n   */\n  saveDatabase(dbname: string, dbstring: string) {\n    return Promise.resolve(localStorage.setItem(dbname, dbstring));\n  }\n\n  /**\n   * deleteDatabase() - delete the database from localstorage, will throw an error if it\n   * can't be deleted\n   * @param {string} dbname - the filename of the database to delete\n   * @returns {Promise} a Promise that resolves after the database was deleted\n   */\n  deleteDatabase(dbname: string) {\n    return Promise.resolve(localStorage.removeItem(dbname));\n  }\n}\n\nexport default LocalStorage;\n"
  },
  {
    "path": "packages/local-storage/webpack.config.js",
    "content": "/* global __dirname, module, require */\nconst path = require(\"path\");\nconst webpackConigCreator = require('../../config/webpack-config-creator.js');\n\nmodule.exports = webpackConigCreator({\n  entry: path.join(__dirname, \"src\", \"index.ts\"),\n  filename: \"lokidb.local-storage.js\",\n  library: \"@lokidb/local-storage\",\n  externals: {\n    \"../../loki/src/loki\": \"@lokidb/loki\"\n  },\n});\n"
  },
  {
    "path": "packages/loki/package.json",
    "content": "{\n  \"name\": \"@lokidb/loki\",\n  \"description\": \"Fast document oriented javascript in-memory database\",\n  \"author\": \"Various authors\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/LokiJS-Forge/LokiDB.git\"\n  },\n  \"main\": \"lokidb.loki.js\",\n  \"types\": \"./types/loki/src/index.d.ts\"\n}\n"
  },
  {
    "path": "packages/loki/spec/generic/avl-index.spec.ts",
    "content": "import { AvlTreeIndex, TreeNode } from \"../../src/avl_index\";\nimport { IRangedIndexRequest, RangedIndexFactoryMap, IRangedIndex } from \"../../src/ranged_indexes\";\nimport { CreateJavascriptComparator, ComparatorMap, ILokiComparer } from \"../../src/comparators\";\nimport { Loki } from \"../../src/loki\";\nimport { Doc } from \"../../../common/types\";\n\ndescribe(\"avl tree index tests\", () => {\n  const possible = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n  const count = 100;\n\n  let cmp = CreateJavascriptComparator<string>();\n\n  // setup utility function for random string generation\n  let genRandomVal = () => {\n    let text = \"\";\n\n    for (let i = 0; i < 20; i++)\n      text += possible.charAt(Math.floor(Math.random() * possible.length));\n\n    return text;\n  };\n\n  // setup utility function to shuffle array\n  let shuffle = (array: any[]) => {\n    let 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  let reverseString = (str: string) => {\n    let splitString = str.split(\"\");\n    let reverseArray = splitString.reverse();\n    let joinArray = reverseArray.join(\"\");\n    return joinArray;\n  };\n\n  beforeEach(() => {\n  });\n\n  it(\"avl population works\", () => {\n    let avl = new AvlTreeIndex<string>(\"last\", cmp);\n\n    avl.insert(1, \"smith\");\n    avl.insert(2, \"patterson\");\n    avl.insert(3, \"albertson\");\n    avl.insert(4, \"gilbertson\");\n    avl.insert(5, \"yannitz\");\n    avl.insert(6, \"harrison\");\n    avl.insert(7, \"livingstone\");\n    avl.insert(8, \"gilbertson\");\n    avl.insert(9, \"lapierre\");\n\n    // get all sorted ids (since not passing an IRangeRequest)\n    let result: number[] = avl.rangeRequest();\n\n    // verify number of elements is accurate\n    expect(result.length).toEqual(9);\n\n    // verify ordering is correct\n    expect(result[0]).toEqual(3);\n    // handle the duplicate\n    expect(result[1] === 4 || result[1] === 8).toEqual(true);\n    expect(result[2] === 4 || result[2] === 8).toEqual(true);\n    expect(result[1] !== result[2]).toEqual(true);\n    // resume asserting order of remaining\n    expect(result[3]).toEqual(6);\n    expect(result[4]).toEqual(9);\n    expect(result[5]).toEqual(7);\n    expect(result[6]).toEqual(2);\n    expect(result[7]).toEqual(1);\n    expect(result[8]).toEqual(5);\n  });\n\n  it(\"avl population stress test works\", () => {\n    let avl = new AvlTreeIndex<string>(\"rand\", cmp);\n    let idbuf: number[] = [];\n    let rnd: string;\n\n    // Populate avl and retain values\n    for (let idx = 0; idx < count; idx++) {\n      rnd = genRandomVal();\n      idbuf.push(idx + 1);\n      avl.insert(idx + 1, rnd);\n    }\n\n    expect(idbuf.length).toEqual(count);\n    expect(avl.validateIndex()).toEqual(true);\n    expect(avl.rangeRequest().length).toEqual(count);\n\n    // suffle id array and then sequentially update index vals\n    shuffle(idbuf);\n    for (let id of idbuf) {\n      avl.update(id, genRandomVal());\n    }\n\n    expect(avl.validateIndex()).toEqual(true);\n    expect(avl.rangeRequest().length).toEqual(count);\n  });\n\n  it(\"avl maintenance (unique vals) stress test works\", () => {\n    let idbuf: number[] = [];\n    let rnd: string;\n\n    let avl = new AvlTreeIndex<string>(\"last\", cmp);\n\n    // insert random values into avl and retain values using numeric id greater than 0\n    for (let idx = 1; idx <= count; idx++) {\n      idbuf.push(idx);\n      rnd = genRandomVal();\n      avl.insert(idx, rnd);\n    }\n\n    expect(avl.validateIndex()).toEqual(true);\n    expect(avl.rangeRequest().length).toEqual(count);\n\n    // now update every value in the index to a different random value\n    shuffle(idbuf);\n\n    for (let id of idbuf) {\n      let urnd = genRandomVal();\n      avl.update(id, urnd);\n    }\n\n    // make sure the index is still valid\n    expect(avl.validateIndex()).toEqual(true);\n    expect(avl.rangeRequest().length).toEqual(count);\n\n    shuffle(idbuf);\n    for (let id of idbuf) {\n      avl.remove(id);\n      expect(avl.validateIndex()).toEqual(true);\n    }\n  });\n\n  it(\"avl maintenance with dups stress test works\", () => {\n    let idbuf: number[] = [];\n    let valbuf: string[] = [];\n    let rnd: string;\n\n    let avl = new AvlTreeIndex<string>(\"last\", cmp);\n\n    // insert random values into avl and retain values using numeric id greater than 0\n    for (let idx = 1; idx <= count; idx++) {\n      idbuf.push(idx);\n      rnd = genRandomVal();\n      valbuf.push(rnd);\n      avl.insert(idx, rnd);\n    }\n\n    shuffle(idbuf);\n\n    // now insert duplicate values for all previous inserted values\n    for (let idx = 0; idx < count; idx++) {\n      avl.insert(count + idx + 1, valbuf[idx]);\n    }\n\n    // make sure the index is still valid\n    expect(avl.validateIndex()).toEqual(true);\n    expect(avl.rangeRequest().length).toEqual(count * 2);\n  });\n\n  it(\"avl maintenance with dups and removes stress\", () => {\n    let idbuf: number[] = [];\n    let valbuf: string[] = [];\n    let rnd: string;\n\n    let avl = new AvlTreeIndex<string>(\"last\", cmp);\n\n    // insert random values into avl and retain values using numeric id greater than 0\n    for (let idx = 0; idx < count; idx++) {\n      idbuf.push(idx + 1);\n      rnd = genRandomVal();\n      valbuf.push(rnd);\n      avl.insert(idx + 1, rnd);\n    }\n\n    // now insert duplicate values for all previous inserted values\n    for (let idx = 0; idx < count; idx++) {\n      idbuf.push(count + idx + 1);\n      avl.insert(count + idx + 1, valbuf[idx]);\n\n      // verify siblings\n      if (avl.nodes[idx + 1].siblings.length !== 1) {\n        throw new Error(\"wrong number of siblings\");\n      }\n      if (avl.nodes[count + idx + 1].siblings.length !== 0) {\n        throw new Error(\"wrong number of siblings\");\n      }\n      if (avl.nodes[count + idx + 1].parent !== idx + 1) {\n        throw new Error(\"incorrectly parented sibling\");\n      }\n    }\n\n    // make sure the index is still valid\n    expect(avl.validateIndex()).toEqual(true);\n    expect(avl.rangeRequest().length).toEqual(count * 2);\n\n    shuffle(idbuf);\n\n    for (let idx = 0; idx < idbuf.length; idx++) {\n      avl.remove(idbuf[idx]);\n    }\n\n    // make sure the index is still valid\n    expect(avl.validateIndex()).toEqual(true);\n    expect(avl.rangeRequest().length).toEqual(0);\n  });\n\n  it(\"insert rotation balancing check\", () => {\n    // left heavy involving apex\n    // insert s,p,a\n    // expect p(a)(s)\n    let avl = new AvlTreeIndex<string>(\"last\", cmp);\n    avl.insert(1, \"smith\");\n    avl.insert(2, \"patterson\");\n    avl.insert(3, \"albertson\");\n    expect(avl.apex).toEqual(2);\n    expect(avl.nodes[avl.apex].height).toEqual(1);\n    expect(avl.nodes[avl.apex].balance).toEqual(0);\n    expect(avl.nodes[avl.apex].left).toEqual(3);\n    expect(avl.nodes[avl.apex].right).toEqual(1);\n    expect(avl.nodes[1].height).toEqual(0);\n    expect(avl.nodes[1].balance).toEqual(0);\n    expect(avl.nodes[3].height).toEqual(0);\n    expect(avl.nodes[3].balance).toEqual(0);\n\n    // right heavy involving apex\n    // insert a,p,s\n    // expect p(a)(s)\n    avl = new AvlTreeIndex<string>(\"last\", cmp);\n    avl.insert(3, \"albertson\");\n    avl.insert(2, \"patterson\");\n    avl.insert(1, \"smith\");\n    expect(avl.apex).toEqual(2);\n    expect(avl.nodes[avl.apex].left).toEqual(3);\n    expect(avl.nodes[avl.apex].right).toEqual(1);\n\n    // double right heavy\n    // insert order : s,p,a,g,h\n    // expect final = p(g(a)(h))(s)\n    avl = new AvlTreeIndex<string>(\"last\", cmp);\n    avl.insert(1, \"smith\");\n    avl.insert(2, \"patterson\");\n    avl.insert(3, \"albertson\");\n    avl.insert(4, \"gilbertson\");\n    avl.insert(6, \"harrison\");\n    expect(avl.apex).toEqual(2);\n    expect(avl.nodes[avl.apex].left).toEqual(4);\n    expect(avl.nodes[avl.apex].right).toEqual(1);\n    expect(avl.nodes[4].left).toEqual(3);\n    expect(avl.nodes[4].right).toEqual(6);\n\n    // right-left heavy\n    // insert order : s,p,a,g,d\n    // expect final : p(d(a)(g))(s)\n    avl = new AvlTreeIndex<string>(\"last\", cmp);\n    avl.insert(1, \"smith\");\n    avl.insert(2, \"patterson\");\n    avl.insert(3, \"albertson\");\n    avl.insert(4, \"gilbertson\");\n    avl.insert(6, \"donaldson\");\n    expect(avl.apex).toEqual(2);\n    expect(avl.nodes[avl.apex].left).toEqual(6);\n    expect(avl.nodes[avl.apex].right).toEqual(1);\n    expect(avl.nodes[6].left).toEqual(3);\n    expect(avl.nodes[6].right).toEqual(4);\n\n    // double left heavy\n    avl = new AvlTreeIndex<string>(\"last\", cmp);\n    avl.insert(1, \"patterson\");\n    avl.insert(2, \"gilbertson\");\n    avl.insert(3, \"smith\");\n    avl.insert(4, \"donaldson\");\n    avl.insert(5, \"albertson\");\n    expect(avl.apex).toEqual(1);\n    expect(avl.nodes[1].left).toEqual(4);\n    expect(avl.nodes[1].right).toEqual(3);\n    expect(avl.nodes[4].left).toEqual(5);\n    expect(avl.nodes[4].right).toEqual(2);\n\n    // left right heavy\n    avl = new AvlTreeIndex<string>(\"last\", cmp);\n    avl.insert(1, \"patterson\");\n    avl.insert(2, \"gilbertson\");\n    avl.insert(3, \"smith\");\n    avl.insert(4, \"albertson\");\n    avl.insert(5, \"donaldson\");\n    expect(avl.apex).toEqual(1);\n    expect(avl.nodes[1].left).toEqual(5);\n    expect(avl.nodes[1].right).toEqual(3);\n    expect(avl.nodes[5].left).toEqual(4);\n    expect(avl.nodes[5].right).toEqual(2);\n\n  });\n\n  it(\"remove leafs, causing rotation to rebalance\", () => {\n    let avl = new AvlTreeIndex<string>(\"last\", cmp);\n\n    // double left heavy involving remove\n    // interim tree p (g (d)(h)) (s ()(t))\n    // remove t (removing right leaf)\n    // final expect g (d (a)(f)) (p (h)(s)))\n    avl = new AvlTreeIndex<string>(\"last\", cmp);\n    avl.insert(1, \"patterson\");\n    avl.insert(2, \"gilbertson\");\n    avl.insert(3, \"smith\");\n    avl.insert(4, \"donaldson\");\n    avl.insert(5, \"harrison\");\n    avl.insert(6, \"thompson\"); // keep balanced during next 2 inserts\n    avl.insert(7, \"albertson\");\n    avl.insert(8, \"fiset\");\n    expect(avl.apex).toEqual(1);\n    expect(avl.nodes[1].left).toEqual(2);\n    expect(avl.nodes[1].right).toEqual(3);\n    expect(avl.nodes[2].left).toEqual(4);\n    expect(avl.nodes[2].right).toEqual(5);\n    avl.remove(6); // make tree double left heavy\n    expect(avl.apex).toEqual(2);\n    expect(avl.nodes[2].left).toEqual(4);\n    expect(avl.nodes[2].right).toEqual(1);\n    expect(avl.nodes[1].left).toEqual(5);\n    expect(avl.nodes[1].right).toEqual(3);\n    expect(avl.nodes[4].left).toEqual(7);\n    expect(avl.nodes[4].right).toEqual(8);\n\n    // double right heavy involving remove\n    // interim tree g (d (a)()) (p (l) (t (s)(w)))\n    // remove a (remove left leaf)\n    // final tree p (g (d)(l)) (t (s)(w))\n    avl = new AvlTreeIndex<string>(\"last\", cmp);\n    avl.insert(1, \"gilbertson\");\n    avl.insert(2, \"donaldson\");\n    avl.insert(3, \"patterson\");\n    avl.insert(4, \"albertson\"); // later leaf to remove\n    avl.insert(5, \"lapierre\");\n    avl.insert(6, \"thompson\");\n    avl.insert(7, \"smith\");\n    avl.insert(8, \"williams\");\n    expect(avl.apex).toEqual(1);\n    expect(avl.nodes[1].left).toEqual(2);\n    expect(avl.nodes[1].right).toEqual(3);\n    expect(avl.nodes[3].left).toEqual(5);\n    expect(avl.nodes[3].right).toEqual(6);\n    avl.remove(4); // make tree double right heavy\n    expect(avl.apex).toEqual(3);\n    expect(avl.nodes[3].left).toEqual(1);\n    expect(avl.nodes[3].right).toEqual(6);\n    expect(avl.nodes[1].left).toEqual(2);\n    expect(avl.nodes[1].right).toEqual(5);\n    expect(avl.nodes[6].left).toEqual(7);\n    expect(avl.nodes[6].right).toEqual(8);\n  });\n\n  // verify that we use in-order predecessor\n  // predecessor may have 0-1 children\n  // this test will use predecessor with no children\n  it(\"remove rotation where node has two children and tree is left heavy\", () => {\n    // interim tree p (g (d)(h)) (s)  root balance = -1\n    let avl = new AvlTreeIndex<string>(\"last\", cmp);\n    avl.insert(1, \"patterson\");\n    avl.insert(2, \"gilbertson\");\n    avl.insert(3, \"smith\");\n    avl.insert(4, \"donaldson\");\n    avl.insert(5, \"harrison\");\n    expect(avl.apex).toEqual(1);\n    expect(avl.nodes[1].left).toEqual(2);\n    expect(avl.nodes[1].right).toEqual(3);\n    expect(avl.nodes[2].left).toEqual(4);\n    expect(avl.nodes[2].right).toEqual(5);\n    expect(avl.nodes[3].left).toEqual(null);\n    expect(avl.nodes[3].right).toEqual(null);\n\n    // remove root which has two children and that root is left heavy...\n    // it will use in-order predecessor (h) to reduce chance of rotation\n    // new tree should be h (g (d)()) (s)\n    avl.remove(1);\n    expect(avl.apex).toEqual(5);\n    expect(avl.nodes[5].left).toEqual(2);\n    expect(avl.nodes[5].right).toEqual(3);\n    expect(avl.nodes[2].left).toEqual(4);\n    expect(avl.nodes[2].right).toEqual(null);\n    expect(avl.nodes[3].left).toEqual(null);\n    expect(avl.nodes[3].right).toEqual(null);\n  });\n\n  // verify that we use in-order successor\n  // succecessor may have 0-1 children\n  // this test will use successor with no children\n  it(\"remove rotation where node has two children and tree is right heavy\", () => {\n    // interim tree g (d) (p (h)(t))  root balance = +1\n    let avl = new AvlTreeIndex<string>(\"last\", cmp);\n    avl.insert(1, \"gilbertson\");\n    avl.insert(2, \"donaldson\");\n    avl.insert(3, \"patterson\");\n    avl.insert(4, \"harrison\");\n    avl.insert(5, \"thompson\");\n    expect(avl.apex).toEqual(1);\n    expect(avl.nodes[1].left).toEqual(2);\n    expect(avl.nodes[1].right).toEqual(3);\n    expect(avl.nodes[2].left).toEqual(null);\n    expect(avl.nodes[2].right).toEqual(null);\n    expect(avl.nodes[3].left).toEqual(4);\n    expect(avl.nodes[3].right).toEqual(5);\n    // remove root which has two children and that root is right heavy...\n    // it will use in-order predecessor (h) to reduce chance of rotation\n    // new tree should be h (g (d)()) (s)\n    avl.remove(1);\n    expect(avl.apex).toEqual(4);\n    expect(avl.nodes[4].left).toEqual(2);\n    expect(avl.nodes[4].right).toEqual(3);\n    expect(avl.nodes[2].left).toEqual(null);\n    expect(avl.nodes[2].right).toEqual(null);\n    expect(avl.nodes[3].left).toEqual(null);\n    expect(avl.nodes[3].right).toEqual(5);\n  });\n\n  it(\"avl $eq rangeRequest works\", () => {\n    let idbuf: number[] = [];\n    let valbuf: string[] = [];\n    let rnd: string;\n\n    let avl = new AvlTreeIndex<string>(\"asdf\", cmp);\n\n    // insert random values into avl and retain values using numeric id greater than 0\n    for (let idx = 1; idx <= count; idx++) {\n      idbuf.push(idx);\n      rnd = genRandomVal();\n      valbuf.push(rnd);\n      avl.insert(idx, rnd);\n    }\n\n    for (let idx = 1; idx <= count; idx++) {\n      idbuf.push(count + idx);\n      avl.insert(count + idx, valbuf[idx - 1]);\n    }\n\n    for (let idx = 1; idx <= count; idx++) {\n      let matches = avl.rangeRequest({\n        op: \"$eq\",\n        val: valbuf[idx - 1]\n      });\n\n      expect(matches.length).toEqual(2);\n    }\n  });\n\n  it(\"avl $lt rangeRequest works\", () => {\n    let avl = new AvlTreeIndex<string>(\"test\", cmp);\n\n    avl.insert(1, \"dsa\");   // should be in results\n    avl.insert(2, \"xja\");\n    avl.insert(3, \"asd\");   // should be in results\n    avl.insert(4, \"gfd\");   // not in results since op is $lt\n    avl.insert(5, \"ert\");   // should be in results\n    avl.insert(6, \"mnb\");\n    avl.insert(7, \"vbn\");\n    avl.insert(8, \"rty\");\n    avl.insert(9, \"zxc\");\n\n    let result: number[] = avl.rangeRequest({ op: \"$lt\", val: \"gfd\" });\n\n    expect(result.length).toEqual(3);\n    expect(result[0]).toEqual(3);\n    expect(result[1]).toEqual(1);\n    expect(result[2]).toEqual(5);\n  });\n\n  it(\"avl $lte rangeRequest works\", () => {\n    let avl = new AvlTreeIndex<string>(\"test\", cmp);\n\n    avl.insert(1, \"dsa\");   // should be in results\n    avl.insert(2, \"xja\");\n    avl.insert(3, \"asd\");   // should be in results\n    avl.insert(4, \"gfd\");   // should be in results\n    avl.insert(5, \"ert\");   // should be in results\n    avl.insert(6, \"mnb\");\n    avl.insert(7, \"vbn\");\n    avl.insert(8, \"rty\");\n    avl.insert(9, \"zxc\");\n\n    let result: number[] = avl.rangeRequest({ op: \"$lte\", val: \"gfd\" });\n\n    expect(result.length).toEqual(4);\n    expect(result[0]).toEqual(3);\n    expect(result[1]).toEqual(1);\n    expect(result[2]).toEqual(5);\n    expect(result[3]).toEqual(4);\n  });\n\n  it(\"avl $gt rangeRequest works\", () => {\n    let avl = new AvlTreeIndex<string>(\"test\", cmp);\n\n    avl.insert(1, \"dsa\");\n    avl.insert(2, \"xja\");   // should be in results\n    avl.insert(3, \"asd\");\n    avl.insert(4, \"gfd\");\n    avl.insert(5, \"ert\");\n    avl.insert(6, \"mnb\");   // should -not- be in results since op is $gt\n    avl.insert(7, \"vbn\");   // should be in results\n    avl.insert(8, \"rty\");   // should be in results\n    avl.insert(9, \"zxc\");   // should be in results\n\n    let result: number[] = avl.rangeRequest({ op: \"$gt\", val: \"mnb\" });\n\n    expect(result.length).toEqual(4);\n    expect(result[0]).toEqual(8);\n    expect(result[1]).toEqual(7);\n    expect(result[2]).toEqual(2);\n    expect(result[3]).toEqual(9);\n  });\n\n  it(\"avl $gte rangeRequest works\", () => {\n    let avl = new AvlTreeIndex<string>(\"test\", cmp);\n\n    avl.insert(1, \"dsa\");\n    avl.insert(2, \"xja\");   // should be in results\n    avl.insert(3, \"asd\");\n    avl.insert(4, \"gfd\");\n    avl.insert(5, \"ert\");\n    avl.insert(6, \"mnb\");   // should be in results\n    avl.insert(7, \"vbn\");   // should be in results\n    avl.insert(8, \"rty\");   // should be in results\n    avl.insert(9, \"zxc\");   // should be in results\n\n    let result: number[] = avl.rangeRequest({ op: \"$gte\", val: \"mnb\" });\n\n    expect(result.length).toEqual(5);\n    expect(result[0]).toEqual(6);\n    expect(result[1]).toEqual(8);\n    expect(result[2]).toEqual(7);\n    expect(result[3]).toEqual(2);\n    expect(result[4]).toEqual(9);\n  });\n\n  it(\"avl $between rangeRequest works\", () => {\n    let avl = new AvlTreeIndex<string>(\"test\", cmp);\n\n    avl.insert(1, \"dsa\");\n    avl.insert(2, \"xja\");\n    avl.insert(3, \"asd\");\n    avl.insert(4, \"gfd\");   // should be in results\n    avl.insert(5, \"ert\");\n    avl.insert(6, \"mnb\");   // should be in results\n    avl.insert(7, \"vbn\");   // should be in results\n    avl.insert(8, \"rty\");   // should be in results\n    avl.insert(9, \"zxc\");\n\n    let result: number[] = avl.rangeRequest({ op: \"$between\", val: \"gfd\", high: \"vbn\" });\n\n    expect(result.length).toEqual(4);\n    expect(result[0]).toEqual(4);\n    expect(result[1]).toEqual(6);\n    expect(result[2]).toEqual(8);\n    expect(result[3]).toEqual(7);\n  });\n\n  it(\"collection find ops on avl index work\", () => {\n    interface TestUserType {\n      name: string;\n      age: number;\n      location: string;\n    }\n\n    const db = new Loki(\"idxtest\");\n    const items = db.addCollection<TestUserType>(\"users\", {\n      rangedIndexes: {\n        name: { indexTypeName: \"avl\", comparatorName: \"js\" }\n      }\n    });\n\n    items.insert([\n      { name: \"patterson\", age: 10, location: \"a\" },\n      { name: \"gilbertson\", age: 20, location: \"b\" },\n      { name: \"smith\", age: 30, location: \"c\" },\n      { name: \"donaldson\", age: 40, location: \"d\" },\n      { name: \"harrison\", age: 50, location: \"e\" },\n      { name: \"thompson\", age: 60, location: \"f\" },\n      { name: \"albertson\", age: 70, location: \"g\" },\n      { name: \"fiset\", age: 80, location: \"h\" }\n    ]);\n\n    // $eq\n    let results: TestUserType[] = items.find({ name: \"donaldson\" });\n    expect(results.length).toEqual(1);\n    expect(results[0].name).toEqual(\"donaldson\");\n    expect(results[0].age).toEqual(40);\n    expect(results[0].location).toEqual(\"d\");\n\n    // $lt\n    results = items.find({ name: { $lt: \"giraffe\" } });\n    expect(results.length).toEqual(4);\n    expect(results[0].name).toEqual(\"albertson\");\n    expect(results[1].name).toEqual(\"donaldson\");\n    expect(results[2].name).toEqual(\"fiset\");\n    expect(results[3].name).toEqual(\"gilbertson\");\n\n    // $lte\n    results = items.find({ name: { $lte: \"fiset\" } });\n    expect(results.length).toEqual(3);\n    expect(results[0].name).toEqual(\"albertson\");\n    expect(results[1].name).toEqual(\"donaldson\");\n    expect(results[2].name).toEqual(\"fiset\");\n\n    // $gt\n    results = items.find({ name: { $gt: \"giraffe\" } });\n    expect(results.length).toEqual(4);\n    expect(results[0].name).toEqual(\"harrison\");\n    expect(results[1].name).toEqual(\"patterson\");\n    expect(results[2].name).toEqual(\"smith\");\n    expect(results[3].name).toEqual(\"thompson\");\n\n    // $gte\n    results = items.find({ name: { $gte: \"patterson\" } });\n    expect(results.length).toEqual(3);\n    expect(results[0].name).toEqual(\"patterson\");\n    expect(results[1].name).toEqual(\"smith\");\n    expect(results[2].name).toEqual(\"thompson\");\n\n    // $between\n    results = items.find({ name: { $between: [\"faraday\", \"samuel\"] } });\n    expect(results.length).toEqual(4);\n    expect(results[0].name).toEqual(\"fiset\");\n    expect(results[1].name).toEqual(\"gilbertson\");\n    expect(results[2].name).toEqual(\"harrison\");\n    expect(results[3].name).toEqual(\"patterson\");\n\n  });\n\n  it(\"update works on collection with avl index\", () => {\n    interface TestUserType {\n      name: string;\n      age: number;\n      location: string;\n    }\n\n    const db = new Loki(\"idxtest\");\n    const items = db.addCollection<TestUserType>(\"users\", {\n      rangedIndexes: {\n        name: { indexTypeName: \"avl\", comparatorName: \"js\" }\n      }\n    });\n\n    items.insert([\n      { name: \"patterson\", age: 10, location: \"a\" },\n      { name: \"gilbertson\", age: 20, location: \"b\" },\n      { name: \"smith\", age: 30, location: \"c\" },\n      { name: \"donaldson\", age: 40, location: \"d\" },\n      { name: \"harrison\", age: 50, location: \"e\" },\n      { name: \"thompson\", age: 60, location: \"f\" },\n      { name: \"albertson\", age: 70, location: \"g\" },\n    ]);\n\n    items.chain().update((o: Doc<TestUserType>) => { o.name = reverseString(o.name); return o; });\n\n    let result = items.find({ name: { $lte: \"nosk\" } });\n    expect(result.length).toEqual(3);\n    expect(result[0].name).toEqual(\"htims\");\n    expect(result[1].name).toEqual(\"nosdlanod\");\n    expect(result[2].name).toEqual(\"nosirrah\");\n\n    // using weak filter to return all docs ordered by our index\n    result = items.find({ name: { $gte: \"a\" } });\n    expect(result.length).toEqual(7);\n    expect(result[0].name).toEqual(\"htims\");\n    expect(result[1].name).toEqual(\"nosdlanod\");\n    expect(result[2].name).toEqual(\"nosirrah\");\n    expect(result[3].name).toEqual(\"nospmoht\");\n    expect(result[4].name).toEqual(\"nosrettap\");\n    expect(result[5].name).toEqual(\"nostrebla\");\n    expect(result[6].name).toEqual(\"nostreblig\");\n  });\n\n  it(\"remove works on collection with avl index\", () => {\n    interface TestUserType {\n      name: string;\n      age: number;\n      location: string;\n    }\n\n    const db = new Loki(\"idxtest\");\n    const items = db.addCollection<TestUserType>(\"users\", {\n      rangedIndexes: {\n        name: { indexTypeName: \"avl\", comparatorName: \"js\" }\n      }\n    });\n\n    items.insert([\n      { name: \"patterson\", age: 10, location: \"a\" },\n      { name: \"gilbertson\", age: 20, location: \"b\" },\n      { name: \"smith\", age: 30, location: \"c\" },\n      { name: \"donaldson\", age: 40, location: \"d\" },\n      { name: \"harrison\", age: 50, location: \"e\" },\n      { name: \"thompson\", age: 60, location: \"f\" },\n      { name: \"albertson\", age: 70, location: \"g\" },\n    ]);\n\n    items.chain().find({ name: { $lte: \"goldman\" } }).remove();\n\n    let result = items.find({ name: { $lte: \"samuels\" } });\n    expect(result.length).toEqual(2);\n    expect(result[0].name).toEqual(\"harrison\");\n    expect(result[1].name).toEqual(\"patterson\");\n  });\n\n  it(\"simplesort works on collection with avl index\", () => {\n    interface TestUserType {\n      name: string;\n      age: number;\n      location: string;\n    }\n\n    const db = new Loki(\"idxtest\");\n    const items = db.addCollection<TestUserType>(\"users\", {\n      rangedIndexes: {\n        name: { indexTypeName: \"avl\", comparatorName: \"js\" }\n      }\n    });\n\n    items.insert([\n      { name: \"patterson\", age: 10, location: \"a\" },\n      { name: \"gilbertson\", age: 20, location: \"b\" },\n      { name: \"smith\", age: 30, location: \"c\" },\n      { name: \"donaldson\", age: 40, location: \"d\" },\n      { name: \"harrison\", age: 50, location: \"e\" },\n      { name: \"thompson\", age: 60, location: \"f\" },\n      { name: \"albertson\", age: 70, location: \"g\" },\n    ]);\n\n    let result: TestUserType[] = items.chain().simplesort(\"name\").data();\n\n    expect(result.length).toEqual(7);\n    expect(result[0].name).toEqual(\"albertson\");\n    expect(result[1].name).toEqual(\"donaldson\");\n    expect(result[2].name).toEqual(\"gilbertson\");\n    expect(result[3].name).toEqual(\"harrison\");\n    expect(result[4].name).toEqual(\"patterson\");\n    expect(result[5].name).toEqual(\"smith\");\n    expect(result[6].name).toEqual(\"thompson\");\n  });\n\n  it(\"comparator and ranged index maps can be injected into\", () => {\n\n    let cmp = (a: any, b: any) => {\n      if (a > b) return 1;\n      if (a === b) return 0;\n      return -1;\n    };\n\n    // not really a functional ranged index, should have constructor accepting comparator\n\n    class customRangedIndex<T> implements IRangedIndex<T> {\n      public name: string;\n      public comparator: ILokiComparer<T>;\n\n      constructor(name: string, comparator: ILokiComparer<T>) {\n        this.name = name;\n        this.comparator = comparator;\n      }\n\n      insert(id: number, val: T) {\n        if (!id || !val) throw new Error(\"\");\n        return;\n      }\n      update(id: number, val: T) {\n        if (!id || val === null) throw new Error(\"\");\n        return;\n      }\n      remove(id: number) {\n        if (!id) throw new Error(\"\");\n        return;\n      }\n      restore(tree: any) {\n        if (!tree) throw new Error(\"\");\n        return;\n      }\n      backup() {\n        return this;\n      }\n      rangeRequest(range?: IRangedIndexRequest<T>) {\n        if (range === null) {\n          // return everything\n          return <number[]> [];\n        }\n        return <number[]> [];\n      }\n      validateIndex() {\n        return true;\n      }\n    }\n\n    let myCustomIndexFactory = (name: string, cmp: ILokiComparer<any>) => { return new customRangedIndex<any>(name, cmp); };\n\n    let db = new Loki(\"test.db\", {\n      comparatorMap: {\n        \"FastNumeric\": cmp\n      },\n      rangedIndexFactoryMap: {\n        \"MyCustomRangedIndex\": myCustomIndexFactory\n      }\n    });\n\n    expect(db instanceof Loki).toEqual(true);\n\n    // verify they are registered into (global for now) comparator and rangedindex factory maps\n    expect(ComparatorMap.hasOwnProperty(\"FastNumeric\")).toEqual(true);\n    expect(typeof ComparatorMap[\"FastNumeric\"]).toEqual(\"function\");\n    expect(RangedIndexFactoryMap.hasOwnProperty(\"MyCustomRangedIndex\")).toEqual(true);\n    expect(typeof RangedIndexFactoryMap[\"MyCustomRangedIndex\"]).toEqual(\"function\");\n\n  });\n\n  it(\"nested property with avl index work\", () => {\n    interface TestUserType {\n      user: {\n        name: string;\n        age: number;\n        location: string;\n      };\n    }\n\n    const db = new Loki(\"idxtest\");\n    const items = db.addCollection<TestUserType, { \"user.name\": string }>(\"users\", {\n      rangedIndexes: {\n        \"user.name\": { indexTypeName: \"avl\", comparatorName: \"js\" }\n      },\n      nestedProperties: [\"user.name\"]\n    });\n\n    items.insert([\n      { user: { name: \"patterson\", age: 10, location: \"a\" } },\n      { user: { name: \"gilbertson\", age: 20, location: \"b\" } },\n      { user: { name: \"smith\", age: 30, location: \"c\" } },\n      { user: { name: \"donaldson\", age: 40, location: \"d\" } },\n      { user: { name: \"harrison\", age: 50, location: \"e\" } },\n      { user: { name: \"thompson\", age: 60, location: \"f\" } },\n      { user: { name: \"albertson\", age: 70, location: \"g\" } },\n      { user: { name: \"fiset\", age: 80, location: \"h\" } }\n    ]);\n\n    // $eq\n    let results: TestUserType[] = items.find({ \"user.name\": \"donaldson\" });\n    expect(results.length).toEqual(1);\n    expect(results[0].user.name).toEqual(\"donaldson\");\n    expect(results[0].user.age).toEqual(40);\n    expect(results[0].user.location).toEqual(\"d\");\n\n    // $lt\n    results = items.find({ \"user.name\": { $lt: \"giraffe\" } });\n    expect(results.length).toEqual(4);\n    expect(results[0].user.name).toEqual(\"albertson\");\n    expect(results[1].user.name).toEqual(\"donaldson\");\n    expect(results[2].user.name).toEqual(\"fiset\");\n    expect(results[3].user.name).toEqual(\"gilbertson\");\n\n    // $lte\n    results = items.find({ \"user.name\": { $lte: \"fiset\" } });\n    expect(results.length).toEqual(3);\n    expect(results[0].user.name).toEqual(\"albertson\");\n    expect(results[1].user.name).toEqual(\"donaldson\");\n    expect(results[2].user.name).toEqual(\"fiset\");\n\n    // $gt\n    results = items.find({ \"user.name\": { $gt: \"giraffe\" } });\n    expect(results.length).toEqual(4);\n    expect(results[0].user.name).toEqual(\"harrison\");\n    expect(results[1].user.name).toEqual(\"patterson\");\n    expect(results[2].user.name).toEqual(\"smith\");\n    expect(results[3].user.name).toEqual(\"thompson\");\n\n    // $gte\n    results = items.find({ \"user.name\": { $gte: \"patterson\" } });\n    expect(results.length).toEqual(3);\n    expect(results[0].user.name).toEqual(\"patterson\");\n    expect(results[1].user.name).toEqual(\"smith\");\n    expect(results[2].user.name).toEqual(\"thompson\");\n\n    // $between\n    results = items.find({ \"user.name\": { $between: [\"faraday\", \"samuel\"] } });\n    expect(results.length).toEqual(4);\n    expect(results[0].user.name).toEqual(\"fiset\");\n    expect(results[1].user.name).toEqual(\"gilbertson\");\n    expect(results[2].user.name).toEqual(\"harrison\");\n    expect(results[3].user.name).toEqual(\"patterson\");\n\n    // simplesort\n    results = items.chain().simplesort(\"user.name\").data();\n    expect(results.length).toEqual(8);\n    expect(results[0].user.name).toEqual(\"albertson\");\n    expect(results[1].user.name).toEqual(\"donaldson\");\n    expect(results[2].user.name).toEqual(\"fiset\");\n    expect(results[3].user.name).toEqual(\"gilbertson\");\n    expect(results[4].user.name).toEqual(\"harrison\");\n    expect(results[5].user.name).toEqual(\"patterson\");\n    expect(results[6].user.name).toEqual(\"smith\");\n    expect(results[7].user.name).toEqual(\"thompson\");\n\n    // remove\n    items.chain().find({ \"user.name\": { $lte: \"goldman\" } }).remove();\n    results = items.find({ \"user.name\": { $lte: \"samuels\" } });\n    expect(results.length).toEqual(2);\n    expect(results[0].user.name).toEqual(\"harrison\");\n    expect(results[1].user.name).toEqual(\"patterson\");\n\n    // update\n    items.chain().update((o) => { o.user.name = reverseString(o.user.name); return o; });\n    results = items.find({ \"user.name\": { $gte: \"nork\" } });\n    expect(results.length).toEqual(3);\n    expect(results[0].user.name).toEqual(\"nosirrah\");\n    expect(results[1].user.name).toEqual(\"nospmoht\");\n    expect(results[2].user.name).toEqual(\"nosrettap\");\n  });\n\n  it(\"avl index raises exceptions where appropriate\", () => {\n    let cmp: ILokiComparer<any> = (a: any, b: any) => { return (a > b) ? -1 : 0; };\n    let avl = new AvlTreeIndex(\"test\", cmp);\n\n    // if inserting val <= 0, expect an error to be thrown\n    expect(() => avl.insert(0, \"test\")).toThrow(new Error(\"avl index ids are required to be numbers greater than zero\"));\n\n    // if comparator returns value other than -1, 0, or 1, expect an error to be thrown\n    let node1: TreeNode<any> = {\n      id: 0, value: 0, parent: null, balance: 0, height: 0, left: null, right: null, siblings: []\n    };\n    let node2: TreeNode<any> = {\n      id: 0, value: 0, parent: null, balance: 0, height: 0, left: null, right: null, siblings: []\n    };\n\n    let icmp = (a: any, b: any) => { return (a > b) ? -2 : 2; };\n    cmp = icmp as any as ILokiComparer<any>;\n\n    avl.comparator = cmp;\n\n    expect(() => avl.insertNode(node1, node2)).toThrow(new Error(\"Invalid comparator result\"));\n\n    // attempting to remove a node from an avl tree which has no index should throw error\n    avl.apex = null;\n    expect(() => avl.remove(1)).toThrow(new Error(\"remove() : attempting remove when tree has no apex\"));\n  });\n});\n"
  },
  {
    "path": "packages/loki/spec/generic/changesApi.spec.ts",
    "content": "/* global describe, it, expect */\nimport { Loki } from \"../../src/loki\";\n\ndescribe(\"changesApi\", () => {\n\n  interface User {\n    name: string;\n  }\n\n  it(\"does what it says on the tin\", () => {\n    const db = new Loki();\n    const options = {\n      asyncListeners: false,\n      disableChangesApi: false\n    };\n    const users = db.addCollection<User>(\"users\", options);\n    const test = db.addCollection<User>(\"test\", options);\n    const test2 = db.addCollection<User>(\"test2\", options);\n\n    const u = users.insert({\n      name: \"joe\"\n    });\n    u.name = \"jack\";\n    users.update(u);\n    test.insert({\n      name: \"test\"\n    });\n    test2.insert({\n      name: \"test2\"\n    });\n\n    const userChanges = db.generateChangesNotification([\"users\"]);\n\n    expect(userChanges.length).toEqual(2);\n    expect(db.serializeChanges([\"users\"])).toEqual(JSON.stringify(userChanges));\n\n    const someChanges = db.generateChangesNotification([\"users\", \"test2\"]);\n\n    expect(someChanges.length).toEqual(3);\n    const allChanges = db.generateChangesNotification();\n\n    expect(allChanges.length).toEqual(4);\n    users.setChangesApi(true);\n    expect(users[\"_disableChangesApi\"]).toEqual(true);\n\n    u.name = \"john\";\n    users.update(u);\n    const newChanges = db.generateChangesNotification([\"users\"]);\n\n    expect(newChanges.length).toEqual(2);\n    db.clearChanges();\n\n    expect(users.getChanges().length).toEqual(0);\n\n    u.name = \"jim\";\n    users.update(u);\n    users.flushChanges();\n\n    expect(users.getChanges().length).toEqual(0);\n  });\n\n  it(\"works with delta mode\", () => {\n    const db = new Loki();\n    const options = {\n      asyncListeners: false,\n      disableChangesApi: false,\n      disableDeltaChangesApi: false\n    };\n\n    interface User {\n      name: string;\n      owner: string;\n      maker: {\n        name: string,\n        count: number;\n      };\n    }\n\n    const items = db.addCollection<User>(\"items\", options);\n\n    // Add some documents to the collection\n    items.insert({name: \"mjolnir\", owner: \"thor\", maker: {name: \"dwarves\", count: 1}});\n    items.insert({name: \"gungnir\", owner: \"odin\", maker: {name: \"elves\", count: 1}});\n    items.insert({name: \"tyrfing\", owner: \"Svafrlami\", maker: {name: \"dwarves\", count: 1}});\n    items.insert({name: \"draupnir\", owner: \"odin\", maker: {name: \"elves\", count: 1}});\n\n    // Find and update an existing document\n    const tyrfing = items.findOne({\"name\": \"tyrfing\"});\n    tyrfing.owner = \"arngrim\";\n    items.update(tyrfing);\n    tyrfing.maker.count = 4;\n    items.update(tyrfing);\n\n    let changes_serialized = db.serializeChanges([\"items\"]);\n    let changes = JSON.parse(changes_serialized);\n\n    expect(changes.length).toEqual(6);\n\n    const firstUpdate = changes[4];\n    expect(firstUpdate.operation).toEqual(\"U\");\n    expect(firstUpdate.obj.owner).toEqual(\"arngrim\");\n    expect(firstUpdate.obj.name).toBeUndefined();\n\n    const secondUpdate = changes[5];\n    expect(secondUpdate.operation).toEqual(\"U\");\n    expect(secondUpdate.obj.owner).toBeUndefined();\n    expect(secondUpdate.obj.maker).toEqual({count: 4});\n  });\n\n  it(\"batch operations work with delta mode\", () => {\n\n    interface User {\n      name: string;\n      maker: string;\n      owner: string;\n      count: number;\n    }\n\n    const db = new Loki();\n    const options = {\n      asyncListeners: false,\n      disableChangesApi: false,\n      disableDeltaChangesApi: false\n    };\n    const items = db.addCollection<User>(\"items\", options);\n\n    // Add some documents to the collection\n    items.insert([\n      {name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\", count: 0},\n      {name: \"gungnir\", owner: \"odin\", maker: \"elves\", count: 0},\n      {name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\", count: 0},\n      {name: \"draupnir\", owner: \"odin\", maker: \"elves\", count: 0}\n    ]);\n\n    items.chain().update((o) => {\n      o.count++;\n      return o;\n    });\n\n    const changes = JSON.parse(db.serializeChanges([\"items\"]));\n    expect(changes.length).toEqual(8);\n\n    expect(changes[0].name).toEqual(\"items\");\n    expect(changes[0].operation).toEqual(\"I\");\n    expect(changes[1].name).toEqual(\"items\");\n    expect(changes[1].operation).toEqual(\"I\");\n    expect(changes[2].name).toEqual(\"items\");\n    expect(changes[2].operation).toEqual(\"I\");\n    expect(changes[3].name).toEqual(\"items\");\n    expect(changes[3].operation).toEqual(\"I\");\n\n    expect(changes[4].name).toEqual(\"items\");\n    expect(changes[4].operation).toEqual(\"U\");\n    expect(changes[4].obj.count).toEqual(1);\n    expect(changes[5].name).toEqual(\"items\");\n    expect(changes[5].operation).toEqual(\"U\");\n    expect(changes[5].obj.count).toEqual(1);\n    expect(changes[6].name).toEqual(\"items\");\n    expect(changes[6].operation).toEqual(\"U\");\n    expect(changes[6].obj.count).toEqual(1);\n    expect(changes[7].name).toEqual(\"items\");\n    expect(changes[7].operation).toEqual(\"U\");\n    expect(changes[7].obj.count).toEqual(1);\n\n    const keys = Object.keys(changes[7].obj);\n    keys.sort();\n    expect(keys[0]).toEqual(\"$loki\");\n    expect(keys[1]).toEqual(\"count\");\n    expect(keys[2]).toEqual(\"meta\");\n  });\n});\n"
  },
  {
    "path": "packages/loki/spec/generic/cloning.spec.ts",
    "content": "/* global describe, beforeEach, it, expect */\nimport { Loki } from \"../../src/loki\";\nimport { Collection } from \"../../src/collection\";\n\ndescribe(\"cloning behavior\", () => {\n  interface User {\n    name: string;\n    owner: string;\n    maker: string;\n  }\n\n  let db: Loki;\n  let items: Collection<User>;\n\n  beforeEach(() => {\n    db = new Loki(\"cloningDisabled\");\n    items = db.addCollection<User>(\"items\");\n    items.insert({name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\"});\n    items.insert({name: \"gungnir\", owner: \"odin\", maker: \"elves\"});\n    items.insert({name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\"});\n    items.insert({name: \"draupnir\", owner: \"odin\", maker: \"elves\"});\n  });\n\n  describe(\"cloning disabled\", () => {\n    it(\"works\", () => {\n      const mj = items.findOne({name: \"mjolnir\"});\n\n      // you are modifying the actual object instance so this is worst case\n      // where you modify that object and dont even call update().\n      // this is not recommended, you should definately call update after modifying an object.\n      mj.maker = \"the dwarves\";\n\n      const mj2 = items.findOne({name: \"mjolnir\"});\n      expect(mj2.maker).toBe(\"the dwarves\");\n    });\n  });\n\n  describe(\"cloning inserts are immutable\", () => {\n    it(\"works\", () => {\n      const cdb = new Loki(\"clonetest\");\n      const citems = cdb.addCollection<User>(\"items\", {clone: true});\n      const oldObject = {name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\"};\n      const insObject = citems.insert(oldObject);\n\n      // cant' have either of these polluting our collection\n      oldObject.name = \"mewmew\";\n      insObject.name = \"mewmew\";\n\n      const result = citems.findOne({\"owner\": \"thor\"});\n      expect(result.name).toBe(\"mjolnir\");\n    });\n  });\n\n  describe(\"cloning Date and Arrays\", () => {\n    it(\"deep\", () => {\n      const cdb = new Loki(\"clonetest\");\n      const citems = cdb.addCollection<{ some: Date, other: (number | string | Date)[] }>(\"items\", {\n        clone: true,\n        cloneMethod: \"deep\",\n        defaultLokiOperatorPackage : \"loki\"\n      });\n      const oldObject = {\n        some: new Date(\"July 21, 1983 01:14:00\"),\n        other: [1, \"2\", 3, \"4\", new Date(\"July 21, 1983 01:15:00\"), new Date(\"July 21, 1983 01:16:00\")]\n      };\n      const insObject = citems.insert(oldObject);\n\n      oldObject.some = new Date(\"July 21, 1982 01:15:00\");\n      oldObject.other = [\"2\", 1, \"3\", new Date(\"July 22, 1983 01:15:00\"), \"4\"];\n      insObject.some = new Date(\"July 21, 1981 01:15:00\");\n      insObject.other = [\"3\", 4, \"7\", new Date(\"July 20, 1983 01:15:00\"), 5];\n\n      const result = citems.findOne({\"some\": {$eq: new Date(\"July 21, 1983 01:14:00\")}});\n      expect(result.other).not.toEqual(oldObject.other);\n      expect(result.other).not.toEqual(insObject.other);\n    });\n\n    it(\"shallow-recursive\", () => {\n      const cdb = new Loki(\"clonetest\");\n      const citems = cdb.addCollection<{ some: Date, other: (number | string | Date)[] }>(\"items\", {\n        clone: true,\n        cloneMethod: \"shallow-recurse\",\n        defaultLokiOperatorPackage : \"loki\"\n      });\n      const oldObject = {\n        some: new Date(\"July 21, 1983 01:14:00\"),\n        other: [1, \"2\", 3, \"4\", new Date(\"July 21, 1983 01:15:00\"), new Date(\"July 21, 1983 01:16:00\")]\n      };\n      const insObject = citems.insert(oldObject);\n\n      oldObject.some = new Date(\"July 21, 1982 01:15:00\");\n      oldObject.other = [\"2\", 1, \"3\", new Date(\"July 22, 1983 01:15:00\"), \"4\"];\n      insObject.some = new Date(\"July 21, 1981 01:15:00\");\n      insObject.other = [\"3\", 4, \"7\", new Date(\"July 20, 1983 01:15:00\"), 5];\n\n      const result = citems.findOne({\"some\": {$eq: new Date(\"July 21, 1983 01:14:00\")}});\n      expect(result.other).not.toEqual(oldObject.other);\n      expect(result.other).not.toEqual(insObject.other);\n    });\n\n    it(\"parse-stringify\", () => {\n      const cdb = new Loki(\"clonetest\");\n      const citems = cdb.addCollection<{ some: Date | string, other: (number | string | Date)[] }>(\"items\", {\n        clone: true,\n        cloneMethod: \"parse-stringify\",\n        defaultLokiOperatorPackage : \"loki\"\n      });\n      const oldObject = {\n        some: new Date(\"July 21, 1983 01:14:00\"),\n        other: [1, \"2\", 3, \"4\", new Date(\"July 21, 1983 01:15:00\"), new Date(\"July 21, 1983 01:16:00\")]\n      };\n      const insObject = citems.insert(oldObject);\n\n      oldObject.some = new Date(\"July 21, 1982 01:15:00\");\n      oldObject.other = [\"2\", 1, \"3\", new Date(\"July 22, 1983 01:15:00\"), \"4\"];\n      insObject.some = new Date(\"July 21, 1981 01:15:00\");\n      insObject.other = [\"3\", 4, \"7\", new Date(\"July 20, 1983 01:15:00\"), 5];\n\n      const result = citems.findOne({ \"some\": (new Date(\"July 21, 1983 01:14:00\")).toISOString() });\n      expect(result.other).not.toEqual(oldObject.other);\n      expect(result.other).not.toEqual(insObject.other);\n    });\n  });\n\n  describe(\"cloning insert events emit cloned object\", function () {\n    it(\"works\", () => {\n      const cdb = new Loki(\"clonetest\");\n      const citems = cdb.addCollection<User & { count: number }>(\"items\", {clone: true});\n\n      citems.on(\"insert\", (obj: User) => {\n        /// attempt to tamper with name\n        obj.name = \"zzz\";\n      });\n\n      citems.insert({name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\", count: 0});\n      citems.insert({name: \"gungnir\", owner: \"odin\", maker: \"elves\", count: 0});\n      citems.insert({name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\", count: 0});\n      citems.insert({name: \"draupnir\", owner: \"odin\", maker: \"elves\", count: 0});\n\n      const results = citems.find();\n      expect(results.length).toEqual(4);\n\n      results.forEach((obj) => {\n        expect(obj.name === \"zzz\").toEqual(false);\n      });\n    });\n  });\n\n  describe(\"cloning updates are immutable\", () => {\n    it(\"works\", () => {\n      const cdb = new Loki(\"clonetest\");\n      const citems = cdb.addCollection<User>(\"items\", {clone: true});\n      const oldObject = {name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\"};\n      citems.insert(oldObject);\n      const rObject = citems.findOne({\"owner\": \"thor\"});\n\n      // after all that, just do this to ensure internal ref is different\n      citems.update(rObject);\n\n      // can't have this polluting our collection\n      rObject.name = \"mewmew\";\n\n      const result = citems.findOne({\"owner\": \"thor\"});\n\n      expect(result.name).toBe(\"mjolnir\");\n    });\n  });\n\n  describe(\"cloning updates events emit cloned object\", function () {\n    it(\"works\", () => {\n      const cdb = new Loki(\"clonetest\");\n      const citems = cdb.addCollection<User & { count: number }>(\"items\", {clone: true});\n\n      citems.insert({name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\", count: 0});\n      citems.insert({name: \"gungnir\", owner: \"odin\", maker: \"elves\", count: 0});\n      citems.insert({name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\", count: 0});\n      citems.insert({name: \"draupnir\", owner: \"odin\", maker: \"elves\", count: 0});\n\n      citems.on(\"update\", (obj: User & { count: number }) => {\n        /// attempt to tamper with name\n        obj.name = \"zzz\";\n      });\n\n      citems.findAndUpdate({name: \"mjolnir\"}, function (o) {\n        // make an approved modification\n        o.count++;\n      });\n\n      const results = citems.find();\n      expect(results.length).toEqual(4);\n\n      results.forEach((obj) => {\n        expect(obj.name === \"zzz\").toEqual(false);\n      });\n\n      const mj = citems.findOne({name: \"mjolnir\"});\n      expect(mj.count).toEqual(1);\n    });\n  });\n\n  describe(\"cloning method \\\"shallow\\\" save prototype\", function () {\n    it(\"works\", () => {\n      class Item {\n        public name: string;\n        public owner: string;\n        public maker: string;\n\n        constructor(name: string, owner: string, maker: string) {\n          this.name = name;\n          this.owner = owner;\n          this.maker = maker;\n        }\n      }\n\n      const cdb = new Loki(\"clonetest\");\n      const citems = cdb.addCollection<User>(\"items\", {clone: true, cloneMethod: \"shallow\"});\n      const oldObject = new Item(\"mjolnir\", \"thor\", \"dwarves\");\n      const insObject = citems.insert(oldObject);\n\n      // cant' have either of these polluting our collection\n      oldObject.name = \"mewmew\";\n      insObject.name = \"mewmew\";\n\n      const result = citems.findOne({\"owner\": \"thor\"});\n      expect(result instanceof Item).toBe(true);\n      expect(result.name).toBe(\"mjolnir\");\n    });\n  });\n\n  describe(\"collection find() cloning works\", () => {\n    it(\"works\", () => {\n      const cdb = new Loki(\"cloningEnabled\");\n      const citems = cdb.addCollection<User>(\"items\", {\n        clone: true\n      });\n\n      citems.insert({name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\"});\n      citems.insert({name: \"gungnir\", owner: \"odin\", maker: \"elves\"});\n      citems.insert({name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\"});\n      citems.insert({name: \"draupnir\", owner: \"odin\", maker: \"elves\"});\n\n      // just to prove that ResultSet.data() is not giving the user the actual object reference we keep internally\n      // we will modify the object and see if future requests for that object show the change\n      const mj = citems.find({name: \"mjolnir\"})[0];\n      mj.maker = \"the dwarves\";\n\n      const mj2 = citems.find({name: \"mjolnir\"})[0];\n      expect(mj2.maker).toBe(\"dwarves\");\n    });\n\n    it(\"works with stringify\", () => {\n      const cdb = new Loki(\"cloningEnabled\");\n      const citems = cdb.addCollection<User>(\"items\", {\n        clone: true,\n        cloneMethod: \"parse-stringify\"\n      });\n\n      citems.insert({name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\"});\n      citems.insert({name: \"gungnir\", owner: \"odin\", maker: \"elves\"});\n      citems.insert({name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\"});\n      citems.insert({name: \"draupnir\", owner: \"odin\", maker: \"elves\"});\n\n      // just to prove that ResultSet.data() is not giving the user the actual object reference we keep internally\n      // we will modify the object and see if future requests for that object show the change\n      const mj = citems.find({name: \"mjolnir\"})[0];\n      mj.maker = \"the dwarves\";\n\n      const mj2 = citems.find({name: \"mjolnir\"})[0];\n      expect(mj2.maker).toBe(\"dwarves\");\n    });\n  });\n\n  describe(\"collection findOne() cloning works\", () => {\n    it(\"works\", () => {\n      const cdb = new Loki(\"cloningEnabled\");\n      const citems = cdb.addCollection<User>(\"items\", {\n        clone: true\n      });\n\n      citems.insert({name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\"});\n      citems.insert({name: \"gungnir\", owner: \"odin\", maker: \"elves\"});\n      citems.insert({name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\"});\n      citems.insert({name: \"draupnir\", owner: \"odin\", maker: \"elves\"});\n\n      // just to prove that ResultSet.data() is not giving the user the actual object reference we keep internally\n      // we will modify the object and see if future requests for that object show the change\n      const mj = citems.findOne({name: \"mjolnir\"});\n      mj.maker = \"the dwarves\";\n\n      const mj2 = citems.findOne({name: \"mjolnir\"});\n\n      expect(mj2.maker).toBe(\"dwarves\");\n    });\n  });\n\n  describe(\"collection where() cloning works\", () => {\n    it(\"works\", () => {\n      const cdb = new Loki(\"cloningEnabled\");\n      const citems = cdb.addCollection<User>(\"items\", {\n        clone: true\n      });\n\n      citems.insert({name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\"});\n      citems.insert({name: \"gungnir\", owner: \"odin\", maker: \"elves\"});\n      citems.insert({name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\"});\n      citems.insert({name: \"draupnir\", owner: \"odin\", maker: \"elves\"});\n\n      // just to prove that ResultSet.data() is not giving the user the actual object reference we keep internally\n      // we will modify the object and see if future requests for that object show the change\n      const mj = citems.where((obj: User) => obj.name === \"mjolnir\")[0];\n      mj.maker = \"the dwarves\";\n\n      const mj2 = citems.where((obj: User) => obj.name === \"mjolnir\")[0];\n      expect(mj2.maker).toBe(\"dwarves\");\n    });\n  });\n\n  describe(\"collection by() cloning works\", () => {\n    it(\"works\", () => {\n      const cdb = new Loki(\"cloningEnabled\");\n      const citems = cdb.addCollection<User>(\"items\", {\n        clone: true,\n        unique: [\"name\"]\n      });\n\n      citems.insert({name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\"});\n      citems.insert({name: \"gungnir\", owner: \"odin\", maker: \"elves\"});\n      citems.insert({name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\"});\n      citems.insert({name: \"draupnir\", owner: \"odin\", maker: \"elves\"});\n\n      // just to prove that ResultSet.data() is not giving the user the actual object reference we keep internally\n      // we will modify the object and see if future requests for that object show the change\n      const mj = citems.by(\"name\", \"mjolnir\");\n      mj.maker = \"the dwarves\";\n\n      const mj2 = citems.by(\"name\", \"mjolnir\");\n\n      expect(mj2.maker).toBe(\"dwarves\");\n    });\n  });\n\n  describe(\"collection by() cloning works with no data\", () => {\n    it(\"works\", () => {\n      const cdb = new Loki(\"cloningEnabled\");\n      const citems = cdb.addCollection<User>(\"items\", {\n        clone: true,\n        unique: [\"name\"]\n      });\n\n      citems.insert({name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\"});\n\n      // we dont have any items so this should return null\n      let result = citems.by(\"name\", \"gungnir\");\n      expect(result).toEqual(null);\n      result = citems.by(\"name\", \"mjolnir\");\n      expect(result.owner).toEqual(\"thor\");\n    });\n  });\n\n  describe(\"ResultSet data cloning works\", () => {\n    it(\"works\", () => {\n      const cdb = new Loki(\"cloningEnabled\");\n      const citems = cdb.addCollection<User>(\"items\", {\n        clone: true\n      });\n\n      citems.insert({name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\"});\n      citems.insert({name: \"gungnir\", owner: \"odin\", maker: \"elves\"});\n      citems.insert({name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\"});\n      citems.insert({name: \"draupnir\", owner: \"odin\", maker: \"elves\"});\n\n      // just to prove that ResultSet.data() is not giving the user the actual object reference we keep internally\n      // we will modify the object and see if future requests for that object show the change\n      const mj = citems.chain().find({name: \"mjolnir\"}).data()[0];\n      mj.maker = \"the dwarves\";\n\n      const mj2 = citems.findOne({name: \"mjolnir\"});\n      expect(mj2.maker).toBe(\"dwarves\");\n    });\n  });\n\n  describe(\"ResultSet data forced cloning works\", () => {\n    it(\"works\", () => {\n      // although our collection does not define cloning, we can choose to clone results\n      // within ResultSet.data() options\n      const mj = items.chain().find({name: \"mjolnir\"}).data({\n        forceClones: true\n      })[0];\n      mj.maker = \"the dwarves\";\n\n      const mj2 = items.findOne({name: \"mjolnir\"});\n      expect(mj2.maker).toBe(\"dwarves\");\n    });\n  });\n});\n"
  },
  {
    "path": "packages/loki/spec/generic/collection.spec.ts",
    "content": "/* global describe, it, expect */\nimport { Loki } from \"../../src/loki\";\nimport { Collection } from \"../../src/collection\";\nimport { Doc } from \"../../../common/types\";\n\ndescribe(\"collection\", () => {\n  interface CL {\n    a: number;\n    b: number;\n  }\n\n  it(\"works\", () => {\n    class SubclassedCollection extends Collection {\n      constructor(name: string, options: any = {}) {\n        super(name, options);\n      }\n\n      extendedMethod() {\n        return this.name.toUpperCase();\n      }\n    }\n\n    const coll = new SubclassedCollection(\"users\", {});\n\n    expect(coll !== null).toBe(true);\n    expect(\"users\".toUpperCase()).toEqual(coll.extendedMethod());\n    coll.insert({\n      name: \"joe\"\n    });\n    expect(coll.count()).toEqual(1);\n  });\n\n  it(\"lokimap works\", function () {\n    const db = new Loki(\"test.db\");\n    let coll = db.addCollection(\"coll\");\n    coll.insert([{a: 3, b: 3}, {a: 6, b: 7}, {a: 1, b: 2}, {a: 7, b: 8}, {a: 6, b: 4}]);\n\n    expect(Object.keys(coll._lokimap).length).toEqual(5);\n\n    let result = coll.find();\n\n    for (let doc of result) {\n      let lmdoc = coll._lokimap[doc.$loki];\n      expect(lmdoc[\"a\"]).toEqual(doc[\"a\"]);\n      expect(lmdoc[\"b\"]).toEqual(doc[\"b\"]);\n    }\n  });\n\n  it(\"collection rename works\", function () {\n    const db = new Loki(\"test.db\");\n    db.addCollection(\"coll1\");\n\n    let result = db.getCollection(\"coll1\");\n    expect(result.name).toEqual(\"coll1\");\n\n    db.renameCollection(\"coll1\", \"coll2\");\n    result = db.getCollection(\"coll1\");\n    expect(result).toBeNull();\n    result = db.getCollection(\"coll2\");\n    expect(result.name).toEqual(\"coll2\");\n  });\n\n  it(\"add existing collection name works\", function () {\n    const db = new Loki(\"test.db\");\n    const coll1 = db.addCollection(\"coll1\");\n    const coll2 = db.addCollection(\"coll1\");\n    expect(coll1).toEqual(coll2);\n  });\n\n  it(\"findAndUpdate works\", () => {\n    const db = new Loki(\"test.db\");\n    const coll = db.addCollection<CL>(\"testcoll\");\n    coll.insert([{a: 3, b: 3}, {a: 6, b: 7}, {a: 1, b: 2}, {a: 7, b: 8}, {a: 6, b: 4}]);\n\n    coll.findAndUpdate({a: 6}, (obj: CL) => {\n      obj.b += 1;\n      return obj;\n    });\n\n    const result = coll.chain().find({a: 6}).simplesort(\"b\").data();\n    expect(result.length).toEqual(2);\n    expect(result[0].b).toEqual(5);\n    expect(result[1].b).toEqual(8);\n  });\n\n  it(\"findAndRemove works\", () => {\n    const db = new Loki(\"test.db\");\n    const coll = db.addCollection<CL>(\"testcoll\");\n    coll.insert([{a: 3, b: 3}, {a: 6, b: 7}, {a: 1, b: 2}, {a: 7, b: 8}, {a: 6, b: 4}]);\n\n    coll.findAndRemove({a: 6});\n\n    expect(coll.count()).toEqual(3);\n\n    const result = coll.chain().find().simplesort(\"b\").data();\n    expect(result.length).toEqual(3);\n    expect(result[0].b).toEqual(2);\n    expect(result[1].b).toEqual(3);\n    expect(result[2].b).toEqual(8);\n  });\n\n  it(\"removeWhere works\", () => {\n    const db = new Loki(\"test.db\");\n    const coll = db.addCollection<CL>(\"testcoll\");\n    coll.insert([{a: 3, b: 3}, {a: 6, b: 7}, {a: 1, b: 2}, {a: 7, b: 8}, {a: 6, b: 4}]);\n\n    coll.removeWhere((obj: CL) => obj.a === 6);\n\n    expect(coll.count()).toEqual(3);\n\n    const result = coll.chain().find().simplesort(\"b\").data();\n    expect(result.length).toEqual(3);\n    expect(result[0].b).toEqual(2);\n    expect(result[1].b).toEqual(3);\n    expect(result[2].b).toEqual(8);\n  });\n\n  it(\"updateWhere works\", () => {\n    const db = new Loki(\"test.db\");\n    const coll = db.addCollection<CL>(\"testcoll\");\n    coll.insert([{a: 3, b: 3}, {a: 6, b: 7}, {a: 1, b: 2}, {a: 7, b: 8}, {a: 6, b: 4}]);\n\n    // guess we need to return object for this to work\n    coll.updateWhere((fobj: CL) => fobj.a === 6, (obj: Doc<CL>) => {\n      obj.b += 1;\n      return obj;\n    });\n\n    const result = coll.chain().find({a: 6}).simplesort(\"b\").data();\n    expect(result.length).toEqual(2);\n    expect(result[0].b).toEqual(5);\n    expect(result[1].b).toEqual(8);\n  });\n\n  // coll.mode(property) should return single value of property which occurs most in collection\n  // if more than one value 'ties' it will just pick one\n  it(\"mode works\", () => {\n    const db = new Loki(\"test.db\");\n    const coll = db.addCollection<CL>(\"testcoll\");\n    coll.insert([{a: 3, b: 3}, {a: 6, b: 7}, {a: 1, b: 2}, {a: 7, b: 8}, {a: 6, b: 4}]);\n    expect(coll.mode(\"a\")).toEqual(6);\n  });\n\n  it(\"single inserts emit with meta when async listeners false\", () => {\n    const db = new Loki(\"test.db\");\n    const coll = db.addCollection<CL>(\"testcoll\");\n\n    // listen for insert events to validate objects\n    coll.on(\"insert\", (obj: Doc<CL>) => {\n      expect(obj.hasOwnProperty(\"a\")).toEqual(true);\n      expect([3, 6, 1, 7, 5].indexOf(obj.a)).toBeGreaterThan(-1);\n\n      switch (obj.a) {\n        case 3:\n          expect(obj.b).toEqual(3);\n          break;\n        case 6:\n          expect(obj.b).toEqual(7);\n          break;\n        case 1:\n          expect(obj.b).toEqual(2);\n          break;\n        case 7:\n          expect(obj.b).toEqual(8);\n          break;\n        case 5:\n          expect(obj.b).toEqual(4);\n          break;\n      }\n\n\n      expect(obj.hasOwnProperty(\"$loki\")).toEqual(true);\n      expect(obj.hasOwnProperty(\"meta\")).toEqual(true);\n      expect(obj.meta.hasOwnProperty(\"revision\")).toEqual(true);\n      expect(obj.meta.hasOwnProperty(\"created\")).toEqual(true);\n      expect(obj.meta.hasOwnProperty(\"version\")).toEqual(true);\n      expect(obj.meta.revision).toEqual(0);\n      expect(obj.meta.version).toEqual(0);\n      expect(obj.meta.created).toBeGreaterThan(0);\n    });\n\n    coll.insert({a: 3, b: 3});\n    coll.insert({a: 6, b: 7});\n    coll.insert({a: 1, b: 2});\n    coll.insert({a: 7, b: 8});\n    coll.insert({a: 5, b: 4});\n  });\n\n  it(\"single inserts (with clone) emit meta and return instances correctly\", () => {\n    const db = new Loki(\"test.db\");\n    const coll = db.addCollection<CL>(\"testcoll\", {clone: true});\n\n    // listen for insert events to validate objects\n    coll.on(\"insert\", (obj: Doc<CL>) => {\n      expect(obj.hasOwnProperty(\"a\")).toEqual(true);\n      expect([3, 6, 1, 7, 5].indexOf(obj.a)).toBeGreaterThan(-1);\n\n      switch (obj.a) {\n        case 3:\n          expect(obj.b).toEqual(3);\n          break;\n        case 6:\n          expect(obj.b).toEqual(7);\n          break;\n        case 1:\n          expect(obj.b).toEqual(2);\n          break;\n        case 7:\n          expect(obj.b).toEqual(8);\n          break;\n        case 5:\n          expect(obj.b).toEqual(4);\n          break;\n      }\n\n\n      expect(obj.hasOwnProperty(\"$loki\")).toEqual(true);\n      expect(obj.hasOwnProperty(\"meta\")).toEqual(true);\n      expect(obj.meta.hasOwnProperty(\"revision\")).toEqual(true);\n      expect(obj.meta.hasOwnProperty(\"created\")).toEqual(true);\n      expect(obj.meta.hasOwnProperty(\"version\")).toEqual(true);\n      expect(obj.meta.revision).toEqual(0);\n      expect(obj.meta.version).toEqual(0);\n      expect(obj.meta.created).toBeGreaterThan(0);\n    });\n\n    const i1 = coll.insert({a: 3, b: 3});\n    coll.insert({a: 6, b: 7});\n    coll.insert({a: 1, b: 2});\n    coll.insert({a: 7, b: 8});\n    coll.insert({a: 5, b: 4});\n\n    // verify that the objects returned from an insert are clones by tampering with values\n    i1.b = 9;\n    const result = coll.findOne({a: 3});\n    expect(result.b).toEqual(3);\n  });\n\n  it(\"batch inserts emit with meta\", () => {\n    const db = new Loki(\"test.db\");\n    const coll = db.addCollection<CL>(\"testcoll\");\n\n    // listen for insert events to validate objects\n    coll.on(\"insert\", (objs: Doc<CL>[]) => {\n      expect(Array.isArray(objs)).toEqual(true);\n      expect(objs.length).toEqual(5);\n\n      expect(objs[0].b).toEqual(3);\n      expect(objs[1].b).toEqual(7);\n      expect(objs[2].b).toEqual(2);\n      expect(objs[3].b).toEqual(8);\n      expect(objs[4].b).toEqual(4);\n\n      expect(objs[0].hasOwnProperty(\"$loki\")).toEqual(true);\n      expect(objs[1].hasOwnProperty(\"$loki\")).toEqual(true);\n      expect(objs[2].hasOwnProperty(\"$loki\")).toEqual(true);\n      expect(objs[3].hasOwnProperty(\"$loki\")).toEqual(true);\n      expect(objs[4].hasOwnProperty(\"$loki\")).toEqual(true);\n\n      expect(objs[0].hasOwnProperty(\"meta\")).toEqual(true);\n      expect(objs[1].hasOwnProperty(\"meta\")).toEqual(true);\n      expect(objs[2].hasOwnProperty(\"meta\")).toEqual(true);\n      expect(objs[3].hasOwnProperty(\"meta\")).toEqual(true);\n      expect(objs[4].hasOwnProperty(\"meta\")).toEqual(true);\n\n      expect(objs[0].meta.hasOwnProperty(\"revision\")).toEqual(true);\n      expect(objs[0].meta.hasOwnProperty(\"created\")).toEqual(true);\n      expect(objs[0].meta.hasOwnProperty(\"version\")).toEqual(true);\n      expect(objs[0].meta.revision).toEqual(0);\n      expect(objs[0].meta.version).toEqual(0);\n      expect(objs[0].meta.created).toBeGreaterThan(0);\n    });\n\n    coll.insert([{a: 3, b: 3}, {a: 6, b: 7}, {a: 1, b: 2}, {a: 7, b: 8}, {a: 5, b: 4}]);\n  });\n\n  it(\"batch inserts emit with meta and return clones\", () => {\n    const db = new Loki(\"test.db\");\n    const coll = db.addCollection<CL>(\"testcoll\", {clone: true});\n\n    // listen for insert events to validate objects\n    coll.on(\"insert\", (objs: Doc<CL>[]) => {\n      expect(Array.isArray(objs)).toEqual(true);\n      expect(objs.length).toEqual(5);\n\n      expect(objs[0].b).toEqual(3);\n      expect(objs[1].b).toEqual(7);\n      expect(objs[2].b).toEqual(2);\n      expect(objs[3].b).toEqual(8);\n      expect(objs[4].b).toEqual(4);\n\n      expect(objs[0].hasOwnProperty(\"$loki\")).toEqual(true);\n      expect(objs[1].hasOwnProperty(\"$loki\")).toEqual(true);\n      expect(objs[2].hasOwnProperty(\"$loki\")).toEqual(true);\n      expect(objs[3].hasOwnProperty(\"$loki\")).toEqual(true);\n      expect(objs[4].hasOwnProperty(\"$loki\")).toEqual(true);\n\n      expect(objs[0].hasOwnProperty(\"meta\")).toEqual(true);\n      expect(objs[1].hasOwnProperty(\"meta\")).toEqual(true);\n      expect(objs[2].hasOwnProperty(\"meta\")).toEqual(true);\n      expect(objs[3].hasOwnProperty(\"meta\")).toEqual(true);\n      expect(objs[4].hasOwnProperty(\"meta\")).toEqual(true);\n\n      expect(objs[0].meta.hasOwnProperty(\"revision\")).toEqual(true);\n      expect(objs[0].meta.hasOwnProperty(\"created\")).toEqual(true);\n      expect(objs[0].meta.hasOwnProperty(\"version\")).toEqual(true);\n      expect(objs[0].meta.revision).toEqual(0);\n      expect(objs[0].meta.version).toEqual(0);\n      expect(objs[0].meta.created).toBeGreaterThan(0);\n    });\n\n    const obj1 = {a: 3, b: 3};\n    const result = coll.insert([obj1, {a: 6, b: 7}, {a: 1, b: 2}, {a: 7, b: 8}, {a: 5, b: 4}]);\n\n    expect(Array.isArray(result)).toEqual(true);\n\n    // tamper original (after insert)\n    obj1.b = 99;\n    // returned values should have been clones of original\n    expect(result[0].b).toEqual(3);\n\n    // internal data references should have benn clones of original\n    const obj = coll.findOne({a: 3});\n    expect(obj.b).toEqual(3);\n  });\n});\n"
  },
  {
    "path": "packages/loki/spec/generic/comparators.spec.ts",
    "content": "import { Loki } from \"../../src/loki\";\nimport { ILokiComparer, ComparatorMap, CreateJavascriptComparator, CreateAbstractDateJavascriptComparator, CreateAbstractJavascriptComparator } from \"../../src/comparators\";\n\ndescribe(\"comparator feature tests\", () => {\n  it(\"comparator injection works\", () => {\n    let customComparator: ILokiComparer<any> = (a: any, b: any) => {\n      if (typeof a === \"string\" && typeof b === \"string\") {\n        a = a.toLocaleLowerCase();\n        b = b.toLocaleLowerCase();\n      }\n\n      if (a === b) return 0;\n      if (a > b) return 1;\n      return -1;\n    };\n\n    let db = new Loki(\"test\", {\n      comparatorMap: {\n        \"MyCustomComparator\": customComparator\n      }\n    });\n\n    expect(typeof ComparatorMap[\"MyCustomComparator\"]).toEqual(\"function\");\n\n    let cc = ComparatorMap[\"MyCustomComparator\"];\n\n    expect(cc(\"a\", \"b\")).toEqual(-1);\n    expect(cc(\"A\", \"b\")).toEqual(-1);\n    expect(cc(\"a\", \"B\")).toEqual(-1);\n    expect(cc(\"b\", \"b\")).toEqual(0);\n    expect(cc(\"B\", \"b\")).toEqual(0);\n    expect(cc(\"b\", \"B\")).toEqual(0);\n    expect(cc(\"b\", \"a\")).toEqual(1);\n    expect(cc(\"B\", \"a\")).toEqual(1);\n    expect(cc(\"b\", \"A\")).toEqual(1);\n    expect(cc(4, 4)).toEqual(0);\n    expect(cc(1, 4)).toEqual(-1);\n    expect(cc(4, 1)).toEqual(1);\n\n    // since we are temporarily exposing ComparatorMap globally, this test proves only\n    // that the constructor will modify that global variable (which will be used by collection/resultset/etc)\n    db.close();\n  });\n\n  it(\"CreateJavascriptComparator helper function works\", () => {\n\n    let fn = CreateJavascriptComparator<any>();\n\n    expect(fn(4, 12)).toEqual(-1);\n    expect(fn(12, 4)).toEqual(1);\n    expect(fn(\"4\", 4) === 0).toEqual(false);\n    expect(fn(4, \"4\") === 0).toEqual(false);\n    expect(fn(null, undefined) === 0).toEqual(false);\n  });\n\n  it(\"CreateAbstractJavascriptComparator helper function works\", () => {\n    let fn = CreateAbstractJavascriptComparator<any>();\n\n    expect(fn(4, 12)).toEqual(-1);\n    expect(fn(\"4\", 12)).toEqual(-1);\n    expect(fn(\"4\", 4) === 0).toEqual(true);\n    expect(fn(4, \"4\") === 0).toEqual(true);\n    expect(fn(12, 4)).toEqual(1);\n    expect(fn(null, undefined) === 0).toEqual(true);\n  });\n\n  it(\"CreateAbstractDateComparator helper function works\", () => {\n    let fn = CreateAbstractDateJavascriptComparator();\n\n    expect(fn(new Date(\"2015\"), new Date(\"2015\"))).toEqual(0);\n    expect(fn(new Date(\"2015\"), new Date(\"1/1/2014\"))).toEqual(1);\n    expect(fn(new Date(\"2015\"), new Date(\"1/1/2016\"))).toEqual(-1);\n  });\n});\n"
  },
  {
    "path": "packages/loki/spec/generic/dynamic_view.spec.ts",
    "content": "/* global describe, beforeEach, it, expect */\nimport { Loki } from \"../../src/loki\";\nimport { MemoryStorage } from \"../../../memory-storage/src/memory_storage\";\nimport { Collection } from \"../../src/collection\";\nimport { Doc } from \"../../../common/types\";\nimport { LokiOperatorPackageMap } from \"../../src/operator_packages\";\n\ndescribe(\"dynamicviews\", () => {\n  interface User {\n    name: string;\n    owner?: string;\n    maker?: string;\n    age?: number;\n    lang?: string;\n  }\n\n  let testRecords: User[];\n  let db: Loki;\n  let users: Collection<User>;\n  let jonas: Doc<User>;\n\n  beforeEach(() => {\n    testRecords = [\n      {name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\"},\n      {name: \"gungnir\", owner: \"odin\", maker: \"elves\"},\n      {name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\"},\n      {name: \"draupnir\", owner: \"odin\", maker: \"elves\"}\n    ];\n\n    db = new Loki(\"test.json\");\n    users = db.addCollection<User>(\"user\");\n\n    users.insert({\n      name: \"dave\",\n      age: 25,\n      lang: \"English\"\n    });\n\n    users.insert({\n      name: \"joe\",\n      age: 39,\n      lang: \"Italian\"\n    });\n\n    jonas = users.insert({\n      name: \"jonas\",\n      age: 30,\n      lang: \"Swedish\"\n    });\n  });\n\n  function docCompare(a: Doc<User>, b: Doc<User>) {\n    if (a.$loki < b.$loki) return -1;\n    if (a.$loki > b.$loki) return 1;\n\n    return 0;\n  }\n\n  describe(\"test empty filter across changes\", () => {\n    it(\"works\", () => {\n\n      const db = new Loki(\"dvtest\");\n      const items = db.addCollection<User>(\"users\");\n      items.insert(testRecords);\n      const dv = items.addDynamicView(\"view\");\n\n      // with no filter, results should be all documents\n      let results = dv.data();\n      expect(results.length).toBe(4);\n\n      // find and update a document which will notify view to re-evaluate\n      const gungnir = items.findOne({\"name\": \"gungnir\"});\n      expect(gungnir.owner).toBe(\"odin\");\n      gungnir.maker = \"dvalin\";\n      items.update(gungnir);\n\n      results = dv.data();\n      expect(results.length).toBe(4);\n    });\n  });\n\n  describe(\"dynamic view rematerialize works as expected\", () => {\n    it(\"works\", () => {\n      const db = new Loki(\"dvtest\");\n      const items = db.addCollection<User>(\"users\");\n      items.insert(testRecords);\n      const dv = items.addDynamicView(\"view\");\n\n      dv.applyFind({\"owner\": \"odin\"});\n      dv.applyWhere((obj: User) => obj.maker === \"elves\");\n\n      expect(dv.data().length).toEqual(2);\n      expect(dv[\"_filterPipeline\"].length).toEqual(2);\n\n      dv[\"_rematerialize\"]({removeWhereFilters: true});\n      expect(dv.data().length).toEqual(2);\n      expect(dv[\"_filterPipeline\"].length).toEqual(1);\n    });\n  });\n\n  describe(\"dynamic view toJSON does not circularly reference\", () => {\n    it(\"works\", () => {\n      const db = new Loki(\"dvtest\");\n      const items = db.addCollection<User>(\"users\");\n      items.insert(testRecords);\n      const dv = items.addDynamicView(\"view\");\n\n      const obj = dv.toJSON();\n      expect(obj[\"_collection\"]).toEqual(undefined);\n    });\n  });\n\n  describe(\"dynamic view removeFilters works as expected\", () => {\n    it(\"works\", () => {\n      const db = new Loki(\"dvtest\");\n      const items = db.addCollection<User>(\"users\");\n      items.insert(testRecords);\n      const dv = items.addDynamicView(\"ownr\");\n      dv.applyFind({\"owner\": \"odin\"});\n      dv.applyWhere((obj: User) => obj.maker === \"elves\");\n\n      expect(dv[\"_filterPipeline\"].length).toEqual(2);\n      expect(dv.data().length).toEqual(2);\n\n      dv.removeFilters();\n      expect(dv[\"_filterPipeline\"].length).toEqual(0);\n      expect(dv.count()).toEqual(4);\n    });\n  });\n\n  describe(\"removeDynamicView works correctly\", () => {\n    it(\"works\", () => {\n      const db = new Loki(\"dvtest\");\n      const items = db.addCollection<User>(\"users\");\n      items.insert(testRecords);\n      const dv = items.addDynamicView(\"ownr\", {persistent: true});\n\n      dv.applyFind({\"owner\": \"odin\"});\n      dv.applyWhere((obj: User) => obj.maker === \"elves\");\n\n      expect(items[\"_dynamicViews\"].length).toEqual(1);\n\n      items.removeDynamicView(\"ownr\");\n      expect(items[\"_dynamicViews\"].length).toEqual(0);\n    });\n  });\n\n  describe(\"stepEvaluateDocument\", () => {\n    it(\"works\", () => {\n      const view = users.addDynamicView(\"test\");\n      const query = {\n        \"age\": {\n          \"$gt\": 24\n        }\n      };\n\n      view.applyFind(query);\n\n      // churn evaluateDocuments() to make sure it works right\n      jonas.age = 23;\n      users.update(jonas);\n      // evaluate documents\n      expect(view.data().length).toEqual(users.count() - 1);\n      jonas.age = 30;\n      users.update(jonas);\n      expect(view.data().length).toEqual(users.count());\n      jonas.age = 23;\n      users.update(jonas);\n      expect(view.data().length).toEqual(users.count() - 1);\n      jonas.age = 30;\n      users.update(jonas);\n      expect(view.data().length).toEqual(users.count());\n\n      // assert set equality of docArrays irrelevant of sort/sequence\n      const result1 = users.find(query).sort(docCompare);\n      const result2 = view.data().sort(docCompare);\n      result1.forEach((obj: Doc<User>) => {\n        delete obj.meta;\n      });\n      result2.forEach((obj: Doc<User>) => {\n        delete obj.meta;\n      });\n\n      expect(result1).toEqual(result2, \"Result data Equality\");\n      expect(view[\"_resultSet\"]).toEqual(view[\"_resultSet\"].copy(), \"View data equality\");\n      expect(view[\"_resultSet\"] === view[\"_resultSet\"].copy()).toBeFalsy(\"View data copy strict equality\");\n\n      return view;\n    });\n  });\n\n  describe(\"stepDynamicViewPersistence\", () => {\n    it(\"works 1\", () => {\n      const query = {\n        \"age\": {\n          \"$gt\": 24\n        }\n      };\n\n      // set up a persistent dynamic view with sort\n      const pview = users.addDynamicView(\"test2\", {\n        persistent: true\n      });\n      pview.applyFind(query);\n      pview.applySimpleSort(\"age\");\n\n      // the dynamic view depends on an internal ResultSet\n      // the persistent dynamic view also depends on an internal resultdata data array\n      // filteredrows should be applied immediately to ResultSet will be lazily built into resultdata later when data() is called\n      expect(pview[\"_resultSet\"]._filteredRows.length).toEqual(3, \"dynamic view initialization 1\");\n      expect(pview[\"_resultData\"].length).toEqual(0, \"dynamic view initialization 2\");\n\n      // compare how many documents are in results before adding new ones\n      const pviewResultsetLenBefore = pview[\"_resultSet\"]._filteredRows.length;\n\n      users.insert({\n        name: \"abc\",\n        age: 21,\n        lang: \"English\"\n      });\n\n      users.insert({\n        name: \"def\",\n        age: 25,\n        lang: \"English\"\n      });\n\n      // now see how many are in  (without rebuilding persistent view)\n      const pviewResultsetLenAfter = pview[\"_resultSet\"]._filteredRows.length;\n\n      // only one document should have been added to ResultSet (1 was filtered out)\n      expect(pviewResultsetLenBefore + 1).toEqual(pviewResultsetLenAfter, \"dv ResultSet is valid\");\n\n      // Test sorting and lazy build of resultdata\n\n      // retain copy of internal ResultSet's filteredrows before lazy sort\n      const frcopy = pview[\"_resultSet\"]._filteredRows.slice();\n      pview.data();\n      // now make a copy of internal result's filteredrows after lazy sort\n      const frcopy2 = pview[\"_resultSet\"]._filteredRows.slice();\n\n      // verify filteredrows logically matches resultdata (irrelevant of sort)\n      expect(frcopy2.length).not.toBe(0);\n      for (let idxFR = 0; idxFR < frcopy2.length; idxFR++) {\n        expect(pview[\"_resultData\"][idxFR]).not.toBe(undefined);\n        expect(pview[\"_resultData\"][idxFR]).toEqual(pview[\"_collection\"]._data[frcopy2[idxFR]],\n          \"dynamic view ResultSet/resultdata consistency\");\n      }\n      // now verify they are not exactly equal (verify sort moved stuff)\n      expect(frcopy).not.toEqual(frcopy2, \"dynamic view sort\");\n    });\n\n\n    it(\"works 2\", () => {\n      interface CR {\n        index: string;\n        a: number;\n      }\n\n      const test = db.addCollection<CR>(\"nodupes\", {\n        rangedIndexes: { index: {} }\n      });\n\n      const item = test.insert({\n        index: \"key\",\n        a: 1\n      });\n\n      let results = test.find({\n        index: \"key\"\n      });\n      expect(results.length).toEqual(1, \"one result exists\");\n      expect(results[0].a).toEqual(1, \"the correct result is returned\");\n\n\n      item.a = 2;\n      test.update(item);\n\n      results = test.find({\n        index: \"key\"\n      });\n\n      expect(results.length).toEqual(1, \"one result exists\");\n      expect(results[0].a).toEqual(2, \"the correct result is returned\");\n    });\n\n\n    it(\"works 3\", function testEmptyTableWithIndex() {\n      const itc = db.addCollection<any>(\"test\", {\n        rangedIndexes: { testindex: {} }\n      });\n\n      const resultsNoIndex = itc.find({\n        \"testid\": 2\n      });\n      expect(resultsNoIndex.length).toEqual(0);\n\n      const resultsWithIndex = itc.find({\n        \"testindex\": 4\n      });\n      //it(\"no results found\", () => {\n      expect(resultsWithIndex.length).toEqual(0);\n      //});\n    });\n\n    it(\"works 4\", (done) => {\n      // mock persistence by using memory storage\n      const mem = new MemoryStorage();\n      const db = new Loki(\"testCollections\");\n      db.initializePersistence({adapter: mem})\n        .then(() => {\n          expect(db.filename).toEqual(\"testCollections\");\n\n          const t = db.addCollection<any>(\"test1\", {\n            transactional: true\n          });\n          db.addCollection(\"test2\");\n          // Throw error on wrong remove.\n          expect(() => t.remove(\"foo\")).toThrowErrorOfType(\"Error\");\n          // Throw error on non-synced doc\n          expect(() => t.remove({\n            name: \"joe\"\n          })).toThrowErrorOfType(\"Error\");\n\n          expect(db.listCollections().length).toEqual(2);\n          t.clear();\n          const users = [{\n            name: \"joe\"\n          }, {\n            name: \"dave\"\n          }];\n          t.insert(users);\n\n          expect(2).toEqual(t.count());\n          t.remove(users);\n          expect(0).toEqual(t.count());\n\n          class TestError implements Error {\n            public name = \"TestError\";\n            public message = \"TestErrorMessage\";\n          }\n\n          db[\"_autosaveEnable\"]();\n          db.on(\"close\", () => {\n            throw new TestError();\n          });\n          db.close().then(() => done.fail, done);\n        });\n    });\n  });\n\n  it(\"applySortCriteria\", () => {\n    const db = new Loki(\"dvtest.db\");\n    const coll = db.addCollection<User>(\"any\");\n    coll.insert([{\n      name: \"mjolnir\",\n      owner: \"odin\",\n      maker: \"dwarves\",\n    }, {\n      name: \"tyrfing\",\n      owner: \"thor\",\n      maker: \"dwarves\",\n    }, {\n      name: \"gungnir\",\n      owner: \"odin\",\n      maker: \"elves\",\n    }, {\n      name: \"draupnir\",\n      owner: \"thor\",\n      maker: \"elves\",\n    }]);\n    const dv = coll.addDynamicView(\"test\");\n\n    let result = dv.applySortCriteria([\"owner\", \"maker\"]).data();\n    expect(result).toEqual(dv.applySortCriteria([[\"owner\", false], [\"maker\", false]]).data());\n    expect(result.length).toBe(4);\n    expect(result[0].name).toBe(\"mjolnir\");\n    expect(result[1].name).toBe(\"gungnir\");\n    expect(result[2].name).toBe(\"tyrfing\");\n    expect(result[3].name).toBe(\"draupnir\");\n\n    result = dv.applySortCriteria([[\"owner\", false], [\"maker\", true]]).data();\n    expect(result.length).toBe(4);\n    expect(result[0].name).toBe(\"gungnir\");\n    expect(result[1].name).toBe(\"mjolnir\");\n    expect(result[2].name).toBe(\"draupnir\");\n    expect(result[3].name).toBe(\"tyrfing\");\n\n    result = dv.applySortCriteria([[\"owner\", true], [\"maker\", false]]).data();\n    expect(result.length).toBe(4);\n    expect(result[0].name).toBe(\"tyrfing\");\n    expect(result[1].name).toBe(\"draupnir\");\n    expect(result[2].name).toBe(\"mjolnir\");\n    expect(result[3].name).toBe(\"gungnir\");\n\n    result = dv.applySortCriteria([[\"owner\", true], [\"maker\", true]]).data();\n    expect(result.length).toBe(4);\n    expect(result[0].name).toBe(\"draupnir\");\n    expect(result[1].name).toBe(\"tyrfing\");\n    expect(result[2].name).toBe(\"gungnir\");\n    expect(result[3].name).toBe(\"mjolnir\");\n\n    result = dv.applySortCriteria([\"maker\", \"owner\"]).data();\n    expect(result).toEqual(dv.applySortCriteria([[\"maker\", false], [\"owner\", false]]).data());\n    expect(result.length).toBe(4);\n    expect(result[0].name).toBe(\"mjolnir\");\n    expect(result[1].name).toBe(\"tyrfing\");\n    expect(result[2].name).toBe(\"gungnir\");\n    expect(result[3].name).toBe(\"draupnir\");\n\n    result = dv.applySortCriteria([[\"maker\", false], [\"owner\", true]]).data();\n    expect(result.length).toBe(4);\n    expect(result[0].name).toBe(\"tyrfing\");\n    expect(result[1].name).toBe(\"mjolnir\");\n    expect(result[2].name).toBe(\"draupnir\");\n    expect(result[3].name).toBe(\"gungnir\");\n\n    result = dv.applySortCriteria([[\"maker\", true], [\"owner\", false]]).data();\n    expect(result.length).toBe(4);\n    expect(result[0].name).toBe(\"gungnir\");\n    expect(result[1].name).toBe(\"draupnir\");\n    expect(result[2].name).toBe(\"mjolnir\");\n    expect(result[3].name).toBe(\"tyrfing\");\n\n    result = dv.applySortCriteria([[\"maker\", true], [\"owner\", true]]).data();\n    expect(result.length).toBe(4);\n    expect(result[0].name).toBe(\"draupnir\");\n    expect(result[1].name).toBe(\"gungnir\");\n    expect(result[2].name).toBe(\"tyrfing\");\n    expect(result[3].name).toBe(\"mjolnir\");\n  });\n\n  describe(\"dynamic view simplesort options work correctly\", () => {\n    it(\"works\", function () {\n      const db = new Loki(\"dvtest.db\");\n      let coll = db.addCollection<{ a: number, b: number }>(\"colltest\", {\n        rangedIndexes: {\n          a: {},  // uses default 'js' comparator\n          b: {}   // uses default 'js' comparator\n        }\n      });\n\n      // add basic dv with filter on a and basic simplesort on b\n      let dv = coll.addDynamicView(\"dvtest\");\n      dv.applyFind({a: {$lte: 20}});\n      dv.applySimpleSort(\"b\");\n\n      // data only needs to be inserted once since we are leaving collection intact while\n      // building up and tearing down dynamic views within it\n      coll.insert([{a: 1, b: 11}, {a: 2, b: 9}, {a: 8, b: 3}, {a: 6, b: 7}, {a: 2, b: 14}, {a: 22, b: 1}]);\n\n      // test whether results are valid\n      let results = dv.data();\n      expect(results.length).toBe(5);\n      for (let idx = 0; idx < results.length - 1; idx++) {\n        expect(LokiOperatorPackageMap[\"js\"].$lte(results[idx][\"b\"], results[idx + 1][\"b\"]));\n      }\n\n      // remove dynamic view\n      coll.removeDynamicView(\"dvtest\");\n    });\n  });\n});\n"
  },
  {
    "path": "packages/loki/spec/generic/eventEmitter.spec.ts",
    "content": "/* global describe, beforeEach, it, expect */\nimport { Loki } from \"../../src/loki\";\n\ndescribe(\"eventEmitter\", () => {\n  let db: Loki;\n  let users;\n\n  beforeEach(() => {\n    db = new Loki(\"test\");\n    users = db.addCollection(\"users\", {\n      asyncListeners: false\n    });\n\n    users.insert({\n      name: \"joe\"\n    });\n  });\n\n  it(\"async\", function testAsync() {\n    expect(db[\"_asyncListeners\"]).toBe(false);\n  });\n\n  it(\"emit\", () => {\n    const index = db.on(\"test\", function test(obj: number) {\n      expect(obj).toEqual(42);\n    });\n\n    db[\"emit\"](\"test\", 42);\n    db.removeListener(\"test\", index);\n\n    expect(db[\"_events\"][\"test\"].length).toEqual(0);\n  });\n});\n"
  },
  {
    "path": "packages/loki/spec/generic/joins.spec.ts",
    "content": "/* global describe, beforeEach, it, expect */\nimport { Loki } from \"../../src/loki\";\nimport { Collection } from \"../../src/collection\";\nimport { ResultSet } from \"../../src/result_set\";\nimport { Doc } from \"../../../common/types\";\n\ninterface Director {\n  name: string;\n  directorId: number;\n}\n\ninterface Film {\n  title: string;\n  filmId: number;\n  directorId: number;\n}\n\ndescribe(\"joins\", () => {\n  let db: Loki;\n  let directors: Collection<Director>;\n  let films: Collection<Film>;\n\n  beforeEach(() => {\n    db = new Loki(\"testJoins\");\n    directors = db.addCollection<Director>(\"directors\");\n    films = db.addCollection<Film>(\"films\");\n\n    directors.insert([{\n      name: \"Martin Scorsese\",\n      directorId: 1\n    }, {\n      name: \"Francis Ford Coppola\",\n      directorId: 2\n    }, {\n      name: \"Steven Spielberg\",\n      directorId: 3\n    }, {\n      name: \"Quentin Tarantino\",\n      directorId: 4\n    }]);\n\n    films.insert([{\n      title: \"Taxi\",\n      filmId: 1,\n      directorId: 1\n    }, {\n      title: \"Raging Bull\",\n      filmId: 2,\n      directorId: 1\n    }, {\n      title: \"The Godfather\",\n      filmId: 3,\n      directorId: 2\n    }, {\n      title: \"Jaws\",\n      filmId: 4,\n      directorId: 3\n    }, {\n      title: \"ET\",\n      filmId: 5,\n      directorId: 3\n    }, {\n      title: \"Raiders of the Lost Ark\",\n      filmId: 6,\n      directorId: 3\n    }]);\n  });\n\n  it(\"works\", () => {\n    let joined;\n\n    //Basic non-mapped join\n    joined = films.eqJoin(directors, \"directorId\", \"directorId\").data();\n    expect(joined[0].left.title).toEqual(\"Taxi\");\n\n    //Basic join with map\n    joined = films.eqJoin(directors, \"directorId\", \"directorId\", (left: Film, right: Director) => ({\n      filmTitle: left.title,\n      directorName: right.name\n    })).data();\n    expect(joined.length).toEqual(films.count());\n    expect(joined[0].filmTitle).toEqual(\"Taxi\");\n    expect(joined[0].directorName).toEqual(\"Martin Scorsese\");\n\n    //Basic non-mapped join with chained map\n    joined = films.eqJoin(directors, \"directorId\", \"directorId\")\n      .map((obj: {left: Film, right: Director}) => ({\n        filmTitle: obj.left.title,\n        directorName: obj.right.name\n      })).data();\n    expect(joined[0].filmTitle).toEqual(\"Taxi\");\n    expect(joined[0].directorName).toEqual(\"Martin Scorsese\");\n\n\n    interface Join1 {\n      filmTitle: string;\n      directorName: string;\n    }\n\n    //Test filtered join\n    joined = films\n      .chain()\n      .find({\n        directorId: 3\n      })\n      .simplesort(\"title\")\n      .eqJoin(directors, \"directorId\", \"directorId\", (left: Film, right: Director) => ({\n        filmTitle: left.title,\n        directorName: right.name\n      })) as any as ResultSet<Join1>;\n    expect(joined.data().length).toEqual(3);\n\n    //Test chaining after join\n    joined.find({\n      filmTitle: \"Jaws\"\n    });\n    expect(joined.data()[0].filmTitle).toEqual(\"Jaws\");\n\n    interface Join2 {\n      left: Doc<Film>;\n      right: Doc<Director>;\n    }\n\n    //Test calculated keys\n    joined = films.chain().eqJoin(directors,\n      (film: Film) => String(film.directorId + 1),\n      (director: Director) => String(director.directorId - 1))\n      .data() as Join2[];\n\n    expect(joined[0].right.name).toEqual(\"Steven Spielberg\");\n  });\n});\n"
  },
  {
    "path": "packages/loki/spec/generic/operator_packages.spec.ts",
    "content": "import { Loki } from \"../../src/loki\";\nimport { LokiOperatorPackageMap, LokiOperatorPackage, ComparatorOperatorPackage, aeqHelper, ltHelper, gtHelper } from \"../../src/operator_packages\";\nimport { ILokiComparer } from \"../../src/comparators\";\n\ndescribe(\"Testing operator packages feature\", () => {\n  beforeEach(() => {\n  });\n\n  it(\"LokiOperatorPackage (js) works as expected\", () => {\n    expect(LokiOperatorPackageMap[\"js\"].$eq(true, true)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"js\"].$eq(true, false)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"js\"].$eq(5, \"5\")).toEqual(false);\n    expect(LokiOperatorPackageMap[\"js\"].$eq(null, null)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"js\"].$eq(null, undefined)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"js\"].$eq(undefined, undefined)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"js\"].$eq(new Date(2015), new Date(2015))).toEqual(false);\n\n    expect(LokiOperatorPackageMap[\"js\"].$ne(true, true)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"js\"].$ne(true, false)).toEqual(true);\n\n    expect(LokiOperatorPackageMap[\"js\"].$in(4, [1, 3, 4])).toEqual(true);\n    expect(LokiOperatorPackageMap[\"js\"].$in(8, [1, 3, 4])).toEqual(false);\n\n    expect(LokiOperatorPackageMap[\"js\"].$nin(4, [1, 3, 4])).toEqual(false);\n    expect(LokiOperatorPackageMap[\"js\"].$nin(8, [1, 3, 4])).toEqual(true);\n\n    expect(LokiOperatorPackageMap[\"js\"].$gte(new Date(2015), new Date(2015))).toEqual(true);\n    expect(LokiOperatorPackageMap[\"js\"].$lt(5, 10)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"js\"].$lt(10, 5)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"js\"].$lte(5, 5)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"js\"].$lte(10, 5)).toEqual(false);\n\n    expect(LokiOperatorPackageMap[\"js\"].$gte(new Date(2015), new Date(2015))).toEqual(true);\n    expect(LokiOperatorPackageMap[\"js\"].$gt(5, 10)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"js\"].$gt(10, 5)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"js\"].$gte(5, 5)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"js\"].$gte(10, 5)).toEqual(true);\n\n    expect(LokiOperatorPackageMap[\"js\"].$len(\"abc\", 3)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"js\"].$len(\"abcd\", 3)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"js\"].$len(5, 1)).toEqual(false);\n\n    expect(LokiOperatorPackageMap[\"js\"].$where(3, function(a: any) { return a - 3 === 0; })).toEqual(true);\n    expect(LokiOperatorPackageMap[\"js\"].$where(4, function(a: any) { return a - 3 === 0; })).toEqual(false);\n\n    expect(LokiOperatorPackageMap[\"js\"].$between(5, [1, 10])).toEqual(true);\n    expect(LokiOperatorPackageMap[\"js\"].$between(null, [1, 10])).toEqual(false);\n  });\n\n  it(\"LokiAbstractOperatorPackage works as expected\", () => {\n    expect(LokiOperatorPackageMap[\"loki\"].$eq(5, \"5\")).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$eq(null, undefined)).toEqual(true);\n\n    expect(LokiOperatorPackageMap[\"loki\"].$gte(null, null)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$gt(undefined, undefined)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$gte(undefined, undefined)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$gt(0, 0)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$gte(0, 0)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$gt(new Date(2010), new Date(2015))).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$gte(new Date(2015), new Date(2015))).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$gt(\"14\", 12)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$gt(12, \"14\")).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$gt(\"10\", 12)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$gt(12, \"10\")).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$gt(\"test\", 12)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$gt(12, \"test\")).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$gt(12, 0)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$gt(0, 12)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$gt(12, \"\")).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$gt(\"\", 12)).toEqual(false);\n\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(false, false)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$lte(false, false)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(true, false)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(true, true)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$lte(true, true)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(null, null)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$lte(null, null)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(undefined, undefined)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$lte(undefined, undefined)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(-1, 0)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(0, 0)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$lte(0, 0)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(1, 0)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(new Date(2010), new Date(2015))).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(new Date(2015), new Date(2015))).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$lte(new Date(2015), new Date(2015))).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(\"12\", 14)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(14, \"12\")).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(\"10\", 12)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(12, \"10\")).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(\"test\", 12)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(12, \"test\")).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(12, 0)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(0, 12)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(12, \"\")).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$lt(\"\", 12)).toEqual(true);\n  });\n\n  it (\"user defined LokiOperatorPackage works as expected\", () => {\n    // simple inline class overriding some ops to work negatively\n    class MyOperatorPackage extends LokiOperatorPackage {\n      $gt(a: any, b: any): boolean {\n        if (a < b) return true;\n        return false;\n      }\n\n      $lt(a: any, b: any): boolean {\n        if (a > b) return true;\n        return false;\n      }\n    }\n\n    // inject our new operator into global LokiOperatorPackageMap.\n    // if it already exists, it will overwrite... this includes overriding native packages.\n    let db = new Loki(\"test.db\", {\n      lokiOperatorPackageMap : {\n        \"MyOperatorPackage\": new MyOperatorPackage()\n      }\n    });\n\n    interface IMyDoc {\n      a: number;\n      b: number;\n    }\n\n    // for this collection, we will specify to use that operator package for its find ops\n    let coll = db.addCollection<IMyDoc>(\"coll\", {\n      defaultLokiOperatorPackage: \"MyOperatorPackage\"\n    });\n\n    coll.insert([\n      { a: 8, b: 2 },\n      { a: 3, b: 7 },\n      { a: 12, b: 1 },\n      { a: 5, b: 11 },\n      { a: 6, b: 8 },\n      { a: 10, b: 6 },\n      { a: 20, b: 15 }\n    ]);\n\n    // our $lt op override actually means gt, so find all docs greater than 9 sort largest to least (desc)\n    let results = coll.chain().find({ a: { $lt: 9 } }).simplesort(\"a\", { desc: true }).data();\n\n    expect(results.length).toEqual(3);\n    expect(results[0].a).toEqual(20);\n    expect(results[1].a).toEqual(12);\n    expect(results[2].a).toEqual(10);\n  });\n\n  it (\"ComparatorOperatorPackage works as expected\", () => {\n    let customComparator: ILokiComparer<any> = (a: any, b: any) => {\n      if (typeof a === \"string\" && typeof b === \"string\") {\n        a = a.toLocaleLowerCase();\n        b = b.toLocaleLowerCase();\n      }\n\n      if (a === b) return 0;\n      if (a > b) return 1;\n      return -1;\n    };\n\n    let myComparatorOperatorPackage = new ComparatorOperatorPackage<string>(customComparator);\n\n    let db = new Loki(\"test.db\", {\n      lokiOperatorPackageMap: {\n        \"MyComparatorOperatorPackage\": myComparatorOperatorPackage\n      }\n    });\n\n    interface IMyDoc {\n      name: string;\n      num: number;\n    }\n\n    let coll = db.addCollection<IMyDoc>(\"coll\", {\n      defaultLokiOperatorPackage: \"MyComparatorOperatorPackage\"\n    });\n\n    coll.insert([\n      { name: \"a\", num: 1 },\n      { name: \"B\", num: 2 },\n      { name: \"c\", num: 3 },\n      { name: \"D\", num: 4 },\n      { name: \"e\", num: 5 },\n      { name: \"F\", num: 6 },\n      { name: \"g\", num: 7 },\n      { name: \"h\", num: 8 }\n    ]);\n\n    let results = coll.chain().find({ name : { $lte: \"d\" }}).simplesort(\"name\").data();\n\n    expect(results.length).toEqual(4);\n\n    // our filtering used our case insensitive comparator, but or sort did not...\n    // we could have mapped comparator into comparator map and set unindexedComparatorMap to use it...\n    // see another unit test for how to do that\n    expect(results[0].name).toEqual(\"B\");\n    expect(results[1].name).toEqual(\"D\");\n    expect(results[2].name).toEqual(\"a\");\n    expect(results[3].name).toEqual(\"c\");\n\n    // just making sure our in-op rewrite of variable tolowercase did not affect document\n    expect(coll.findOne({ name: \"B\"}).num).toEqual(2);\n  });\n\n  it (\"Comparator map + unindexSortComparator works as expected\", () => {\n    let customComparator: ILokiComparer<any> = (a: any, b: any) => {\n      if (typeof a === \"string\" && typeof b === \"string\") {\n        a = a.toLocaleLowerCase();\n        b = b.toLocaleLowerCase();\n      }\n\n      if (a === b) return 0;\n      if (a > b) return 1;\n      return -1;\n    };\n\n    let db = new Loki(\"test.db\", {\n      comparatorMap: {\n        \"MyCustomComparator\": customComparator\n      }\n    });\n\n    interface IMyDoc {\n      name: string;\n      num: number;\n    }\n\n    let coll = db.addCollection<IMyDoc>(\"coll\", {\n      unindexedSortComparator: \"MyCustomComparator\"\n    });\n\n    coll.insert([\n      { name: \"g\", num: 7 },\n      { name: \"a\", num: 1 },\n      { name: \"e\", num: 5 },\n      { name: \"B\", num: 2 },\n      { name: \"D\", num: 4 },\n      { name: \"F\", num: 6 },\n      { name: \"h\", num: 8 },\n      { name: \"c\", num: 3 }\n    ]);\n\n    let results = coll.chain().simplesort(\"name\").data();\n\n    expect(results[0].name).toEqual(\"a\");\n    expect(results[1].name).toEqual(\"B\");\n    expect(results[2].name).toEqual(\"c\");\n    expect(results[3].name).toEqual(\"D\");\n    expect(results[4].name).toEqual(\"e\");\n    expect(results[5].name).toEqual(\"F\");\n    expect(results[6].name).toEqual(\"g\");\n    expect(results[7].name).toEqual(\"h\");\n  });\n\n  it (\"aeqHelper works as expected\", () => {\n    expect(aeqHelper(1, \"1\")).toEqual(true);\n    expect(aeqHelper(false, false)).toEqual(true);\n    expect(aeqHelper(true, true)).toEqual(true);\n    expect(aeqHelper(false, true)).toEqual(false);\n    expect(aeqHelper(true, false)).toEqual(false);\n    expect(aeqHelper(\"\", \"\")).toEqual(true);\n    expect(aeqHelper(\"\", \" \")).toEqual(false);\n    expect(aeqHelper(\" \", \"\")).toEqual(false);\n    expect(aeqHelper(1, \"1\")).toEqual(true);\n    expect(aeqHelper(1, \"1\")).toEqual(true);\n    expect(aeqHelper(1.0, \"1\")).toEqual(true);\n    expect(aeqHelper(null, undefined)).toEqual(true);\n    expect(aeqHelper(1.0, \"1\")).toEqual(true);\n    expect(aeqHelper(new Date(\"1/1/2018\"), new Date(\"1/1/2018\"))).toEqual(true);\n    expect(aeqHelper(\"aaa\", \"AAA\")).toEqual(false);\n  });\n\n  it (\"ltHelper works as expected\", () => {\n    expect(ltHelper(\"5\", 5, true)).toEqual(true);\n    expect(ltHelper(\"5\", 5, false)).toEqual(false);\n    expect(ltHelper(\"5\", 6, false)).toEqual(true);\n    expect(ltHelper(6, \"7\", false)).toEqual(true);\n    expect(ltHelper(new Date(\"1/1/2018\"), new Date(\"2/1/2018\"), false)).toEqual(true);\n    expect(ltHelper(new Date(\"2/1/2018\"), new Date(\"1/1/2018\"), false)).toEqual(false);\n    expect(ltHelper({ a: 1 }, \"7\", false)).toEqual(false);\n  });\n\n  it (\"gtHelper works as expected\", () => {\n    expect(gtHelper(\"5\", 5, true)).toEqual(true);\n    expect(gtHelper(\"5\", 5, false)).toEqual(false);\n    expect(gtHelper(\"5\", 6, true)).toEqual(false);\n    expect(gtHelper(\"6\", 5, true)).toEqual(true);\n    expect(gtHelper(false, true, false)).toEqual(false);\n    expect(gtHelper(true, false, false)).toEqual(true);\n  });\n});\n"
  },
  {
    "path": "packages/loki/spec/generic/ops.spec.ts",
    "content": "/* global describe, beforeEach, it, expect */\nimport { Loki } from \"../../src/loki\";\nimport { Collection } from \"../../src/collection\";\nimport { LokiOperatorPackageMap } from \"../../src/operator_packages\";\n\ndescribe(\"Testing operators\", () => {\n\n  interface Tree {\n    text: string;\n    value: string;\n    id: number;\n    order: number;\n    parents_id: number[];\n    level: number;\n    open: boolean;\n    checked: boolean;\n  }\n\n  let db: Loki;\n  let tree: Collection<Tree>;\n  let res;\n\n  beforeEach(() => {\n    db = new Loki(\"testOps\");\n    tree = db.addCollection<Tree>(\"tree\");\n\n    /*\n\t\t\t * The following data represents a tree that should look like this:\n\t\t\t *\n\t\t\t ├A\n\t\t\t ├B\n\t\t\t └───┐\n\t\t\t ├C\n\t\t\t ├D\n\t\t\t └───┐\n\t\t\t ├E\n\t\t\t ├F\n\t\t\t ├G\n\t\t\t └───┐\n\t\t\t ├H\n\t\t\t ├I\n\t\t\t └───┐\n\t\t\t ├J\n\t\t\t ├K\n\t\t\t ├L\n\t\t\t ├M\n\t\t\t ├N\n\t\t\t └───┐\n\t\t\t ├O\n\t\t\t ├P\n\t\t\t └───┐\n\t\t\t ├Q\n\t\t\t └───┐\n\t\t\t ├R\n\t\t\t └───┐\n\t\t\t ├S\n\t\t\t ├T\n\t\t\t ├U\n\t\t\t ├V\n\t\t\t ├W\n\t\t\t ├X\n\t\t\t └───┐\n\t\t\t ├Y\n\t\t\t ├Z\n\t\t\t *\n\t\t\t */\n\n    tree.insert([\n      {text: \"A\", value: \"a\", id: 1, order: 1, parents_id: [], level: 0, open: true, checked: false},\n      {text: \"B\", value: \"b\", id: 2, order: 2, parents_id: [], level: 0, open: true, checked: false},\n      {text: \"C\", value: \"c\", id: 3, order: 3, parents_id: [2], level: 1, open: true, checked: false},\n      {text: \"D\", value: \"d\", id: 4, order: 4, parents_id: [], level: 0, open: true, checked: false},\n      {text: \"E\", value: \"e\", id: 5, order: 5, parents_id: [4], level: 1, open: true, checked: false},\n      {text: \"F\", value: \"f\", id: 6, order: 6, parents_id: [4], level: 1, open: true, checked: false},\n      {text: \"G\", value: \"g\", id: 7, order: 7, parents_id: [], level: 0, open: true, checked: false},\n      {text: \"H\", value: \"h\", id: 8, order: 8, parents_id: [7], level: 1, open: true, checked: false},\n      {text: \"I\", value: \"i\", id: 9, order: 9, parents_id: [7], level: 1, open: true, checked: false},\n      {text: \"J\", value: \"j\", id: 10, order: 10, parents_id: [7, 9], level: 2, open: true, checked: false},\n      {text: \"K\", value: \"k\", id: 11, order: 11, parents_id: [7, 9], level: 2, open: true, checked: false},\n      {text: \"L\", value: \"l\", id: 12, order: 12, parents_id: [7], level: 1, open: true, checked: false},\n      {text: \"M\", value: \"m\", id: 13, order: 13, parents_id: [7], level: 1, open: true, checked: false},\n      {text: \"N\", value: \"n\", id: 14, order: 14, parents_id: [], level: 0, open: true, checked: false},\n      {text: \"O\", value: \"o\", id: 15, order: 15, parents_id: [14], level: 1, open: true, checked: false},\n      {text: \"P\", value: \"p\", id: 16, order: 16, parents_id: [14], level: 1, open: true, checked: false},\n      {text: \"Q\", value: \"q\", id: 17, order: 17, parents_id: [14, 16], level: 2, open: true, checked: false},\n      {text: \"R\", value: \"r\", id: 18, order: 18, parents_id: [14, 16, 17], level: 3, open: true, checked: false},\n      {text: \"S\", value: \"s\", id: 19, order: 19, parents_id: [14, 16, 17, 18], level: 4, open: true, checked: false},\n      {text: \"T\", value: \"t\", id: 20, order: 20, parents_id: [14, 16, 17], level: 3, open: true, checked: false},\n      {text: \"U\", value: \"u\", id: 21, order: 21, parents_id: [14, 16], level: 2, open: true, checked: false},\n      {text: \"V\", value: \"v\", id: 22, order: 22, parents_id: [14], level: 1, open: true, checked: false},\n      {text: \"W\", value: \"w\", id: 23, order: 23, parents_id: [], level: 0, open: true, checked: false},\n      {text: \"X\", value: \"x\", id: 24, order: 24, parents_id: [], level: 0, open: true, checked: false},\n      {text: \"Y\", value: \"y\", id: 25, order: 25, parents_id: [24], level: 1, open: true, checked: false},\n      {text: \"Z\", value: \"z\", id: 26, order: 26, parents_id: [24], level: 1, open: true, checked: false}\n    ]);\n  });\n\n  it(\"$size works\", () => {\n    res = tree\n      .chain()\n      .find({\n        \"parents_id\": {\"$size\": 4}\n      });\n    expect(res.data().length).toEqual(1);\n    expect(res.data()[0].value).toEqual(\"s\");\n  });\n});\n\ndescribe(\"Individual operator tests\", () => {\n\n  it(\"$ne op works as expected with 'loki' comparator\", () => {\n    expect(LokiOperatorPackageMap[\"loki\"].$ne(15, 20)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$ne(15, 15.0)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$ne(0, \"0\")).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$ne(NaN, NaN)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$ne(\"en\", NaN)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$ne(0, NaN)).toEqual(true);\n  });\n\n  it(\"misc eq ops works as expected\", () => {\n    expect(LokiOperatorPackageMap[\"loki\"].$eq(1, 11)).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$eq(1, \"1\")).toEqual(true);\n\n    const dt1 = new Date();\n    const dt2 = new Date();\n    dt2.setTime(dt1.getTime());\n    const dt3 = new Date();\n    dt3.setTime(dt1.getTime() - 10000);\n\n    expect(LokiOperatorPackageMap[\"loki\"].$eq(dt1, dt2)).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$eq(dt1, dt3)).toEqual(false);\n  });\n\n  it(\"$type op works as expected\", () => {\n    expect(LokiOperatorPackageMap[\"loki\"].$type(\"test\", \"string\")).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$type(4, \"number\")).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$type({a: 1}, \"object\")).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$type(new Date(), \"date\")).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$type([1, 2], \"array\")).toEqual(true);\n\n    expect(LokiOperatorPackageMap[\"loki\"].$type(\"test\", \"number\")).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$type(4, \"string\")).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$type({a: 1}, \"date\")).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$type(new Date(), \"object\")).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$type([1, 2], \"number\")).toEqual(false);\n  });\n\n  it(\"$in op works as expected\", () => {\n    expect(LokiOperatorPackageMap[\"loki\"].$in(4, [1, 2, 3, 4])).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$in(7, [1, 2, 3, 4])).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$in(\"el\", \"hello\")).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$in(\"le\", \"hello\")).toEqual(false);\n  });\n\n  it(\"$between op works as expected\", () => {\n    expect(LokiOperatorPackageMap[\"loki\"].$between(75, [5, 100])).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$between(75, [75, 100])).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$between(75, [5, 75])).toEqual(true);\n    expect(LokiOperatorPackageMap[\"loki\"].$between(75, [5, 74])).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$between(75, [76, 100])).toEqual(false);\n    expect(LokiOperatorPackageMap[\"loki\"].$between(null, [5, 100])).toEqual(false);\n  });\n\n  it(\"$between find works as expected\", () => {\n    // test unindexed code path\n    let db = new Loki(\"db\");\n\n    interface User {\n      name: string;\n      count: number;\n    }\n\n    let coll: Collection<User> = db.addCollection<User>(\"coll\");\n    coll.insert({name: \"mjolnir\", count: 73});\n    coll.insert({name: \"gungnir\", count: 5});\n    coll.insert({name: \"tyrfing\", count: 15});\n    coll.insert({name: \"draupnir\", count: 132});\n\n    // simple inner between\n    let results = coll.chain().find({count: {$between: [10, 80]}}).simplesort(\"count\").data();\n    expect(results.length).toEqual(2);\n    expect(results[0].count).toEqual(15);\n    expect(results[1].count).toEqual(73);\n\n    // range exceeds bounds\n    results = coll.find({count: {$between: [100, 200]}});\n    expect(results.length).toEqual(1);\n    expect(results[0].count).toEqual(132);\n\n    // no matches in range\n    expect(coll.find({count: {$between: [133, 200]}}).length).toEqual(0);\n    expect(coll.find({count: {$between: [1, 4]}}).length).toEqual(0);\n\n    // multiple low and high bounds\n    db = new Loki(\"db\");\n    coll = db.addCollection<User>(\"coll\");\n    coll.insert({name: \"first\", count: 5});\n    coll.insert({name: \"mjolnir\", count: 15});\n    coll.insert({name: \"gungnir\", count: 15});\n    coll.insert({name: \"tyrfing\", count: 75});\n    coll.insert({name: \"draupnir\", count: 75});\n    coll.insert({name: \"last\", count: 100});\n\n    results = coll.chain().find({count: {$between: [15, 75]}}).simplesort(\"count\").data();\n    expect(results.length).toEqual(4);\n    expect(results[0].count).toEqual(15);\n    expect(results[1].count).toEqual(15);\n    expect(results[2].count).toEqual(75);\n    expect(results[3].count).toEqual(75);\n\n    expect(coll.find({count: {$between: [-1, 4]}}).length).toEqual(0);\n    expect(coll.find({count: {$between: [-1, 5]}}).length).toEqual(1);\n    expect(coll.find({count: {$between: [-1, 6]}}).length).toEqual(1);\n    expect(coll.find({count: {$between: [99, 140]}}).length).toEqual(1);\n    expect(coll.find({count: {$between: [100, 140]}}).length).toEqual(1);\n    expect(coll.find({count: {$between: [101, 140]}}).length).toEqual(0);\n    expect(coll.find({count: {$between: [12, 76]}}).length).toEqual(4);\n    expect(coll.find({count: {$between: [20, 60]}}).length).toEqual(0);\n\n    // now test -indexed- code path\n    coll.ensureRangedIndex(\"count\");\n\n    results = coll.chain().find({count: {$between: [15, 75]}}).simplesort(\"count\").data();\n    expect(results.length).toEqual(4);\n    expect(results[0].count).toEqual(15);\n    expect(results[1].count).toEqual(15);\n    expect(results[2].count).toEqual(75);\n    expect(results[3].count).toEqual(75);\n\n    expect(coll.find({count: {$between: [-1, 4]}}).length).toEqual(0);\n    expect(coll.find({count: {$between: [-1, 5]}}).length).toEqual(1);\n    expect(coll.find({count: {$between: [-1, 6]}}).length).toEqual(1);\n    expect(coll.find({count: {$between: [99, 140]}}).length).toEqual(1);\n    expect(coll.find({count: {$between: [100, 140]}}).length).toEqual(1);\n    expect(coll.find({count: {$between: [101, 140]}}).length).toEqual(0);\n    expect(coll.find({count: {$between: [12, 76]}}).length).toEqual(4);\n    expect(coll.find({count: {$between: [20, 60]}}).length).toEqual(0);\n  });\n\n  it(\"indexed $in find works as expected\", () => {\n    interface User {\n      name: string;\n      count: number;\n    }\n\n    // test unindexed code path\n    const db = new Loki(\"db\");\n    const coll = db.addCollection<User>(\"coll\", { rangedIndexes: { \"count\": {} } });\n    coll.insert({name: \"mjolnir\", count: 73});\n    coll.insert({name: \"gungnir\", count: 5});\n    coll.insert({name: \"tyrfing\", count: 15});\n    coll.insert({name: \"draupnir\", count: 132});\n\n    const results = coll.chain().find({count: {$in: [15, 73]}}).simplesort(\"count\").data();\n    expect(results.length).toEqual(2);\n    expect(results[0].count).toEqual(15);\n    expect(results[1].count).toEqual(73);\n  });\n\n  it(\"$keyin and $nkeyin\", () => {\n    interface User {\n      name: string;\n    }\n\n    const db = new Loki(\"db\");\n    const coll = db.addCollection<User>(\"coll\");\n    coll.insert({name: \"mjolnir\"});\n\n    let results = coll.find({name: {$keyin: {mjolnir: \"not relevant\"}}});\n    expect(results.length).toEqual(1);\n\n    results = coll.find({name: {$keyin: {mjolnir: undefined}}});\n    expect(results.length).toEqual(1);\n\n    results = coll.find({name: {$nkeyin: {mjolnir: \"not relevant\"}}});\n    expect(results.length).toEqual(0);\n\n    results = coll.find({name: {$nkeyin: {mjolnir: undefined}}});\n    expect(results.length).toEqual(0);\n  });\n\n  it(\"$definedin and $ndefinedin\", () => {\n    interface User {\n      name: string;\n    }\n\n    const db = new Loki(\"db\");\n    const coll = db.addCollection<User>(\"coll\");\n    coll.insert({name: \"mjolnir\"});\n\n    let results = coll.find({name: {$definedin: {mjolnir: \"not relevant\"}}});\n    expect(results.length).toEqual(1);\n\n    results = coll.find({name: {$definedin: {mjolnir: undefined}}});\n    expect(results.length).toEqual(0);\n\n    results = coll.find({name: {$undefinedin: {mjolnir: \"not relevant\"}}});\n    expect(results.length).toEqual(0);\n\n    results = coll.find({name: {$undefinedin: {mjolnir: undefined}}});\n    expect(results.length).toEqual(1);\n  });\n\n  describe(\"$contains, $containsNone, $containsAny\", () => {\n\n    describe(\"string\", () => {\n      interface User {\n        name: string;\n      }\n\n      const db = new Loki(\"db\");\n      const coll = db.addCollection<User>(\"coll\");\n      coll.insert({name: \"odin\"});\n      coll.insert({name: \"thor\"});\n      coll.insert({name: \"svafrlami\"});\n      coll.insert({name: \"arngrim\"});\n\n      it(\"$contains\", () => {\n        let results = coll.find({name: {$contains: \"d\"}});\n        expect(results.length).toEqual(1);\n        expect(results[0].name).toEqual(\"odin\");\n\n        results = coll.find({name: {$contains: [\"o\", \"i\"]}});\n        expect(results.length).toEqual(1);\n        expect(results[0].name).toEqual(\"odin\");\n\n        results = coll.find({name: {$contains: \"x\"}});\n        expect(results.length).toEqual(0);\n      });\n\n      it(\"$containsNone\", () => {\n        let results = coll.find({name: {$containsNone: \"d\"}});\n        expect(results.length).toEqual(3);\n        expect(results[0].name).toEqual(\"thor\");\n        expect(results[1].name).toEqual(\"svafrlami\");\n        expect(results[2].name).toEqual(\"arngrim\");\n\n        results = coll.find({name: {$containsNone: [\"i\", \"o\"]}});\n        expect(results.length).toEqual(0);\n\n        results = coll.find({name: {$containsNone: \"x\"}});\n        expect(results.length).toEqual(4);\n      });\n\n      it(\"$containsAny\", () => {\n        let results = coll.find({name: {$containsAny: \"d\"}});\n        expect(results.length).toEqual(1);\n        expect(results[0].name).toEqual(\"odin\");\n\n        results = coll.find({name: {$containsAny: [\"o\", \"i\"]}});\n        expect(results.length).toEqual(4);\n\n        results = coll.find({name: {$containsAny: \"x\"}});\n        expect(results.length).toEqual(0);\n      });\n    });\n\n    describe(\"array\", () => {\n      interface User {\n        name: string;\n        weapons: string[];\n      }\n\n      const db = new Loki(\"db\");\n      const coll = db.addCollection<User>(\"coll\");\n      coll.insert({name: \"odin\", weapons: [\"gungnir\", \"draupnir\"]});\n      coll.insert({name: \"thor\", weapons: [\"mjolnir\"]});\n      coll.insert({name: \"svafrlami\", weapons: [\"tyrfing\"]});\n      coll.insert({name: \"arngrim\", weapons: [\"tyrfing\"]});\n\n      it(\"$contains\", () => {\n        let results = coll.find({weapons: {$contains: [\"gungnir\", \"draupnir\"]}});\n        expect(results.length).toEqual(1);\n        expect(results[0].name).toEqual(\"odin\");\n\n        results = coll.find({weapons: {$contains: [\"mjolnir\"]}});\n        expect(results).toEqual(coll.find({weapons: {$contains: \"mjolnir\"}}));\n        expect(results.length).toEqual(1);\n        coll.find({weapons: {$contains: \"mjolnir\"}});\n\n        results = coll.find({weapons: {$contains: [\"mjolnir\", \"tyrfing\"]}});\n        expect(results.length).toEqual(0);\n      });\n\n      it(\"$containsNone\", () => {\n        let results = coll.find({weapons: {$containsNone: [\"mjolnir\", \"tyrfing\"]}});\n        expect(results.length).toEqual(1);\n        expect(results[0].name).toEqual(\"odin\");\n\n        results = coll.find({weapons: {$containsNone: [\"draupnir\"]}});\n        expect(results.length).toEqual(3);\n      });\n\n      it(\"$containsAny\", () => {\n        let results = coll.find({weapons: {$containsAny: [\"gungnir\", \"mjolnir\"]}});\n        expect(results.length).toEqual(2);\n        expect(results[0].name).toEqual(\"odin\");\n        expect(results[1].name).toEqual(\"thor\");\n\n        results = coll.find({weapons: {$containsAny: [\"svafrlami\"]}});\n        expect(results.length).toEqual(0);\n      });\n    });\n\n    describe(\"object\", () => {\n      interface User {\n        name: string;\n        options: {\n          a?: boolean;\n          b?: boolean;\n          c?: boolean;\n        };\n      }\n\n      const db = new Loki(\"db\");\n      const coll = db.addCollection<User>(\"coll\");\n      coll.insert({name: \"odin\", options: {a: true, b: true}});\n      coll.insert({name: \"thor\", options: {a: true}});\n      coll.insert({name: \"svafrlami\", options: {}});\n      coll.insert({name: \"arngrim\", options: {b: true}});\n\n      it(\"$contains\", () => {\n        let results = coll.find({options: {$contains: [\"a\", \"b\"]}});\n        expect(results.length).toEqual(1);\n        expect(results[0].name).toEqual(\"odin\");\n\n        results = coll.find({options: {$contains: [\"a\"]}});\n        expect(results).toEqual(coll.find({options: {$contains: \"a\"}}));\n        expect(results.length).toEqual(2);\n        expect(results[0].name).toEqual(\"odin\");\n        expect(results[1].name).toEqual(\"thor\");\n\n        results = coll.find({options: {$contains: [\"c\"]}});\n        expect(results.length).toEqual(0);\n      });\n\n      it(\"$containsNone\", () => {\n        let results = coll.find({options: {$containsNone: [\"a\"]}});\n        expect(results).toEqual(coll.find({options: {$containsNone: \"a\"}}));\n        expect(results.length).toEqual(2);\n        expect(results[0].name).toEqual(\"svafrlami\");\n        expect(results[1].name).toEqual(\"arngrim\");\n\n        results = coll.find({options: {$containsNone: [\"a\", \"b\"]}});\n        expect(results.length).toEqual(1);\n        expect(results[0].name).toEqual(\"svafrlami\");\n\n        results = coll.find({options: {$containsNone: [\"c\"]}});\n        expect(results.length).toEqual(4);\n      });\n\n      it(\"$containsAny\", () => {\n        let results = coll.find({options: {$containsAny: [\"a\", \"b\"]}});\n        expect(results.length).toEqual(3);\n        expect(results[0].name).toEqual(\"odin\");\n        expect(results[1].name).toEqual(\"thor\");\n        expect(results[2].name).toEqual(\"arngrim\");\n\n        results = coll.find({options: {$containsAny: [\"b\"]}});\n        expect(results).toEqual(coll.find({options: {$containsAny: \"b\"}}));\n        expect(results.length).toEqual( 2);\n        expect(results[0].name).toEqual(\"odin\");\n        expect(results[1].name).toEqual(\"arngrim\");\n\n        results = coll.find({options: {$containsAny: [\"c\"]}});\n        expect(results.length).toEqual(0);\n      });\n    });\n  });\n\n  it(\"ops work with mixed datatypes\", () => {\n    const db = new Loki(\"db\");\n\n    interface AB {\n      a: any;\n      b: number;\n    }\n\n    const coll = db.addCollection<AB>(\"coll\", { defaultLokiOperatorPackage: \"loki\" });\n\n    coll.insert({a: null, b: 5});\n    coll.insert({a: \"asdf\", b: 5});\n    coll.insert({a: \"11\", b: 5});\n    coll.insert({a: 2, b: 5});\n    coll.insert({a: \"1\", b: 5});\n    coll.insert({a: \"4\", b: 5});\n    coll.insert({a: 7.2, b: 5});\n    coll.insert({a: \"5\", b: 5});\n    coll.insert({a: 4, b: 5});\n    coll.insert({a: \"18.1\", b: 5});\n\n    expect(coll.findOne({a: \"asdf\"}).a).toEqual(\"asdf\");\n    // loki equality is abstract\n    expect(coll.find({a: 4}).length).toEqual(2);\n    expect(coll.find({a: \"4\"}).length).toEqual(2);\n    // default range ops (lt, lte, gt, gte, between) are loose\n    expect(coll.find({a: {$between: [4, 12]}}).length).toEqual(5); // \"4\", 4, \"5\", 7.2, \"11\"\n    expect(coll.find({a: {$gte: \"7.2\"}}).length).toEqual(4); // 7.2, \"11\", \"18.1\", \"asdf\" (strings after numbers)\n    expect(coll.chain().find({a: {$gte: \"7.2\"}}).find({a: {$finite: true}}).data().length).toEqual(3); // 7.2, \"11\", \"18.1\"\n    expect(coll.find({a: {$gt: \"7.2\"}}).length).toEqual(3); // \"11\", \"18.1\", \"asdf\"\n    expect(coll.find({a: {$lte: \"7.2\"}}).length).toEqual(7); // 7.2, \"5\", \"4\", 4, 2, 1, null\n\n    // expect same behavior when avl index is applied to property being queried\n    coll.ensureIndex(\"a\");\n\n    expect(coll.findOne({a: \"asdf\"}).a).toEqual(\"asdf\");\n    // loki equality is abstract, whether indexed or not\n    expect(coll.find({a: 4}).length).toEqual(2);\n    expect(coll.find({a: \"4\"}).length).toEqual(2);\n    // default range ops (lt, lte, gt, gte, between) are loose\n    expect(coll.find({a: {$between: [4, 12]}}).length).toEqual(5); // \"4\", 4, \"5\", 7.2, \"11\"\n    expect(coll.find({a: {$gte: \"7.2\"}}).length).toEqual(4); // 7.2, \"11\", \"18.1\", \"asdf\" (strings after numbers)\n    expect(coll.chain().find({a: {$gte: \"7.2\"}}).find({a: {$finite: true}}).data().length).toEqual(3); // 7.2, \"11\", \"18.1\"\n    expect(coll.find({a: {$gt: \"7.2\"}}).length).toEqual(3); // \"11\", \"18.1\", \"asdf\"\n    expect(coll.find({a: {$lte: \"7.2\"}}).length).toEqual(7); // 7.2, \"5\", \"4\", 4, 2, 1, null\n  });\n});\n"
  },
  {
    "path": "packages/loki/spec/generic/persistence.spec.ts",
    "content": "/* global describe, beforeEach, it, expect */\nimport { Loki } from \"../../src/loki\";\nimport { MemoryStorage } from \"../../../memory-storage/src/memory_storage\";\nimport { Collection } from \"../../src/collection\";\nimport { StorageAdapter } from \"../../../common/types\";\nimport { AvlTreeIndex } from \"../../src/avl_index\";\nimport { CreateJavascriptComparator } from \"../../src/comparators\";\n\ninterface AB {\n  a: number;\n  b: number;\n}\n\ninterface Test {\n  name: string;\n  val: number;\n}\n\ninterface User {\n  name: string;\n  owner?: string;\n  maker?: string;\n}\n\ndescribe(\"testing unique index serialization\", () => {\n  let db: Loki;\n\n  interface AUser {\n    username: string;\n  }\n\n  let users: Collection<AUser>;\n  beforeEach(() => {\n    db = new Loki();\n    users = db.addCollection<AUser>(\"users\");\n    users.insert([{\n      username: \"joe\"\n    }, {\n      username: \"jack\"\n    }, {\n      username: \"john\"\n    }, {\n      username: \"jim\"\n    }]);\n    users.ensureUniqueIndex(\"username\");\n  });\n\n  it(\"should have a unique index\", () => {\n    const ser = db.serialize(), reloaded = new Loki();\n    reloaded.loadJSON(ser);\n    const coll = reloaded.getCollection<AUser>(\"users\");\n    expect(coll.count()).toEqual(4);\n    expect(coll._constraints.unique[\"username\"]).toBeDefined();\n    const joe = coll.by(\"username\", \"joe\");\n    expect(joe).toBeDefined();\n    expect(joe.username).toEqual(\"joe\");\n\n    expect(reloaded[\"_serializationMethod\"]).toBe(\"normal\");\n    expect(reloaded[\"_destructureDelimiter\"]).toBe(\"$<\\n\");\n  });\n});\n\ndescribe(\"testing nested avl index serialization\", () => {\n  let db: Loki;\n\n  interface AUser {\n    user: {\n      id: number;\n    };\n  }\n\n  interface Nested {\n    \"user.id\": number;\n  }\n\n  let users: Collection<AUser, Nested>;\n  beforeEach(() => {\n    db = new Loki();\n    users = db.addCollection<AUser, Nested>(\"users\", {\n      nestedProperties: [\"user.id\"],\n      rangedIndexes: { \"user.id\": { indexTypeName: \"avl\", comparatorName: \"js\" } }\n    });\n    users.insert([\n      { user: { id: 1 } },\n      { user: { id: 2 } },\n      { user: { id: 3 } },\n      { user: { id: 4 } }\n    ]);\n  });\n\n  it(\"should have a ranged index\", function () {\n    /*\n    const ser = db.serialize();\n    const reloaded = new Loki();\n    reloaded.loadJSON(ser);\n    const coll = reloaded.getCollection<AUser, Nested>(\"users\");\n    expect(coll.count()).toEqual(4);\n    const joe = coll.findOne({ \"user.id\": 1 });\n    expect(joe).toBeDefined();\n    expect(joe.user.id).toEqual(1);\n    */\n    expect(users.find().length).toEqual(4);\n  });\n});\n\ndescribe(\"testing avl index serialization\", function () {\n  it(\"collection find ops on avl index work\", (done) => {\n    interface TestUserType {\n      name: string;\n      age: number;\n      location: string;\n    }\n\n    const memAdapter = new MemoryStorage();\n    const db = new Loki(\"idxtest\");\n    db.initializePersistence({ adapter: memAdapter });\n\n    const items = db.addCollection<TestUserType>(\"users\", {\n      rangedIndexes: {\n        name: { indexTypeName: \"avl\", comparatorName: \"js\" }\n      }\n    });\n\n    items.insert([\n      { name: \"patterson\", age: 10, location: \"a\" },\n      { name: \"gilbertson\", age: 20, location: \"b\" },\n      { name: \"smith\", age: 30, location: \"c\" },\n      { name: \"donaldson\", age: 40, location: \"d\" },\n      { name: \"harrison\", age: 50, location: \"e\" },\n      { name: \"thompson\", age: 60, location: \"f\" },\n      { name: \"albertson\", age: 70, location: \"g\" },\n      { name: \"fiset\", age: 80, location: \"h\" }\n    ]);\n\n    db.saveDatabase().then(() => {\n      // now deserialize via loadDatabase() and ensure index is functional\n      const db2 = new Loki(\"idxtest\");\n      db2.initializePersistence({ adapter: memAdapter });\n      db2.loadDatabase({}).then(() => {\n        let items2 = db.getCollection<TestUserType>(\"users\");\n\n        // $eq\n        let results: TestUserType[] = items2.find({ name: \"donaldson\" });\n        expect(results.length).toEqual(1);\n        expect(results[0].name).toEqual(\"donaldson\");\n        expect(results[0].age).toEqual(40);\n        expect(results[0].location).toEqual(\"d\");\n\n        // $lt\n        results = items2.find({ name: { $lt: \"giraffe\" } });\n        expect(results.length).toEqual(4);\n        expect(results[0].name).toEqual(\"albertson\");\n        expect(results[1].name).toEqual(\"donaldson\");\n        expect(results[2].name).toEqual(\"fiset\");\n        expect(results[3].name).toEqual(\"gilbertson\");\n\n        // $lte\n        results = items2.find({ name: { $lte: \"fiset\" } });\n        expect(results.length).toEqual(3);\n        expect(results[0].name).toEqual(\"albertson\");\n        expect(results[1].name).toEqual(\"donaldson\");\n        expect(results[2].name).toEqual(\"fiset\");\n\n        // $gt\n        results = items2.find({ name: { $gt: \"giraffe\" } });\n        expect(results.length).toEqual(4);\n        expect(results[0].name).toEqual(\"harrison\");\n        expect(results[1].name).toEqual(\"patterson\");\n        expect(results[2].name).toEqual(\"smith\");\n        expect(results[3].name).toEqual(\"thompson\");\n\n        // $gte\n        results = items2.find({ name: { $gte: \"patterson\" } });\n        expect(results.length).toEqual(3);\n        expect(results[0].name).toEqual(\"patterson\");\n        expect(results[1].name).toEqual(\"smith\");\n        expect(results[2].name).toEqual(\"thompson\");\n\n        // $between\n        results = items2.find({ name: { $between: [\"faraday\", \"samuel\"] } });\n        expect(results.length).toEqual(4);\n        expect(results[0].name).toEqual(\"fiset\");\n        expect(results[1].name).toEqual(\"gilbertson\");\n        expect(results[2].name).toEqual(\"harrison\");\n        expect(results[3].name).toEqual(\"patterson\");\n\n        // make sure we are acutally using avl tree index\n        expect(items2._rangedIndexes[\"name\"].indexTypeName).toEqual(\"avl\");\n        expect(items2._rangedIndexes[\"name\"].comparatorName).toEqual(\"js\");\n        expect(typeof items2._rangedIndexes[\"name\"].index.rangeRequest).toEqual(\"function\");\n        expect(items2._rangedIndexes[\"name\"].index.constructor.name).toEqual(\"AvlTreeIndex\");\n\n        done();\n      });\n    });\n  });\n\n  it(\"avl backup and restore work correctly\", function () {\n    let bst = new AvlTreeIndex(\"test\", CreateJavascriptComparator());\n    bst.insert(1, \"f\");\n    bst.insert(2, \"b\");\n    bst.insert(3, \"c\");\n    bst.insert(4, \"a\");\n    bst.insert(5, \"d\");\n\n    let bkp = bst.backup();\n\n    // add another to original to ensure backup does not include it\n    bst.insert(6, \"g\");\n\n    let bst2 = new AvlTreeIndex(\"test\", CreateJavascriptComparator());\n    bst2.restore(JSON.parse(JSON.stringify(bkp)));\n\n    let results = bst2.rangeRequest();\n    expect(results.length).toEqual(5);\n    expect(results[0]).toEqual(4);\n    expect(results[1]).toEqual(2);\n    expect(results[2]).toEqual(3);\n    expect(results[3]).toEqual(5);\n    expect(results[4]).toEqual(1);\n  });\n});\n\ndescribe(\"testing disable meta serialization\", function () {\n  it(\"should have meta disabled\", function () {\n    const db = new Loki();\n    db.addCollection<User>(\"users\", { disableMeta: true });\n\n    const ser = db.serialize();\n    const reloaded = new Loki();\n    reloaded.loadJSON(ser);\n    const coll = reloaded.getCollection(\"users\");\n    expect(coll[\"_disableMeta\"]).toEqual(true);\n  });\n});\n\ndescribe(\"testing destructured serialization/deserialization\", () => {\n  it(\"verify default (D) destructuring works as expected\", () => {\n    const ddb = new Loki(\"test.db\", { serializationMethod: \"destructured\" });\n    const coll = ddb.addCollection<Test>(\"testcoll\");\n    coll.insert({\n      name: \"test1\",\n      val: 100\n    });\n    coll.insert({\n      name: \"test2\",\n      val: 101\n    });\n    coll.insert({\n      name: \"test3\",\n      val: 102\n    });\n\n    const coll2 = ddb.addCollection<AB>(\"another\");\n    coll2.insert({\n      a: 1,\n      b: 2\n    });\n\n    const destructuredJson = ddb.serialize();\n\n    const cddb = new Loki(\"test.db\", { serializationMethod: \"destructured\" });\n    cddb.loadJSON(destructuredJson);\n\n    expect(cddb[\"_serializationMethod\"]).toEqual(\"destructured\");\n    expect(cddb[\"_collections\"].length).toEqual(2);\n    expect(cddb[\"_collections\"][0].count()).toEqual(3);\n    expect(cddb[\"_collections\"][0]._data[0][\"val\"]).toEqual(ddb[\"_collections\"][0]._data[0][\"val\"]);\n    expect(cddb[\"_collections\"][1].count()).toEqual(1);\n    expect(cddb[\"_collections\"][1]._data[0][\"a\"]).toEqual(ddb[\"_collections\"][1]._data[0][\"a\"]);\n  });\n\n  // Destructuring Formats :\n  // D : one big Delimited string { partitioned: false, delimited : true }\n  // DA : Delimited Array of strings [0] db [1] collection [n] collection { partitioned: true, delimited: true }\n  // NDA : Non-Delimited Array : one iterable array with empty string collection partitions { partitioned: false, delimited: false }\n  // NDAA : Non-Delimited Array with subArrays. db at [0] and collection subarrays at [n] { partitioned: true, delimited : false }\n\n  it(\"verify custom destructuring works as expected\", () => {\n    const methods = [\"D\", \"DA\", \"NDA\", \"NDAA\"];\n    let idx, options, result;\n    let cddb;\n    const ddb = new Loki(\"test.db\");\n    const coll = ddb.addCollection<Test>(\"testcoll\");\n    coll.insert({\n      name: \"test1\",\n      val: 100\n    });\n    coll.insert({\n      name: \"test2\",\n      val: 101\n    });\n    coll.insert({\n      name: \"test3\",\n      val: 102\n    });\n\n    const coll2 = ddb.addCollection<AB>(\"another\");\n    coll2.insert({\n      a: 1,\n      b: 2\n    });\n\n    for (idx = 0; idx < methods.length; idx++) {\n      switch (methods[idx]) {\n        case \"D\":\n          options = { partitioned: false, delimited: true };\n          break;\n        case \"DA\":\n          options = { partitioned: true, delimited: true };\n          break;\n        case \"NDA\":\n          options = { partitioned: false, delimited: false };\n          break;\n        case \"NDAA\":\n          options = { partitioned: true, delimited: false };\n          break;\n        default:\n          options = {};\n          break;\n      }\n\n      // do custom destructuring\n      result = ddb.serializeDestructured(options);\n\n      // reinflate from custom destructuring\n      cddb = new Loki(\"test.db\");\n      const reinflatedDatabase = cddb.deserializeDestructured(result, options);\n      cddb.loadJSONObject(reinflatedDatabase);\n\n      // assert expectations on reinflated database\n      expect(cddb[\"_collections\"].length).toEqual(2);\n      expect(cddb[\"_collections\"][0]._data.length).toEqual(3);\n      expect(cddb[\"_collections\"][0]._data[0][\"val\"]).toEqual(ddb[\"_collections\"][0]._data[0][\"val\"]);\n      expect(cddb[\"_collections\"][0]._data[0].$loki).toEqual(ddb[\"_collections\"][0]._data[0].$loki);\n      expect(cddb[\"_collections\"][0]._data[2].$loki).toEqual(ddb[\"_collections\"][0]._data[2].$loki);\n      expect(cddb[\"_collections\"][1].count()).toEqual(1);\n      expect(cddb[\"_collections\"][1]._data[0][\"a\"]).toEqual(ddb[\"_collections\"][1]._data[0][\"a\"]);\n    }\n  });\n\n  it(\"verify individual partitioning works correctly\", () => {\n    let result;\n    let cddb;\n    const ddb = new Loki(\"test.db\");\n    const coll = ddb.addCollection<Test>(\"testcoll\");\n    coll.insert({\n      name: \"test1\",\n      val: 100\n    });\n    coll.insert({\n      name: \"test2\",\n      val: 101\n    });\n    coll.insert({\n      name: \"test3\",\n      val: 102\n    });\n\n    const coll2 = ddb.addCollection<AB>(\"another\");\n    coll2.insert({\n      a: 1,\n      b: 2\n    });\n\n    // Verify db alone works correctly using NDAA format\n    result = ddb.serializeDestructured({\n      partitioned: true,\n      delimited: false,\n      partition: -1 // indicates to get serialized db container only\n    });\n\n    cddb = new Loki(\"test\");\n    cddb.loadJSON(result);\n\n    expect(cddb[\"_collections\"].length).toEqual(2);\n    expect(cddb[\"_collections\"][0].count()).toEqual(0);\n    expect(cddb[\"_collections\"][1].count()).toEqual(0);\n    expect(cddb[\"_collections\"][0].name).toEqual(ddb[\"_collections\"][0][\"name\"]);\n    expect(cddb[\"_collections\"][1].name).toEqual(ddb[\"_collections\"][1][\"name\"]);\n\n    // Verify collection alone works correctly using NDAA format\n    result = ddb.serializeDestructured({\n      partitioned: true,\n      delimited: false,\n      partition: 0 // collection [0] only\n    });\n\n    // we dont need to test all components of reassembling whole database\n    // so we will just call helper function to deserialize just collection data\n    let data = ddb.deserializeCollection<Test>(result, { partitioned: true, delimited: false });\n\n    expect(data.length).toEqual(ddb[\"_collections\"][0].count());\n    expect(data[0][\"val\"]).toEqual(ddb[\"_collections\"][0]._data[0][\"val\"]);\n    expect(data[1][\"val\"]).toEqual(ddb[\"_collections\"][0]._data[1][\"val\"]);\n    expect(data[2][\"val\"]).toEqual(ddb[\"_collections\"][0]._data[2][\"val\"]);\n    expect(data[0].$loki).toEqual(ddb[\"_collections\"][0]._data[0].$loki);\n    expect(data[1].$loki).toEqual(ddb[\"_collections\"][0]._data[1].$loki);\n    expect(data[2].$loki).toEqual(ddb[\"_collections\"][0]._data[2].$loki);\n\n    // Verify collection alone works correctly using DA format (the other partitioned format)\n    result = ddb.serializeDestructured({\n      partitioned: true,\n      delimited: true,\n      partition: 0 // collection [0] only\n    });\n\n    // now reinflate from that interim DA format\n    data = ddb.deserializeCollection<Test>(result, { partitioned: true, delimited: true });\n\n    expect(data.length).toEqual(ddb[\"_collections\"][0].count());\n    expect(data[0][\"val\"]).toEqual(ddb[\"_collections\"][0]._data[0][\"val\"]);\n    expect(data[1][\"val\"]).toEqual(ddb[\"_collections\"][0]._data[1][\"val\"]);\n    expect(data[2][\"val\"]).toEqual(ddb[\"_collections\"][0]._data[2][\"val\"]);\n    expect(data[0].$loki).toEqual(ddb[\"_collections\"][0]._data[0].$loki);\n    expect(data[1].$loki).toEqual(ddb[\"_collections\"][0]._data[1].$loki);\n    expect(data[2].$loki).toEqual(ddb[\"_collections\"][0]._data[2].$loki);\n  });\n\n});\n\ndescribe(\"testing adapter functionality\", () => {\n  it(\"verify basic memory storage functionality works\", (done) => {\n    const memAdapter = new MemoryStorage();\n    const ddb = new Loki(\"test.db\");\n\n    ddb.initializePersistence({ adapter: memAdapter });\n\n    const coll = ddb.addCollection<Test>(\"testcoll\");\n    coll.insert({\n      name: \"test1\",\n      val: 100\n    });\n    coll.insert({\n      name: \"test2\",\n      val: 101\n    });\n    coll.insert({\n      name: \"test3\",\n      val: 102\n    });\n\n    const coll2 = ddb.addCollection<AB>(\"another\");\n    coll2.insert({\n      a: 1,\n      b: 2\n    });\n    let dv = coll2.addDynamicView(\"test\");\n    dv.applyFind({ \"a\": 1 });\n    dv.data();\n\n    const p1 = ddb.saveDatabase().then(() => {\n      expect(memAdapter.hashStore.hasOwnProperty(\"test.db\")).toEqual(true);\n      expect(memAdapter.hashStore[\"test.db\"].savecount).toEqual(1);\n    });\n\n    const cdb = new Loki(\"test.db\");\n    cdb.initializePersistence({ adapter: memAdapter });\n\n    const p2 = cdb.loadDatabase().then(() => {\n      expect(cdb[\"_collections\"].length).toEqual(2);\n      expect(cdb.getCollection<Test>(\"testcoll\").findOne({ name: \"test2\" })[\"val\"]).toEqual(101);\n      expect(cdb[\"_collections\"][0].count()).toEqual(3);\n      expect(cdb[\"_collections\"][1].count()).toEqual(1);\n      expect(cdb.getCollection<AB>(\"another\").getDynamicView(\"test\").data()).toEqual(coll2.find({ \"a\": 1 }));\n    });\n\n    Promise.all([p1, p2]).then(done, done.fail);\n  });\n\n  it(\"verify loki deleteDatabase works\", (done) => {\n    const memAdapter = new MemoryStorage();\n    const ddb = new Loki(\"test.db\");\n    ddb.initializePersistence({ adapter: memAdapter });\n\n    const coll = ddb.addCollection<Test>(\"testcoll\");\n    coll.insert({\n      name: \"test1\",\n      val: 100\n    });\n    coll.insert({\n      name: \"test2\",\n      val: 101\n    });\n    coll.insert({\n      name: \"test3\",\n      val: 102\n    });\n\n    ddb.saveDatabase().then(() => {\n      expect(memAdapter.hashStore.hasOwnProperty(\"test.db\")).toEqual(true);\n      expect(memAdapter.hashStore[\"test.db\"].savecount).toEqual(1);\n\n      return ddb.deleteDatabase();\n    }).then(() => {\n      expect(memAdapter.hashStore.hasOwnProperty(\"test.db\")).toEqual(false);\n    }).then(done, done.fail);\n  });\n\n  it(\"verify reference adapters get db reference which is copy and serializable-safe\", (done) => {\n    // Current loki functionality with regards to reference mode adapters:\n    // Since we don't use serializeReplacer on reference mode adapters, we make\n    // lightweight clone, cloning only db container and collection containers (object refs are same).\n\n    interface MN {\n      m: number;\n      n: number;\n    }\n\n    class MyFakeReferenceAdapter implements StorageAdapter {\n      mode = \"reference\";\n\n      loadDatabase(dbname: string) {\n        expect(typeof (dbname)).toEqual(\"string\");\n\n        const result = new Loki(\"new db\");\n        const n1 = result.addCollection<MN>(\"n1\");\n        const n2 = result.addCollection<MN>(\"n2\");\n        n1.insert({ m: 9, n: 8 });\n        n2.insert({ m: 7, n: 6 });\n\n        return Promise.resolve(result);\n      }\n\n      saveDatabase() {\n        return Promise.resolve();\n      }\n\n      deleteDatabase() {\n        return Promise.resolve();\n      }\n\n      exportDatabase(dbname: string, dbref: Loki) {\n        expect(typeof (dbname)).toEqual(\"string\");\n        expect(dbref.constructor.name).toEqual(\"Loki\");\n\n        expect(dbref[\"_persistenceAdapter\"]).toEqual(null);\n        expect(dbref[\"_collections\"].length).toEqual(2);\n        // these changes should not affect original database\n        dbref[\"filename\"] = \"somethingelse\";\n        dbref[\"_collections\"][0].name = \"see1\";\n        return Promise.resolve();\n      }\n    }\n\n    const adapter = new MyFakeReferenceAdapter();\n    const db = new Loki(\"rma test\");\n    let db2: Loki;\n    db.initializePersistence({ adapter: adapter });\n    const c1 = db.addCollection<AB>(\"c1\");\n    const c2 = db.addCollection<AB>(\"c2\");\n    c1.insert({ a: 1, b: 2 });\n    c2.insert({ a: 3, b: 4 });\n\n    db.saveDatabase().then(() => {\n      expect(db[\"persistenceAdapter\"]).not.toEqual(null);\n      expect(db[\"filename\"]).toEqual(\"rma test\");\n      expect(db[\"_collections\"][0].name).toEqual(\"c1\");\n      expect(db.getCollection<AB>(\"c1\").findOne({ a: 1 }).b).toEqual(2);\n\n      db2 = new Loki(\"other name\");\n      db2.initializePersistence({ adapter: adapter });\n\n      return db2.loadDatabase();\n    }).then(() => {\n      expect(db2[\"_collections\"].length).toEqual(2);\n      expect(db2[\"_collections\"][0].name).toEqual(\"n1\");\n      expect(db2[\"_collections\"][1].name).toEqual(\"n2\");\n      expect(db2.getCollection<MN>(\"n1\").findOne({ m: 9 }).n).toEqual(8);\n    }).then(done, done.fail);\n  });\n});\n\ndescribe(\"async adapter tests\", () => {\n  it(\"verify throttled async drain\", (done) => {\n    const mem = new MemoryStorage({ asyncResponses: true, asyncTimeout: 50 });\n    const db = new Loki(\"sandbox.db\");\n    db.initializePersistence({ adapter: mem, throttledSaves: true });\n\n    // Add a collection to the database\n    const items = db.addCollection<User>(\"items\");\n    items.insert({ name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\" });\n    items.insert({ name: \"gungnir\", owner: \"odin\", maker: \"elves\" });\n    const tyr = items.insert({ name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\" });\n    const drau = items.insert({ name: \"draupnir\", owner: \"odin\", maker: \"elves\" });\n\n    const another = db.addCollection<AB>(\"another\");\n    const ai = another.insert({ a: 1, b: 2 });\n\n    // this should immediately kick off the first save\n    db.saveDatabase();\n\n    // the following saves (all async) should coalesce into one save\n    ai.b = 3;\n    another.update(ai);\n    db.saveDatabase();\n\n    tyr.owner = \"arngrim\";\n    items.update(tyr);\n    db.saveDatabase();\n\n    drau.maker = \"dwarves\";\n    items.update(drau);\n    db.saveDatabase();\n\n    db.throttledSaveDrain().then(() => {\n      // Wait until saves are complete and then loading the database and make\n      // sure all saves are complete and includes their changes\n      const db2 = new Loki(\"sandbox.db\");\n      db2.initializePersistence({ adapter: mem });\n\n      db2.loadDatabase().then(() => {\n        // total of 2 saves should have occurred\n        expect(mem.hashStore[\"sandbox.db\"].savecount).toEqual(2);\n\n        // verify the saved database contains all expected changes\n        expect(db2.getCollection<AB>(\"another\").findOne({ a: 1 }).b).toEqual(3);\n        expect(db2.getCollection<User>(\"items\").findOne({ name: \"tyrfing\" }).owner).toEqual(\"arngrim\");\n        expect(db2.getCollection<User>(\"items\").findOne({ name: \"draupnir\" }).maker).toEqual(\"dwarves\");\n        done();\n      });\n    });\n  });\n\n  it(\"verify throttledSaveDrain with duration timeout works\", (done) => {\n    const mem = new MemoryStorage({ asyncResponses: true, asyncTimeout: 200 });\n    const db = new Loki(\"sandbox.db\");\n    db.initializePersistence({ adapter: mem });\n\n    // Add a collection to the database\n    const items = db.addCollection<User>(\"items\");\n    items.insert({ name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\" });\n    items.insert({ name: \"gungnir\", owner: \"odin\", maker: \"elves\" });\n    const tyr = items.insert({ name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\" });\n    const drau = items.insert({ name: \"draupnir\", owner: \"odin\", maker: \"elves\" });\n\n    const another = db.addCollection<AB>(\"another\");\n    const ai = another.insert({ a: 1, b: 2 });\n\n    // this should immediately kick off the first save (~200ms)\n    db.saveDatabase();\n    // now queue up a sequence to be run one after the other, at ~50ms each (~300ms total) when first completes\n    ai.b = 3;\n    another.update(ai);\n\n    db.saveDatabase().then(() => {\n      tyr.owner = \"arngrim\";\n      items.update(tyr);\n\n      return db.saveDatabase();\n    }).then(() => {\n      drau.maker = \"dwarves\";\n      items.update(drau);\n\n      return db.saveDatabase();\n    });\n\n    expect(db[\"_throttledSaveRunning\"]).not.toEqual(null);\n    expect(db[\"_throttledSavePending\"]).not.toEqual(null);\n\n    // we want this to fail so above they should be bootstrapping several\n    // saves which take about 400ms to complete.\n    // The full drain can take one save/callback cycle longer than duration (~200ms).\n    db.throttledSaveDrain({ recursiveWaitLimit: true, recursiveWaitLimitDuration: 200 })\n      .then(() => {\n        expect(true).toEqual(false);\n        done();\n      }, () => {\n        expect(true).toEqual(true);\n        done();\n      });\n  });\n\n  it(\"verify throttled async throttles\", (done) => {\n    const mem = new MemoryStorage({ asyncResponses: true, asyncTimeout: 50 });\n    const db = new Loki(\"sandbox.db\");\n    db.initializePersistence({ adapter: mem });\n\n    // Add a collection to the database\n    const items = db.addCollection<User>(\"items\");\n    items.insert({ name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\" });\n    items.insert({ name: \"gungnir\", owner: \"odin\", maker: \"elves\" });\n    const tyr = items.insert({ name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\" });\n    const drau = items.insert({ name: \"draupnir\", owner: \"odin\", maker: \"elves\" });\n\n    const another = db.addCollection<AB>(\"another\");\n    const ai = another.insert({ a: 1, b: 2 });\n\n    // this should immediately kick off the first save\n    db.saveDatabase();\n\n    // the following saves (all async) should coalesce into one save\n    ai.b = 3;\n    another.update(ai);\n    db.saveDatabase();\n\n    tyr.owner = \"arngrim\";\n    items.update(tyr);\n    db.saveDatabase();\n\n    drau.maker = \"dwarves\";\n    items.update(drau);\n    db.saveDatabase();\n\n    // give all async saves time to complete and then verify outcome\n    setTimeout(() => {\n      // total of 2 saves should have occurred\n      expect(mem.hashStore[\"sandbox.db\"].savecount).toEqual(2);\n\n      // verify the saved database contains all expected changes\n      const db2 = new Loki(\"sandbox.db\");\n      db2.initializePersistence({ adapter: mem });\n      db2.loadDatabase().then(() => {\n        expect(db2.getCollection<AB>(\"another\").findOne({ a: 1 }).b).toEqual(3);\n        expect(db2.getCollection<User>(\"items\").findOne({ name: \"tyrfing\" }).owner).toEqual(\"arngrim\");\n        expect(db2.getCollection<User>(\"items\").findOne({ name: \"draupnir\" }).maker).toEqual(\"dwarves\");\n        done();\n      });\n    }, 200);\n  });\n\n  it(\"verify there is no race condition with dirty-checking\", (done) => {\n    const mem = new MemoryStorage({ asyncResponses: true, asyncTimeout: 50 });\n    const db = new Loki(\"sandbox.db\");\n\n    db.initializePersistence({ adapter: mem });\n\n    const items = db.addCollection<User & { foo?: string }>(\"items\");\n    items.insert({ name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\" });\n    const gungnir = items.insert({ name: \"gungnir\", owner: \"odin\", maker: \"elves\" });\n\n    expect(db[\"_autosaveDirty\"]()).toBe(true);\n\n    db.saveDatabase().then(() => {\n      // since an update happened after calling saveDatabase (but before save was commited), db should still be dirty\n      expect(db[\"_autosaveDirty\"]()).toBe(true);\n      done();\n    });\n\n    // this happens immediately after saveDatabase is called\n    gungnir.foo = \"bar\";\n    items.update(gungnir);\n  });\n\n  it(\"verify loadDatabase in the middle of throttled saves will wait for  queue to drain first\", (done) => {\n    const mem = new MemoryStorage({ asyncResponses: true, asyncTimeout: 75 });\n    const db = new Loki(\"sandbox.db\");\n    db.initializePersistence({ adapter: mem });\n\n    // Add a collection to the database\n    const items = db.addCollection<User>(\"items\");\n    items.insert({ name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\" });\n    items.insert({ name: \"gungnir\", owner: \"odin\", maker: \"elves\" });\n    const tyr = items.insert({ name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\" });\n    const drau = items.insert({ name: \"draupnir\", owner: \"odin\", maker: \"elves\" });\n\n    const another = db.addCollection<AB>(\"another\");\n    const ai = another.insert({ a: 1, b: 2 });\n\n    // this should immediately kick off the first save (~100ms)\n    db.saveDatabase();\n\n    // now queue up a sequence to be run one after the other, at ~50ms each (~300ms total) when first completes\n    ai.b = 3;\n    another.update(ai);\n    db.saveDatabase().then(() => {\n      tyr.owner = \"arngrim\";\n      items.update(tyr);\n\n      db.saveDatabase().then(() => {\n        drau.maker = \"dwarves\";\n        items.update(drau);\n\n        db.saveDatabase();\n      });\n    });\n\n    expect(db[\"_throttledSaveRunning\"]).not.toEqual(null);\n    expect(db[\"_throttledSavePending\"]).not.toEqual(null);\n\n    // at this point, several rounds of saves should be triggered...\n    // a load at this scope (possibly simulating script run from different code path)\n    // should wait until any pending saves are complete, then freeze saves (queue them ) while loading,\n    // then re-enable saves\n    db.loadDatabase().then(() => {\n\n      expect(db.getCollection<AB>(\"another\").findOne({ a: 1 }).b).toEqual(3);\n      expect(db.getCollection<User>(\"items\").findOne({ name: \"tyrfing\" }).owner).toEqual(\"arngrim\");\n      expect(db.getCollection<User>(\"items\").findOne({ name: \"draupnir\" }).maker).toEqual(\"dwarves\");\n    });\n\n    setTimeout(() => {\n      done();\n    }, 600);\n  });\n});\n\ndescribe(\"autosave/autoload\", () => {\n  it(\"verify autosave works\", (done) => {\n    class DummyStorage implements StorageAdapter {\n\n      public counter = 0;\n\n      loadDatabase(_0: string): Promise<any> {\n        return undefined;\n      }\n\n      saveDatabase(_0: string, _1: string): Promise<void> {\n        this.counter++;\n        return Promise.resolve();\n      }\n    }\n\n    const dummyStorage = new DummyStorage();\n    const db = new Loki(\"sandbox.db\");\n    const items = db.addCollection<User>(\"items\");\n\n    db.initializePersistence({ adapter: dummyStorage, autosave: true, autosaveInterval: 1 })\n      .then(() => {\n        items.insert({ name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\" });\n        expect(dummyStorage.counter).toEqual(0);\n        return new Promise(resolve => setTimeout(resolve, 2));\n      })\n      .then(() => {\n        items.insert({ name: \"gungnir\", owner: \"odin\", maker: \"elves\" });\n        expect(dummyStorage.counter).toEqual(1);\n        return new Promise(resolve => setTimeout(resolve, 2));\n      })\n      .then(() => {\n        items.insert({ name: \"gungnir\", owner: \"odin\", maker: \"elves\" });\n        expect(dummyStorage.counter).toEqual(2);\n        return db.close();\n      })\n      .then(() => {\n        expect(dummyStorage.counter).toEqual(3);\n      })\n      .then(done)\n      .catch(done.fail);\n  });\n\n  it(\"verify autosave with autoload works\", (done) => {\n    const mem = new MemoryStorage({ asyncResponses: true, asyncTimeout: 1 });\n    const db = new Loki(\"sandbox.db\");\n    const db2 = new Loki(\"sandbox.db\");\n    const items = db.addCollection<User>(\"items\");\n\n    db.initializePersistence({ adapter: mem, autosave: true, autosaveInterval: 1 })\n      .then(() => {\n        items.insert({ name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\" });\n        return new Promise(resolve => setTimeout(resolve, 2));\n      })\n      .then(() => {\n        return db2.initializePersistence({ adapter: mem, autoload: true });\n      })\n      .then(() => {\n        expect(db2.getCollection(\"items\")).toBeDefined();\n        return db.close();\n      })\n      .then(done)\n      .catch(done.fail);\n  });\n});\n\ndescribe(\"testing changesAPI\", () => {\n  it(\"verify pending changes persist across save/load cycle\", (done) => {\n    const mem = new MemoryStorage();\n    const db = new Loki(\"sandbox.db\");\n    let db2: Loki;\n    db.initializePersistence({ adapter: mem });\n\n    // Add a collection to the database\n    const items = db.addCollection<User>(\"items\", { disableChangesApi: false });\n\n    // Add some documents to the collection\n    items.insert({ name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\" });\n    items.insert({ name: \"gungnir\", owner: \"odin\", maker: \"elves\" });\n    items.insert({ name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\" });\n    items.insert({ name: \"draupnir\", owner: \"odin\", maker: \"elves\" });\n\n    // Find and update an existing document\n    const tyrfing = items.findOne({ \"name\": \"tyrfing\" });\n    tyrfing.owner = \"arngrim\";\n    items.update(tyrfing);\n\n    // memory storage is synchronous so i will not bother with callbacks\n    db.saveDatabase().then(() => {\n      db2 = new Loki(\"sandbox.db\");\n      db2.initializePersistence({ adapter: mem });\n\n      return db2.loadDatabase();\n    }).then(() => {\n      const result = JSON.parse(db2.serializeChanges());\n      expect(result.length).toEqual(5);\n\n      expect(result[0].name).toEqual(\"items\");\n      expect(result[0].operation).toEqual(\"I\");\n      expect(result[0].obj.name).toEqual(\"mjolnir\");\n\n      expect(result[4].name).toEqual(\"items\");\n      expect(result[4].operation).toEqual(\"U\");\n      expect(result[4].obj.name).toEqual(\"tyrfing\");\n    }).then(done, done.fail);\n  });\n});\n"
  },
  {
    "path": "packages/loki/spec/generic/remove.spec.ts",
    "content": "/* global describe, it, expect */\nimport { Loki } from \"../../src/loki\";\nimport { Doc } from \"../../../common/types\";\n\ninterface User {\n  name: string;\n  age: number;\n}\n\ndescribe(\"remove\", () => {\n  it(\"removes\", () => {\n    const db = new Loki();\n    const users = db.addCollection<User>(\"users\");\n\n    users.insert({\n      name: \"joe\",\n      age: 39\n    });\n    users.insert({\n      name: \"jack\",\n      age: 20\n    });\n    users.insert({\n      name: \"jim\",\n      age: 40\n    });\n    users.insert({\n      name: \"dave\",\n      age: 33\n    });\n    users.insert({\n      name: \"jim\",\n      age: 29\n    });\n    users.insert({\n      name: \"dave\",\n      age: 21\n    });\n\n    const dv = users.addDynamicView(\"testview\");\n    dv.applyWhere((obj: User) => obj.name.length > 3);\n\n    users.removeWhere((obj: User) => obj.age > 35);\n    expect(users.count()).toEqual(4);\n    users.findAndRemove({\n      \"age\": {\n        $gt: 25\n      }\n    });\n    expect(users.count()).toEqual(2);\n    users.remove(6);\n    expect(users.count()).toEqual(1);\n    users.removeDataOnly();\n    expect(users.count()).toEqual(0);\n    expect(!!users.getDynamicView(\"testview\")).toEqual(true);\n\n\n    const foo = {\n      name: \"foo\",\n      age: 42\n    };\n    users.insert(foo);\n    expect(users.count()).toEqual(1);\n    users.remove(foo as Doc<User>);\n    expect(users.count()).toEqual(0);\n    // test that $loki and meta properties have been removed correctly to allow object re-insertion\n    expect(foo[\"$loki\"]).toEqual(undefined);\n    expect(foo[\"meta\"]).toEqual(undefined);\n    users.insert(foo);\n    expect(users.count()).toEqual(1);\n  });\n\n  it(\"removes with unique index\", () => {\n    const db = new Loki();\n    const users1 = db.addCollection<User & {username: string}>(\"userswithunique\", {\n      unique: [\"username\"]\n    });\n\n    users1.insert({\n      username: \"joe\",\n      name: \"joe\",\n      age: 39\n    });\n    users1.insert({\n      username: \"jack\",\n      name: \"jack\",\n      age: 20\n    });\n    expect(users1.count()).toEqual(2);\n    users1.removeDataOnly();\n    expect(users1.count()).toEqual(0);\n  });\n});\n"
  },
  {
    "path": "packages/loki/spec/generic/sortingIndexing.spec.ts",
    "content": "/* global describe, beforeEach, it, expect */\nimport { Loki } from \"../../src/loki\";\n\ndescribe(\"sorting and indexing\", () => {\n  let db: Loki;\n  beforeEach(() => {\n    db = new Loki(\"sortingIndexingTest\");\n  });\n\n  it(\"ResultSet simplesort\", () => {\n    interface Sortable {\n      a: number;\n      b: number;\n    }\n\n    const rss = db.addCollection<Sortable>(\"rssort\");\n\n    rss.insert({ a: 4, b: 2 });\n    rss.insert({ a: 7, b: 1 });\n    rss.insert({ a: 3, b: 4 });\n    rss.insert({ a: 9, b: 5 });\n\n    const results = rss.chain().simplesort(\"a\").data();\n    expect(results[0].a).toBe(3);\n    expect(results[1].a).toBe(4);\n    expect(results[2].a).toBe(7);\n    expect(results[3].a).toBe(9);\n  });\n\n  it(\"ResultSet simplesort descending\", () => {\n    interface Sortable {\n      a: number;\n      b: number;\n    }\n\n    const rss = db.addCollection<Sortable>(\"rssort\");\n\n    rss.insert({ a: 4, b: 2 });\n    rss.insert({ a: 7, b: 1 });\n    rss.insert({ a: 3, b: 4 });\n    rss.insert({ a: 9, b: 5 });\n\n    let results = rss.chain().simplesort(\"a\", true).data();\n    expect(results[0].a).toBe(9);\n    expect(results[1].a).toBe(7);\n    expect(results[2].a).toBe(4);\n    expect(results[3].a).toBe(3);\n\n    // test when indexed\n    const rss2 = db.addCollection<Sortable>(\"rssort2\", { rangedIndexes: { \"a\": {} } });\n\n    rss2.insert({ a: 4, b: 2 });\n    rss2.insert({ a: 7, b: 1 });\n    rss2.insert({ a: 3, b: 4 });\n    rss2.insert({ a: 9, b: 5 });\n\n    results = rss2.chain().simplesort(\"a\", true).data();\n    expect(results[0].a).toBe(9);\n    expect(results[1].a).toBe(7);\n    expect(results[2].a).toBe(4);\n    expect(results[3].a).toBe(3);\n  });\n\n  it(\"ResultSet simplesort on nested properties\", () => {\n    interface Sortable {\n      foo: {\n        a: number;\n        b: number;\n      };\n    }\n\n    const rss = db.addCollection<Sortable, { \"foo.a\": number }>(\"rssort\",\n      {\n        nestedProperties: [\"foo.a\"]\n      });\n\n    rss.insert({ foo: { a: 4, b: 2 } });\n    rss.insert({ foo: { a: 7, b: 1 } });\n    rss.insert({ foo: { a: 3, b: 4 } });\n    rss.insert({ foo: { a: 9, b: 5 } });\n\n    const results = rss.chain().simplesort(\"foo.a\").data();\n    expect(results[0].foo.a).toBe(3);\n    expect(results[1].foo.a).toBe(4);\n    expect(results[2].foo.a).toBe(7);\n    expect(results[3].foo.a).toBe(9);\n  });\n\n  it(\"ResultSet simplesort with dates\", () => {\n    const now = new Date().getTime();\n    const dt1 = new Date(now - 1000);\n    const dt2 = new Date(now + 5000);\n    const dt3 = new Date(2000, 6, 1);\n    const dt4 = new Date(now + 2000);\n    const dt5 = new Date(now - 3000);\n\n    interface Sortable {\n      a: number;\n      b: Date;\n    }\n\n    const rss = db.addCollection<Sortable>(\"rssort\");\n\n    rss.insert({ a: 1, b: dt1 });\n    rss.insert({ a: 2, b: dt2 });\n    rss.insert({ a: 3, b: dt3 });\n    rss.insert({ a: 4, b: dt4 });\n    rss.insert({ a: 5, b: dt5 });\n\n    const results = rss.chain().simplesort(\"b\").data();\n    expect(results[0].a).toBe(3);\n    expect(results[1].a).toBe(5);\n    expect(results[2].a).toBe(1);\n    expect(results[3].a).toBe(4);\n    expect(results[4].a).toBe(2);\n  });\n\n  it(\"ResultSet sort works correctly\", () => {\n    interface Sortable {\n      a: number;\n      b: number;\n      c: string;\n    }\n\n    const db = new Loki(\"test.db\");\n    const coll = db.addCollection<Sortable>(\"coll\");\n\n    coll.insert([\n      { a: 1, b: 9, c: \"first\" },\n      { a: 5, b: 7, c: \"second\" },\n      { a: 2, b: 9, c: \"third\" }\n    ]);\n\n    const sortfun = (obj1: Sortable, obj2: Sortable) => {\n      if (obj1.a === obj2.a) return 0;\n      if (obj1.a > obj2.a) return 1;\n      return -1;\n    };\n\n    const result = coll.chain().sort(sortfun).data();\n    expect(result.length).toEqual(3);\n    expect(result[0].a).toEqual(1);\n    expect(result[1].a).toEqual(2);\n    expect(result[2].a).toEqual(5);\n  });\n\n  it(\"ResultSet compoundsort works correctly\", () => {\n    const db = new Loki(\"test.db\");\n\n    interface ABC {\n      a: number;\n      b: number;\n      c: string;\n    }\n\n    const coll = db.addCollection<ABC>(\"coll\");\n\n    coll.insert([\n      { a: 1, b: 9, c: \"first\" },\n      { a: 5, b: 7, c: \"second\" },\n      { a: 2, b: 9, c: \"third\" }\n    ]);\n\n    let result = coll.chain().compoundsort([\"b\", \"c\"]).data();\n    expect(result.length).toEqual(3);\n    expect(result[0].a).toEqual(5);\n    expect(result[1].a).toEqual(1);\n    expect(result[2].a).toEqual(2);\n\n    result = coll.chain().compoundsort([\"b\", [\"c\", true]]).data();\n    expect(result.length).toEqual(3);\n    expect(result[0].a).toEqual(5);\n    expect(result[1].a).toEqual(2);\n    expect(result[2].a).toEqual(1);\n  });\n\n  it(\"ResultSet compoundsort on nested properties works correctly\", () => {\n    const db = new Loki(\"test.db\");\n\n    interface AZYBC {\n      a: number;\n      z: {\n        y: {\n          b: number;\n          c: string;\n        };\n      };\n    }\n\n    const coll = db.addCollection<AZYBC, { \"z.y.b\": number, \"z.y.c\": number }>(\"coll\",\n      {\n        nestedProperties: [\"z.y.b\", \"z.y.c\"]\n      });\n\n    coll.insert([\n      { a: 1, z: { y: { b: 9, c: \"first\" } } },\n      { a: 5, z: { y: { b: 7, c: \"second\" } } },\n      {\n        a: 2, z: { y: { b: 9, c: \"third\" } }\n      }]);\n\n    let result = coll.chain().compoundsort([\"z.y.b\", \"z.y.c\"]).data();\n    expect(result.length).toEqual(3);\n    expect(result[0].a).toEqual(5);\n    expect(result[1].a).toEqual(1);\n    expect(result[2].a).toEqual(2);\n\n    result = coll.chain().compoundsort([\"z.y.b\", [\"z.y.c\", true]]).data();\n    expect(result.length).toEqual(3);\n    expect(result[0].a).toEqual(5);\n    expect(result[1].a).toEqual(2);\n    expect(result[2].a).toEqual(1);\n  });\n\n  describe(\"collection indexing\", () => {\n    it(\"mixed types sort as expected\", () => {\n\n      interface AB {\n        a?: any;\n        b?: any;\n      }\n\n      const coll = db.addCollection<AB>(\"coll\", { unindexedSortComparator: \"loki\"});\n      coll.insert({ a: undefined, b: 5 });\n      coll.insert({ b: 5 });\n      coll.insert({ a: null, b: 5 });\n      coll.insert({ a: 7, b: 5 });\n      coll.insert({ a: \"7\", b: 5 });\n      coll.insert({ a: 7.0, b: 5 });\n      coll.insert({ a: \"11\", b: 5 });\n      coll.insert({ a: \"4\", b: 5 });\n      coll.insert({ a: new Date(), b: 5 });\n      coll.insert({ a: { ack: \"object\" }, b: 5 });\n      coll.insert({ a: 7.5, b: 5 });\n      coll.insert({ a: NaN, b: 5 });\n      coll.insert({ a: [8, 1, 15], b: 5 });\n      coll.insert({ a: \"asdf\", b: 5 });\n\n      let indexVals: any[] = [];\n\n      // make sure unindexed sort is as expected\n      let result = coll.chain().simplesort(\"a\").data();\n      result.forEach((obj) => {\n        indexVals.push(obj.a);\n      });\n\n      expect(indexVals.length).toEqual(14);\n\n      // undefined, null, or NaN\n      expect(indexVals[0] !== indexVals[0]).toEqual(true);\n      expect(indexVals[1] == null).toEqual(true);\n      expect(indexVals[2] == null).toEqual(true);\n      expect(indexVals[3] == null).toEqual(true);\n\n      expect(indexVals[4] === \"4\").toEqual(true);\n      expect(indexVals[5] === \"7\" || indexVals[5] === 7).toEqual(true);\n      expect(indexVals[6] === \"7\" || indexVals[5] === 7).toEqual(true);\n      expect(indexVals[7] === \"7\" || indexVals[5] === 7).toEqual(true);\n      expect(indexVals[8] === 7.5).toEqual(true);\n      expect(indexVals[9] === \"11\").toEqual(true);\n      expect(indexVals[10] instanceof Date).toEqual(true);\n      expect(Array.isArray(indexVals[11])).toEqual(true);\n      expect(typeof indexVals[12] === \"object\").toEqual(true);\n      expect(indexVals[13] === \"asdf\").toEqual(true);\n\n      // now make sure avl index uses same range\n      coll.ensureIndex(\"a\");\n\n      indexVals = [];\n      result = coll.chain().simplesort(\"a\").data();\n      result.forEach((obj) => {\n        indexVals.push(obj.a);\n      });\n\n      expect(indexVals.length).toEqual(14);\n\n      // undefined, null, or NaN\n      expect(indexVals[0] !== indexVals[0]).toEqual(true);\n      expect(indexVals[1] == null).toEqual(true);\n      expect(indexVals[2] == null).toEqual(true);\n      expect(indexVals[3] == null).toEqual(true);\n\n      expect(indexVals[4] === \"4\").toEqual(true);\n      expect(indexVals[5] === \"7\" || indexVals[5] === 7).toEqual(true);\n      expect(indexVals[6] === \"7\" || indexVals[5] === 7).toEqual(true);\n      expect(indexVals[7] === \"7\" || indexVals[5] === 7).toEqual(true);\n      expect(indexVals[8] === 7.5).toEqual(true);\n      expect(indexVals[9] === \"11\").toEqual(true);\n      expect(indexVals[10] instanceof Date).toEqual(true);\n      expect(Array.isArray(indexVals[11])).toEqual(true);\n      expect(typeof indexVals[12] === \"object\").toEqual(true);\n      expect(indexVals[13] === \"asdf\").toEqual(true);\n    });\n\n    it(\"date sort as expected\", () => {\n      const now = new Date().getTime();\n      const dt1 = new Date(now - 1000);\n      const dt2 = new Date(now + 5000);\n      const dt3 = new Date(2000, 6, 1);\n      const dt4 = new Date(now + 2000);\n      const dt5 = new Date(now - 3000);\n\n      interface Sortable {\n        a: number;\n        b: Date;\n      }\n\n      const cidx = db.addCollection<Sortable>(\"collidx\");\n\n      cidx.insert({ a: 1, b: dt1 });\n      cidx.insert({ a: 2, b: dt2 });\n      cidx.insert({ a: 3, b: dt3 });\n      cidx.insert({ a: 4, b: dt4 });\n      cidx.insert({ a: 5, b: dt5 });\n\n      let sorted = cidx.chain().simplesort(\"b\").data();\n      expect(sorted.length).toEqual(5);\n      expect(sorted[0].a).toEqual(3);\n      expect(sorted[1].a).toEqual(5);\n      expect(sorted[2].a).toEqual(1);\n      expect(sorted[3].a).toEqual(4);\n      expect(sorted[4].a).toEqual(2);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/loki/spec/generic/stage.spec.ts",
    "content": "/* global describe, beforeEach, it, expect */\nimport { Loki } from \"../../src/loki\";\nimport { Collection } from \"../../src/collection\";\n\ninterface Director {\n  name: string;\n  directorId: number;\n}\n\ndescribe(\"Staging and commits\", () => {\n  let db: Loki;\n  let directors: Collection<Director>;\n\n  beforeEach(() => {\n    db = new Loki(\"testJoins\");\n    directors = db.addCollection<Director>(\"directors\");\n\n    directors.insert([{\n      name: \"Martin Scorsese\",\n      directorId: 1\n    }, {\n      name: \"Francis Ford Coppola\",\n      directorId: 2\n    }, {\n      name: \"Steven Spielberg\",\n      directorId: 3\n    }, {\n      name: \"Quentin Tarantino\",\n      directorId: 4\n    }]);\n  });\n\n  it(\"work\", () => {\n\n    const stageName = \"tentative directors\";\n    const newDirectorsName = \"Joel and Ethan Cohen\";\n    const message = \"Edited Cohen brothers name\";\n\n    const cohen = directors.insert({\n      name: \"Cohen Brothers\",\n      directorId: 5\n    });\n    const new_cohen = directors.stage(stageName, cohen);\n    new_cohen.name = newDirectorsName;\n    expect(cohen.name).toEqual(\"Cohen Brothers\");\n    directors.commitStage(stageName, message);\n    expect(directors.get(cohen.$loki).name).toEqual(\"Joel and Ethan Cohen\");\n    expect(directors[\"_commitLog\"][0].message).toEqual(message);\n  });\n});\n"
  },
  {
    "path": "packages/loki/spec/generic/stats.spec.ts",
    "content": "/* global describe, it, expect */\nimport { Loki } from \"../../src/loki\";\n\ndescribe(\"stats\", () => {\n  const db = new Loki();\n\n  interface User {\n    name: string;\n    age: number;\n    relatives: {\n      firstgrade: number;\n    };\n  }\n\n  const users = db.addCollection<User, { \"relatives.firstgrade\": number }>(\"users\", {\n    nestedProperties: [\"relatives.firstgrade\"]\n  });\n\n  users.insert({\n    name: \"joe\",\n    age: 35,\n    relatives: {\n      firstgrade: 15\n    }\n  });\n  users.insert({\n    name: \"jack\",\n    age: 20,\n    relatives: {\n      firstgrade: 20\n    }\n  });\n  users.insert({\n    name: \"jim\",\n    age: 40,\n    relatives: {\n      firstgrade: 32\n    }\n  });\n  users.insert({\n    name: \"dave\",\n    age: 15,\n    relatives: {\n      firstgrade: 20\n    }\n  });\n  users.insert({\n    name: \"jim\",\n    age: 28,\n    relatives: {\n      firstgrade: 15\n    }\n  });\n  users.insert({\n    name: \"dave\",\n    age: 12,\n    relatives: {\n      firstgrade: 12\n    }\n  });\n\n  it(\"max should be 32\", () => {\n\n    expect(users.max(\"relatives.firstgrade\")).toEqual(32);\n\n  });\n  it(\"max record should be 3, 32\", () => {\n    expect({\n      index: 3,\n      value: 32\n    }).toEqual(users.maxRecord(\"relatives.firstgrade\") as any);\n  });\n\n  it(\"min should be 12\", () => {\n    expect(users.min(\"age\")).toEqual(12);\n  });\n\n  it(\"min record to be 6, 12\", () => {\n    expect(users.minRecord(\"age\")).toEqual({\n      index: 6,\n      value: 12\n    } as any);\n  });\n\n  it(\"average to be 19\", () => {\n    expect(users.avg(\"relatives.firstgrade\")).toEqual(19);\n  });\n\n  it(\"median to be 17.5\", () => {\n    expect(users.median(\"relatives.firstgrade\")).toEqual(17.5);\n  });\n\n  it(\"ages should be [35, 20, 40, 15, 28, 12]\", () => {\n    expect(users.extract(\"age\")).toEqual([35, 20, 40, 15, 28, 12]);\n  });\n\n  it(\"Standard deviation on firstgrade relatives should be 6.48...\", () => {\n    expect(users.stdDev(\"relatives.firstgrade\")).toEqual(6.48074069840786);\n  });\n\n  it(\"stdDev should be 10.23...\", () => {\n    expect(users.stdDev(\"age\")).toEqual(10.23067283548187);\n  });\n\n});\n"
  },
  {
    "path": "packages/loki/spec/generic/test.spec.ts",
    "content": "/* global describe, beforeEach, it, expect */\nimport { Loki } from \"../../src/loki\";\nimport { Collection } from \"../../src/collection\";\n\ndescribe(\"loki\", () => {\n  let db: Loki;\n\n  interface User {\n    name: string;\n    age: number;\n    lang: string;\n  }\n\n  let users: Collection<User>;\n\n  beforeEach(() => {\n    db = new Loki(\"test.json\");\n    users = db.addCollection<User>(\"user\");\n\n    users.insert({\n      name: \"dave\",\n      age: 25,\n      lang: \"English\"\n    });\n\n    users.insert({\n      name: \"joe\",\n      age: 39,\n      lang: \"Italian\"\n    });\n\n    users.insert({\n      name: \"jonas\",\n      age: 30,\n      lang: \"Swedish\"\n    });\n  });\n\n\n  describe(\"core methods\", () => {\n    it(\"works\", () => {\n      const tdb = new Loki(\"regextests\");\n      const tcu = tdb.addCollection<User>(\"user\");\n      tcu.insert({\n        name: \"abcd\",\n        age: 25,\n        lang: \"English\"\n      });\n\n      tcu.insert({\n        name: \"AbCd\",\n        age: 39,\n        lang: \"Italian\"\n      });\n\n      tcu.insert({\n        name: \"acdb\",\n        age: 30,\n        lang: \"Swedish\"\n      });\n\n      tcu.insert({\n        name: \"aBcD\",\n        age: 30,\n        lang: \"Swedish\"\n      });\n\n\n      // findOne()\n      const j = users.findOne({\n        \"name\": \"jonas\"\n      });\n      expect(j.name).toEqual(\"jonas\");\n\n      // find()\n      const result = users.find({\n        \"age\": {\n          \"$gt\": 29\n        }\n      });\n      expect(result.length).toEqual(2);\n\n      // $regex test with raw regex\n      expect(users.find({\n        \"name\": {\n          \"$regex\": /o/\n        }\n      }).length).toEqual(2);\n\n      // case insensitive regex with array of [\"pattern\", \"options\"]\n      expect(tcu.find({\n        \"name\": {\n          \"$regex\": [\"abcd\", \"i\"]\n        }\n      }).length).toEqual(3);\n\n      // regex with single encoded string pattern (no options)\n      expect(tcu.find({\n        \"name\": {\n          \"$regex\": \"cd\"\n        }\n      }).length).toEqual(2);\n\n      // $contains\n      expect(users.find({\n        \"name\": {\n          \"$contains\": \"jo\"\n        }\n      }).length).toEqual(2);\n\n      // $contains using array element\n      expect(users.find({\n        \"name\": {\n          \"$contains\": [\"jo\"]\n        }\n      }).length).toEqual(2);\n\n\n      // $contains any with one value\n      expect(users.find({\n        \"name\": {\n          \"$containsAny\": \"nas\"\n        }\n      }).length).toEqual(1);\n\n      // $contains any with multiple values\n      expect(users.find({\n        \"name\": {\n          \"$containsAny\": [\"nas\", \"dave\"]\n        }\n      }).length).toEqual(2);\n\n\n      // insert() : try inserting existing document (should fail), try adding doc with legacy id column\n      const collectionLength = users.count();\n      const objDave = users.findOne({\n        \"name\": \"dave\"\n      });\n      let wasAdded = true;\n      try {\n        users.insert(objDave);\n      } catch (err) {\n        wasAdded = false;\n      }\n      expect(wasAdded).toEqual(false);\n      expect(collectionLength).toEqual(users.count());\n\n      // our collections are not strongly typed so lets invent some object that has its 'own' id column\n      let legacyObject = {\n        id: 999,\n        first: \"aaa\",\n        last: \"bbb\",\n        city: \"pasadena\",\n        state: \"ca\"\n      };\n\n      wasAdded = true;\n\n      try {\n        users.insert(legacyObject as any);\n      } catch (err) {\n        wasAdded = false;\n      }\n\n      expect(wasAdded).toEqual(true);\n\n      // remove object so later queries access valid properties on all objects\n      if (wasAdded) {\n        users.remove(legacyObject as any); // the object itself should have been modified\n      }\n\n      // update()\n      legacyObject = {\n        id: 998,\n        first: \"aaa\",\n        last: \"bbb\",\n        city: \"pasadena\",\n        state: \"ca\"\n      };\n      let wasUpdated = true;\n\n      try {\n        users.update(legacyObject as any);\n      } catch (err) {\n        wasUpdated = false;\n      }\n      expect(wasUpdated).toEqual(false);\n\n      // remove() - add some bogus object to remove\n      const userCount1 = users.count();\n\n      const testObject = {\n        first: \"aaa\",\n        last: \"bbb\",\n        city: \"pasadena\",\n        state: \"ca\"\n      };\n\n      users.insert(testObject as any);\n\n      expect(userCount1 + 1).toEqual(users.count());\n      users.remove(testObject as any);\n      expect(userCount1).toEqual(users.count());\n    });\n\n    it(\"meta not set on returned objects\", function () {\n      const tdb = new Loki(\"test.db\");\n      const coll = tdb.addCollection<{ a: number, b: number }>(\"tc\", { disableMeta: true });\n\n      // verify single insert return objs do not have meta set\n      const obj = coll.insert({ a: 1, b: 2 });\n      expect(obj.hasOwnProperty(\"meta\")).toEqual(false);\n      expect(obj.hasOwnProperty(\"$loki\")).toEqual(true);\n\n      // verify batch insert return objs do not have meta set\n      const objs = coll.insert([{ a: 2, b: 3 }, { a: 3, b: 4 }]);\n      expect(Array.isArray(objs));\n      objs.forEach((o) => {\n        expect(o.hasOwnProperty(\"meta\")).toEqual(false);\n        expect(o.hasOwnProperty(\"$loki\")).toEqual(true);\n      });\n    });\n  });\n\n  describe(\"dot notation\", () => {\n    it(\"works\", () => {\n\n      interface DNC {\n        first: string;\n        last: string;\n        addr?: {\n          street?: string;\n          state?: string;\n          zip?: number;\n        };\n      }\n\n      const dnc = db.addCollection<DNC, { \"addr.state\": string, \"addr.zip\": number }>(\"dncoll\",\n        {\n          nestedProperties: [\"addr.state\", \"addr.zip\"]\n        });\n\n      dnc.insert({\n        first: \"aaa\",\n        last: \"bbb\",\n        addr: {\n          street: \"111 anystreet\",\n          state: \"AS\",\n          zip: 12345\n        }\n      });\n\n      dnc.insert({\n        first: \"ddd\",\n        last: \"eee\",\n        addr: {\n          street: \"222 anystreet\",\n          state: \"FF\",\n          zip: 32345\n        }\n      });\n\n      // make sure it can handle case where top level property doesn't exist\n      dnc.insert({\n        first: \"mmm\",\n        last: \"nnn\"\n      });\n\n      // make sure it can handle case where subscan property doesn't exist\n      dnc.insert({\n        first: \"ooo\",\n        last: \"ppp\",\n        addr: {\n          state: \"YY\"\n        }\n      });\n\n      dnc.insert({\n        first: \"jjj\",\n        last: \"kkk\",\n        addr: {\n          street: \"777 anystreet\",\n          state: \"WW\",\n          zip: 12345\n        }\n      });\n\n      // test dot notation using regular find (with multiple results)\n      const firstResult = dnc.find({\n        \"addr.zip\": 12345\n      });\n      expect(firstResult.length).toEqual(2);\n      expect(firstResult[0].addr.zip).toEqual(12345);\n      expect(firstResult[1].addr.zip).toEqual(12345);\n\n      // test not notation using findOne\n      const secObj = dnc.findOne({\n        \"addr.state\": \"FF\"\n      });\n\n      expect(secObj !== null).toBeTruthy();\n      expect(secObj.addr.zip).toEqual(32345);\n\n    });\n\n    it(\"with transaction\", () => {\n      const dnc = db.addCollection<{ first: string, addr: { zip: number } }, { \"addr.zip\": number }>(\"dncoll\",\n        {\n          nestedProperties: [\"addr.zip\"],\n          transactional: true,\n          unique: [\"first\"]\n        });\n\n      const doc = dnc.insert({first: \"abc\", addr: {zip: 12345}});\n\n      expect(doc[\"addr.zip\"]).toBeDefined();\n\n      expect(() => dnc.insert({first: \"abc\", addr: {zip: 54321}})).toThrowError();\n\n      expect(dnc.find({\"first\": \"abc\"})[0][\"addr.zip\"]).toBeDefined();\n    });\n  });\n\n  // We only support dot notation involving array when\n  // the leaf property is the array.  This verifies that functionality\n  describe(\"dot notation across leaf object array\", () => {\n    it(\"works\", () => {\n\n      interface ABC {\n        id: number;\n        children: {\n          someProperty?: number\n        }[];\n      }\n\n      const dna = db.addCollection<ABC, { \"children.someProperty\": number[] }>(\"dnacoll\", {\n        nestedProperties: [\"children.someProperty\"]\n      });\n\n      dna.insert({\n        id: 1,\n        children: [{\n          someProperty: 11\n        }]\n      });\n\n      dna.insert({\n        id: 2,\n        children: [{\n          someProperty: 22\n        }]\n      });\n\n      dna.insert({\n        id: 3,\n        children: [{\n          someProperty: 33\n        }, {\n          someProperty: 22\n        }]\n      });\n\n      dna.insert({\n        id: 4,\n        children: [{\n          someProperty: 11\n        }]\n      });\n\n      dna.insert({\n        id: 5,\n        children: [{\n          // Missing\n        }]\n      });\n\n      dna.insert({\n        id: 6,\n        children: [{\n          someProperty: null\n        }]\n      });\n\n      let results = dna.find({ \"children.someProperty\": { \"$contains\": 33 } });\n      expect(results.length).toEqual(1);\n\n      results = dna.find({ \"children.someProperty\": { \"$contains\": 22 } });\n      expect(results.length).toEqual(2);\n\n      results = dna.find({ \"children.someProperty\": { \"$contains\": 11 } });\n      expect(results.length).toEqual(2);\n    });\n  });\n\n\n  describe(\"dot notation terminating at leaf array\", () => {\n    it(\"works\", () => {\n\n      interface ABC {\n        relations: {\n          ids: number[];\n        };\n      }\n\n      const dna = db.addCollection<ABC, { \"relations.ids\": number[] }>(\"dnacoll\",\n        {\n          nestedProperties: [\"relations.ids\"]\n        });\n\n      dna.insert({\n        \"relations\": {\n          \"ids\": [379]\n        }\n      });\n\n      dna.insert({\n        \"relations\": {\n          \"ids\": [12, 379]\n        }\n      });\n\n      dna.insert({\n        \"relations\": {\n          \"ids\": [111]\n        }\n      });\n\n      const results = dna.find({\n        \"relations.ids\": { $contains: 379 }\n      });\n\n      expect(results.length).toEqual(2);\n    });\n  });\n\n  describe(\"dot notation across child array\", () => {\n    it(\"works\", () => {\n\n      interface ABC {\n        id: number;\n        children: {\n          id: number;\n          someArray: {\n            someProperty?: number\n          }[]\n        }[];\n      }\n\n      const dna = db.addCollection<ABC, { \"children.someArray.someProperty\": number[] }>(\"dnacoll\",\n        {\n          nestedProperties: [\"children.someArray.someProperty\"]\n        });\n\n      dna.insert({\n        id: 1,\n        children: [{\n          id: 11,\n          someArray: [{\n            someProperty: 111\n          }]\n        }]\n      });\n\n      dna.insert({\n        id: 2,\n        children: [{\n          id: 22,\n          someArray: [{\n            someProperty: 222\n          }]\n        }]\n      });\n\n      dna.insert({\n        id: 3,\n        children: [{\n          id: 33,\n          someArray: [{\n            someProperty: 333\n          }, {\n            someProperty: 222\n          }]\n        }]\n      });\n\n      dna.insert({\n        id: 4,\n        children: [{\n          id: 44,\n          someArray: [{\n            someProperty: 111\n          }]\n        }]\n      });\n\n      dna.insert({\n        id: 5,\n        children: [{\n          id: 55,\n          someArray: [{\n            // Missing\n          }]\n        }]\n      });\n\n      dna.insert({\n        id: 6,\n        children: [{\n          id: 66,\n          someArray: [{\n            someProperty: null\n          }]\n        }]\n      });\n\n      let results = dna.find({ \"children.someArray.someProperty\": { \"$contains\": 333 } });\n      expect(results.length).toEqual(1);\n\n      results = dna.find({ \"children.someArray.someProperty\": { \"$contains\": 111 } });\n      expect(results.length).toEqual(2);\n\n      results = dna.find({ \"children.someArray.someProperty\": { \"$contains\": 222 } });\n      expect(results.length).toEqual(2);\n\n      results = dna.find({ \"$and\": [{ \"id\": 3 }, { \"children.someArray.someProperty\": { \"$contains\": 222 } }] });\n      expect(results.length).toEqual(1);\n\n      results = dna.find({ \"$and\": [{ \"id\": 1 }, { \"children.someArray.someProperty\": { \"$contains\": 222 } }] });\n      expect(results.length).toEqual(0);\n\n      results = dna.find({ \"$or\": [{ \"id\": 1 }, { \"children.someArray.someProperty\": { \"$contains\": 222 } }] });\n      expect(results.length).toEqual(3);\n    });\n  });\n\n  describe(\"avl indexes\", () => {\n    it(\"works\", () => {\n      interface ITC {\n        \"testid\": number;\n      }\n\n      const itc = db.addCollection<ITC>(\"test\", {\n        rangedIndexes: {\n          testid: { indexTypeName: \"avl\", comparatorName: \"js\" }\n        }\n      });\n\n      itc.insert({\n        \"testid\": 1\n      });\n      itc.insert({\n        \"testid\": 2\n      });\n      itc.insert({\n        \"testid\": 5\n      });\n      itc.insert({\n        \"testid\": 5\n      });\n      itc.insert({\n        \"testid\": 9\n      });\n      itc.insert({\n        \"testid\": 11\n      });\n      itc.insert({\n        \"testid\": 22\n      });\n      itc.insert({\n        \"testid\": 22\n      });\n\n      // lte\n      let results = itc.find({\n        \"testid\": {\n          \"$lte\": 1\n        }\n      });\n      expect(results.length).toEqual(1);\n\n      results = itc.find({\n        \"testid\": {\n          \"$lte\": 22\n        }\n      });\n      expect(results.length).toEqual(8);\n\n      // lt\n      results = itc.find({\n        \"testid\": {\n          \"$lt\": 1\n        }\n      });\n      expect(results.length).toEqual(0);\n\n      results = itc.find({\n        \"testid\": {\n          \"$lt\": 22\n        }\n      });\n      expect(results.length).toEqual(6);\n\n      // eq\n      results = itc.find({\n        \"testid\": {\n          \"$eq\": 22\n        }\n      });\n      expect(results.length).toEqual(2);\n\n      // gt\n      results = itc.find({\n        \"testid\": {\n          \"$gt\": 22\n        }\n      });\n      expect(results.length).toEqual(0);\n\n      results = itc.find({\n        \"testid\": {\n          \"$gt\": 5\n        }\n      });\n      expect(results.length).toEqual(4);\n\n      // gte\n      results = itc.find({\n        \"testid\": {\n          \"$gte\": 5\n        }\n      });\n      expect(results.length).toEqual(6);\n\n      results = itc.find({\n        \"testid\": {\n          \"$gte\": 10\n        }\n      });\n      expect(results.length).toEqual(3);\n    });\n  });\n\n  describe(\"ResultSet\", () => {\n    it(\"works\", () => {\n      // ResultSet find\n      expect(users.chain().find({\n        \"age\": {\n          \"$gte\": 30\n        }\n      }).where((obj: User) => obj.lang === \"Swedish\").data().length).toEqual(1);\n\n      // ResultSet offset\n      expect(users.chain().offset(1).data().length).toEqual(users.count() - 1);\n\n      // ResultSet limit\n      expect(users.chain().limit(2).data().length).toEqual(2);\n    });\n  });\n\n  describe(\"andOrOps\", () => {\n    it(\"works\", () => {\n      interface EIC {\n        \"testid\": number;\n        \"testString\": string;\n        \"testFloat\": number;\n      }\n\n      const eic = db.addCollection<EIC>(\"eic\");\n\n      eic.insert({\n        \"testid\": 1,\n        \"testString\": \"hhh\",\n        \"testFloat\": 5.2\n      }); //0\n      eic.insert({\n        \"testid\": 1,\n        \"testString\": \"bbb\",\n        \"testFloat\": 6.2\n      }); //1\n      eic.insert({\n        \"testid\": 5,\n        \"testString\": \"zzz\",\n        \"testFloat\": 7.2\n      }); //2\n      eic.insert({\n        \"testid\": 6,\n        \"testString\": \"ggg\",\n        \"testFloat\": 1.2\n      }); //3\n      eic.insert({\n        \"testid\": 9,\n        \"testString\": \"www\",\n        \"testFloat\": 8.2\n      }); //4\n      eic.insert({\n        \"testid\": 11,\n        \"testString\": \"yyy\",\n        \"testFloat\": 4.2\n      }); //5\n      eic.insert({\n        \"testid\": 22,\n        \"testString\": \"bbb\",\n        \"testFloat\": 9.2\n      }); //6\n      eic.insert({\n        \"testid\": 23,\n        \"testString\": \"m\",\n        \"testFloat\": 2.2\n      }); //7\n\n      // coll.find explicit $and\n      expect(eic.find({\n        \"$and\": [{\n          \"testid\": 1\n        }, {\n          \"testString\": \"bbb\"\n        }]\n      }).length).toEqual(1);\n\n      // coll.find implicit '$and'\n      expect(eic.find({\n        \"testid\": 1,\n        \"testString\": \"bbb\"\n      }).length).toEqual(1);\n\n      // ResultSet.find explicit $and\n      expect(eic.chain().find({\n        \"$and\": [{\n          \"testid\": 1\n        }, {\n          \"testString\": \"bbb\"\n        }]\n      }).data().length).toEqual(1);\n\n      // ResultSet.find implicit $and\n      expect(eic.chain().find({\n        \"testid\": 1,\n        \"testString\": \"bbb\"\n      }).data().length).toEqual(1);\n\n      // ResultSet.find explicit operators\n      expect(eic.chain().find({\n        \"$and\": [{\n          \"testid\": {\n            \"$eq\": 1\n          }\n        }, {\n          \"testFloat\": {\n            \"$gt\": 6.0\n          }\n        }]\n      }).data().length).toEqual(1);\n\n      // coll.find $or\n      expect(eic.find({\n        \"$or\": [{\n          \"testid\": 1\n        }, {\n          \"testString\": \"bbb\"\n        }]\n      }).length).toEqual(3);\n\n      // ResultSet.find $or\n      expect(eic.chain().find({\n        \"$or\": [{\n          \"testid\": 1\n        }, {\n          \"testString\": \"bbb\"\n        }]\n      }).data().length).toEqual(3);\n\n      // ResultSet.find explicit operators\n      expect(eic.chain().find({\n        \"$or\": [{\n          \"testid\": 1\n        }, {\n          \"testFloat\": {\n            \"$gt\": 7.0\n          }\n        }]\n      }).data().length).toEqual(5);\n\n      // add index and repeat final test\n      eic.ensureRangedIndex(\"testid\");\n\n      expect(eic.chain().find({\n        \"$and\": [{\n          \"testid\": {\n            \"$eq\": 1\n          }\n        }, {\n          \"testFloat\": {\n            \"$gt\": 6.0\n          }\n        }]\n      }).data().length).toEqual(1);\n\n      expect(eic.chain().find({\n        \"$or\": [{\n          \"testid\": 1\n        }, {\n          \"testFloat\": {\n            \"$gt\": 7.0\n          }\n        }]\n      }).data().length).toEqual(5);\n\n      db.removeCollection(\"eic\");\n    });\n  });\n\n  describe(\"findOne\", () => {\n    it(\"works\", () => {\n      interface EIC {\n        \"testid\": number;\n        \"testString\": string;\n        \"testFloat\": number;\n      }\n\n      const eic = db.addCollection<EIC>(\"eic\");\n\n      eic.insert({\n        \"testid\": 1,\n        \"testString\": \"hhh\",\n        \"testFloat\": 5.2\n      }); //0\n      eic.insert({\n        \"testid\": 1,\n        \"testString\": \"bbb\",\n        \"testFloat\": 6.2\n      }); //1\n      eic.insert({\n        \"testid\": 5,\n        \"testString\": \"zzz\",\n        \"testFloat\": 7.2\n      }); //2\n\n      // coll.findOne return type\n      expect(typeof eic.findOne({\n        \"testid\": 1\n      })).toEqual(\"object\");\n\n      // coll.findOne return match\n      expect(eic.findOne({\n        \"testid\": 5\n      }).testFloat).toEqual(7.2);\n\n      // findOne with $and op\n      expect(eic.findOne({\n        \"$and\": [{\n          \"testid\": 1\n        }, {\n          \"testString\": \"bbb\"\n        }]\n      }).testFloat).toEqual(6.2);\n\n      expect(eic.findOne({\n        \"$or\": [{\n          \"testid\": 2\n        }, {\n          \"testString\": \"zzz\"\n        }]\n      }).testFloat).toEqual(7.2);\n\n      db.removeCollection(\"eic\");\n    });\n  });\n\n  describe(\"ResultSet unfiltered simplesort works\", () => {\n    it(\"works\", () => {\n      const ssdb = new Loki(\"sandbox.db\");\n\n      interface User {\n        name: string;\n        owner: string;\n        maker: string;\n      }\n\n      // Add a collection to the database\n      const items = ssdb.addCollection<User>(\"items\", { rangedIndexes: { \"name\": {}} });\n\n      // Add some documents to the collection\n      items.insert({ name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\" });\n      items.insert({ name: \"gungnir\", owner: \"odin\", maker: \"elves\" });\n      items.insert({ name: \"tyrfing\", owner: \"svafrlami\", maker: \"dwarves\" });\n      items.insert({ name: \"draupnir\", owner: \"odin\", maker: \"elves\" });\n\n      // simplesort without filters on prop with index should work\n      let results = items.chain().simplesort(\"name\").data();\n      expect(results.length).toEqual(4);\n      expect(results[0].name).toEqual(\"draupnir\");\n      expect(results[1].name).toEqual(\"gungnir\");\n      expect(results[2].name).toEqual(\"mjolnir\");\n      expect(results[3].name).toEqual(\"tyrfing\");\n\n      // simplesort without filters on prop without index should work\n      results = items.chain().simplesort(\"owner\").data();\n      expect(results.length).toEqual(4);\n      expect(results[0].owner).toEqual(\"odin\");\n      expect(results[1].owner).toEqual(\"odin\");\n      expect(results[2].owner).toEqual(\"svafrlami\");\n      expect(results[3].owner).toEqual(\"thor\");\n    });\n  });\n\n  describe(\"ResultSet data clone\", () => {\n    it(\"nested works \", () => {\n      const idb = new Loki(\"sandbox.db\");\n\n      interface AUser {\n        user: {\n          name: string;\n          owner: string;\n          maker: string;\n        };\n      }\n\n      // Add a collection to the database\n      const items = idb.addCollection<AUser, { \"user.name\": string }>(\"items\", { nestedProperties: [\"user.name\"] });\n\n      // Add some documents to the collection\n      items.insert({ user: { name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\" } });\n      items.insert({ user: { name: \"gungnir\", owner: \"odin\", maker: \"elves\" } });\n      items.insert({ user: { name: \"tyrfing\", owner: \"svafrlami\", maker: \"dwarves\" } });\n      items.insert({ user: { name: \"draupnir\", owner: \"odin\", maker: \"elves\" } });\n\n      const result = items.chain().data({ forceClones: true });\n      expect(result[0][\"user.name\"]).toBeDefined();\n      expect(result[0][\"user.owner\"]).toBeUndefined();\n    });\n  });\n\n  describe(\"ResultSet data removeMeta works\", () => {\n    it(\"works\", () => {\n      const idb = new Loki(\"sandbox.db\");\n\n      interface User {\n        name: string;\n        owner: string;\n        maker: string;\n      }\n\n      // Add a collection to the database\n      const items = idb.addCollection<User>(\"items\", { rangedIndexes: { \"owner\" : {}} });\n\n      // Add some documents to the collection\n      items.insert({ name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\" });\n      items.insert({ name: \"gungnir\", owner: \"odin\", maker: \"elves\" });\n      items.insert({ name: \"tyrfing\", owner: \"svafrlami\", maker: \"dwarves\" });\n      items.insert({ name: \"draupnir\", owner: \"odin\", maker: \"elves\" });\n\n      // unfiltered with strip meta\n      let result = items.chain().data({ removeMeta: true });\n      expect(result.length).toEqual(4);\n      expect(result[0].hasOwnProperty(\"$loki\")).toEqual(false);\n      expect(result[0].hasOwnProperty(\"meta\")).toEqual(false);\n      expect(result[1].hasOwnProperty(\"$loki\")).toEqual(false);\n      expect(result[1].hasOwnProperty(\"meta\")).toEqual(false);\n      expect(result[2].hasOwnProperty(\"$loki\")).toEqual(false);\n      expect(result[2].hasOwnProperty(\"meta\")).toEqual(false);\n      expect(result[3].hasOwnProperty(\"$loki\")).toEqual(false);\n      expect(result[3].hasOwnProperty(\"meta\")).toEqual(false);\n\n      // indexed sort with strip meta\n      result = items.chain().simplesort(\"owner\").limit(2).data({ removeMeta: true });\n      expect(result.length).toEqual(2);\n      expect(result[0].owner).toEqual(\"odin\");\n      expect(result[0].hasOwnProperty(\"$loki\")).toEqual(false);\n      expect(result[0].hasOwnProperty(\"meta\")).toEqual(false);\n      expect(result[1].owner).toEqual(\"odin\");\n      expect(result[1].hasOwnProperty(\"$loki\")).toEqual(false);\n      expect(result[1].hasOwnProperty(\"meta\")).toEqual(false);\n\n      // unindexed find strip meta\n      result = items.chain().find({ maker: \"elves\" }).data({ removeMeta: true });\n      expect(result.length).toEqual(2);\n      expect(result[0].maker).toEqual(\"elves\");\n      expect(result[0].hasOwnProperty(\"$loki\")).toEqual(false);\n      expect(result[0].hasOwnProperty(\"meta\")).toEqual(false);\n      expect(result[1].maker).toEqual(\"elves\");\n      expect(result[1].hasOwnProperty(\"$loki\")).toEqual(false);\n      expect(result[1].hasOwnProperty(\"meta\")).toEqual(false);\n\n      // now try unfiltered without strip meta and ensure loki and meta are present\n      result = items.chain().data();\n      expect(result.length).toEqual(4);\n      expect(result[0].hasOwnProperty(\"$loki\")).toEqual(true);\n      expect(result[0].hasOwnProperty(\"meta\")).toEqual(true);\n      expect(result[1].hasOwnProperty(\"$loki\")).toEqual(true);\n      expect(result[1].hasOwnProperty(\"meta\")).toEqual(true);\n      expect(result[2].hasOwnProperty(\"$loki\")).toEqual(true);\n      expect(result[2].hasOwnProperty(\"meta\")).toEqual(true);\n      expect(result[3].hasOwnProperty(\"$loki\")).toEqual(true);\n      expect(result[3].hasOwnProperty(\"meta\")).toEqual(true);\n\n      // now try without strip meta and ensure loki and meta are present\n      result = items.chain().simplesort(\"owner\").limit(2).data();\n      expect(result.length).toEqual(2);\n      expect(result[0].owner).toEqual(\"odin\");\n      expect(result[0].hasOwnProperty(\"$loki\")).toEqual(true);\n      expect(result[0].hasOwnProperty(\"meta\")).toEqual(true);\n      expect(result[1].owner).toEqual(\"odin\");\n      expect(result[1].hasOwnProperty(\"$loki\")).toEqual(true);\n      expect(result[1].hasOwnProperty(\"meta\")).toEqual(true);\n\n      // unindexed find strip meta\n      result = items.chain().find({ maker: \"elves\" }).data();\n      expect(result.length).toEqual(2);\n      expect(result[0].maker).toEqual(\"elves\");\n      expect(result[0].hasOwnProperty(\"$loki\")).toEqual(true);\n      expect(result[0].hasOwnProperty(\"meta\")).toEqual(true);\n      expect(result[1].maker).toEqual(\"elves\");\n      expect(result[1].hasOwnProperty(\"$loki\")).toEqual(true);\n      expect(result[1].hasOwnProperty(\"meta\")).toEqual(true);\n    });\n  });\n\n  describe(\"chained removes\", () => {\n    it(\"works\", () => {\n      interface RSC {\n        \"testid\": number;\n        \"testString\": string;\n        \"testFloat\": number;\n      }\n\n      const rsc = db.addCollection<RSC>(\"rsc\");\n\n      rsc.insert({\n        \"testid\": 1,\n        \"testString\": \"hhh\",\n        \"testFloat\": 5.2\n      });\n      rsc.insert({\n        \"testid\": 1,\n        \"testString\": \"bbb\",\n        \"testFloat\": 6.2\n      });\n      rsc.insert({\n        \"testid\": 2,\n        \"testString\": \"ccc\",\n        \"testFloat\": 6.2\n      });\n      rsc.insert({\n        \"testid\": 5,\n        \"testString\": \"zzz\",\n        \"testFloat\": 7.2\n      });\n\n      const docCount = rsc.find().length;\n\n      // verify initial doc count\n      expect(docCount).toEqual(4);\n\n      // remove middle documents\n      rsc.chain().find({ testFloat: 6.2 }).remove();\n\n\n      // verify new doc count\n      expect(rsc.find().length).toEqual(2);\n      expect(rsc.chain().data().length).toEqual(2);\n\n      // now fetch and retain all remaining documents\n      const results = rsc.chain().simplesort(\"testString\").data();\n\n      // make sure its the documents we expect\n      expect(results[0].testString).toEqual(\"hhh\");\n      expect(results[1].testString).toEqual(\"zzz\");\n    });\n  });\n\n  /* Dynamic View Tests */\n});\n"
  },
  {
    "path": "packages/loki/spec/generic/transforms.spec.ts",
    "content": "/* global describe, beforeEach, it, expect */\nimport { Loki } from \"../../src/loki\";\nimport { Collection } from \"../../src/collection\";\nimport Transform = Collection.Transform;\n\ndescribe(\"transforms\", () => {\n  interface User {\n    name: string;\n    owner?: string;\n    maker?: string;\n  }\n\n  let db: Loki;\n  let items: Collection<User>;\n\n  beforeEach(() => {\n    db = new Loki(\"transformTest\");\n    items = db.addCollection<User>(\"items\");\n\n    items.insert({name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\"});\n    items.insert({name: \"gungnir\", owner: \"odin\", maker: \"elves\"});\n    items.insert({name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\"});\n    items.insert({name: \"draupnir\", owner: \"odin\", maker: \"elves\"});\n  });\n\n  describe(\"basic find transform\", () => {\n    it(\"works\", () => {\n\n      const tx: Transform<User>[] = [\n        {\n          type: \"find\",\n          value: {\n            owner: \"odin\"\n          }\n        }\n      ];\n\n      const results = items.chain(tx).data();\n\n      expect(results.length).toBe(2);\n    });\n  });\n\n  describe(\"basic multi-step transform\", () => {\n    it(\"works\", () => {\n\n      const tx: Transform<User>[] = [\n        {\n          type: \"find\",\n          value: {\n            owner: \"odin\"\n          }\n        },\n        {\n          type: \"where\",\n          value: function (obj: User) {\n            return (obj.name.indexOf(\"drau\") !== -1);\n          }\n        }\n      ];\n\n      const results = items.chain(tx).data();\n\n      expect(results.length).toBe(1);\n    });\n  });\n\n  describe(\"parameterized find\", () => {\n    it(\"works\", () => {\n\n      const tx: Transform<User>[] = [\n        {\n          type: \"find\",\n          value: {\n            owner: \"[%lktxp]OwnerName\"\n          }\n        }\n      ];\n\n      const params = {\n        OwnerName: \"odin\"\n      };\n\n      const results = items.chain(tx, params).data();\n\n      expect(results.length).toBe(2);\n    });\n  });\n\n  describe(\"parameterized transform with non-serializable non-params\", function () {\n    it(\"works\", function () {\n\n      interface Person {\n        name: string;\n        age: number;\n      }\n\n\n      const db = new Loki(\"tx.db\");\n      const items = db.addCollection<Person>(\"items\");\n\n      items.insert({name: \"mjolnir\", age: 5});\n      items.insert({name: \"tyrfing\", age: 9});\n\n      let mapper = function (item: Person) {\n        return item.age;\n      };\n\n      let averageReduceFunction = function (values: number[]) {\n        let sum = 0;\n\n        values.forEach(function (i) {\n          sum += i;\n        });\n\n        return sum / values.length;\n      };\n\n      // so ideally, transform params are useful for\n      // - extracting values that will change across multiple executions, and also\n      // - extracting values which are not serializable so that the transform can be\n      //   named and serialized along with the database.\n      //\n      // The transform used here is not serializable so this test is just to verify\n      // that our parameter substitution method does not have problem with\n      // non-serializable transforms.\n\n      let tx1: Transform<Person>[] = [\n        {\n          type: \"mapReduce\",\n          mapFunction: mapper,\n          reduceFunction: averageReduceFunction\n        }\n      ];\n\n      let tx2: Transform[] = [\n        {\n          type: \"find\",\n          value: {\n            age: {\n              \"$gt\": \"[%lktxp]minimumAge\"\n            },\n          }\n        },\n        {\n          type: \"mapReduce\",\n          mapFunction: mapper,\n          reduceFunction: averageReduceFunction\n        }\n      ] as any;\n\n      // no data() call needed to mapReduce\n      expect(items.chain(tx1) as any as number).toBe(7);\n      expect(items.chain(tx1, {foo: 5}) as any as number).toBe(7);\n      // params will cause a recursive shallow clone of objects before substitution\n      expect(items.chain(tx2, {minimumAge: 4}) as any as number).toBe(7);\n\n      // make sure original transform is unchanged\n      expect(tx2[0].type).toEqual(\"find\");\n      expect(tx2[0][\"value\"].age.$gt).toEqual(\"[%lktxp]minimumAge\");\n      expect(tx2[1].type).toEqual(\"mapReduce\");\n      expect(typeof tx2[1][\"mapFunction\"]).toEqual(\"function\");\n      expect(typeof tx2[1][\"reduceFunction\"]).toEqual(\"function\");\n    });\n  });\n\n  describe(\"parameterized where\", () => {\n    it(\"works\", () => {\n\n      const tx: Transform<User>[] = [\n        {\n          type: \"where\",\n          value: \"[%lktxp]NameFilter\"\n        }\n      ];\n\n      const params = {\n        NameFilter: function (obj: User) {\n          return (obj.name.indexOf(\"nir\") !== -1);\n        }\n      };\n\n      const results = items.chain(tx, params).data();\n\n      expect(results.length).toBe(3);\n    });\n  });\n\n  describe(\"named find transform\", () => {\n    it(\"works\", () => {\n\n      const tx: Transform<User>[] = [\n        {\n          type: \"find\",\n          value: {\n            owner: \"[%lktxp]OwnerName\"\n          }\n        }\n      ];\n\n      items.addTransform(\"OwnerLookup\", tx);\n\n      const params = {\n        OwnerName: \"odin\"\n      };\n\n      const results = items.chain(\"OwnerLookup\", params).data();\n\n      expect(results.length).toBe(2);\n    });\n  });\n\n  describe(\"dynamic view named transform\", () => {\n    it(\"works\", () => {\n      interface AB {\n        a: string;\n        b: number;\n      }\n\n      const testColl = db.addCollection<AB>(\"test\");\n\n      testColl.insert({\n        a: \"first\",\n        b: 1\n      });\n\n      testColl.insert({\n        a: \"second\",\n        b: 2\n      });\n\n      testColl.insert({\n        a: \"third\",\n        b: 3\n      });\n\n      testColl.insert({\n        a: \"fourth\",\n        b: 4\n      });\n\n      testColl.insert({\n        a: \"fifth\",\n        b: 5\n      });\n\n      testColl.insert({\n        a: \"sixth\",\n        b: 6\n      });\n\n      testColl.insert({\n        a: \"seventh\",\n        b: 7\n      });\n\n      testColl.insert({\n        a: \"eighth\",\n        b: 8\n      });\n\n      // our view should allow only first 4 test records\n      const dv = testColl.addDynamicView(\"lower\");\n      dv.applyFind({b: {\"$lte\": 4}});\n\n      // our transform will desc sort string column as 'third', 'second', 'fourth', 'first',\n      // and then limit to first two\n      const tx: Transform<AB>[] = [\n        {\n          type: \"simplesort\",\n          property: \"a\",\n          options: true\n        },\n        {\n          type: \"limit\",\n          value: 2\n        }\n      ];\n\n      expect(dv.branchResultSet(tx).data().length).toBe(2);\n\n      // now store as named (collection) transform and run off dynamic view\n      testColl.addTransform(\"desc4limit2\", tx);\n\n      const results = dv.branchResultSet(\"desc4limit2\").data();\n      expect(results.length).toBe(2);\n      expect(results[0].a).toBe(\"third\");\n      expect(results[1].a).toBe(\"second\");\n\n    });\n  });\n  describe(\"eqJoin step with dataOptions works\", function () {\n    it(\"works\", () => {\n      const db1 = new Loki(\"testJoins\");\n\n      interface Director {\n        name: string;\n        directorId: number;\n      }\n\n      interface Film {\n        title: string;\n        filmId: number;\n        directorId: number;\n      }\n\n      const directors = db1.addCollection<Director>(\"directors\");\n      const films = db1.addCollection<Film>(\"films\");\n\n      directors.insert([\n        {name: \"Martin Scorsese\", directorId: 1},\n        {name: \"Francis Ford Coppola\", directorId: 2},\n        {name: \"Steven Spielberg\", directorId: 3},\n        {name: \"Quentin Tarantino\", directorId: 4}\n      ]);\n\n      films.insert([\n        {title: \"Taxi\", filmId: 1, directorId: 1},\n        {title: \"Raging Bull\", filmId: 2, directorId: 1},\n        {title: \"The Godfather\", filmId: 3, directorId: 2},\n        {title: \"Jaws\", filmId: 4, directorId: 3},\n        {title: \"ET\", filmId: 5, directorId: 3},\n        {title: \"Raiders of the Lost Ark\", filmId: 6, directorId: 3}\n      ]);\n\n      // Since our collection options do not specify cloning, this is only safe\n      // because we have cloned internal objects with dataOptions before modifying them.\n      function fdmap(left: object, right: object) {\n        // PhantomJS does not support es6 Object.assign\n        //left = Object.assign(left, right);\n        Object.keys(right).forEach((key) => {\n          left[key] = right[key];\n        });\n        return left;\n      }\n\n      // The 'joinData' in this instance is a Collection which we will call\n      //   data() on with the specified (optional) dataOptions on.\n      //   It could also be a ResultSet or data array.\n      // Our left side ResultSet which this transform is executed on will also\n      //   call data() with specified (optional) dataOptions.\n      films.addTransform(\"filmdirect\", [\n        {\n          type: \"eqJoin\",\n          joinData: directors,\n          leftJoinKey: \"directorId\",\n          rightJoinKey: \"directorId\",\n          mapFun: fdmap,\n          dataOptions: {removeMeta: true}\n        }\n      ]);\n\n      // Although we removed all meta, the eqjoin inserts the resulting objects\n      // into a new volatile collection which would adds its own meta and loki.\n      // We don't care about these useless volatile data so grab results without it.\n      const results = films.chain(\"filmdirect\").data({removeMeta: true}) as any as (Director & Film)[];\n\n      expect(results.length).toEqual(6);\n      expect(results[0].title).toEqual(\"Taxi\");\n      expect(results[0].name).toEqual(\"Martin Scorsese\");\n      expect(results[5].title).toEqual(\"Raiders of the Lost Ark\");\n      expect(results[5].name).toEqual(\"Steven Spielberg\");\n      results.forEach((obj) => {\n        expect(Object.keys(obj).length).toEqual(4);\n      });\n    });\n  });\n\n  describe(\"map step with dataOptions works\", function () {\n    it(\"works\", () => {\n      const db1 = new Loki(\"testJoins\");\n\n      interface C1 {\n        a: number;\n        b: number;\n        c?: number;\n      }\n\n      const c1 = db1.addCollection<C1>(\"c1\");\n      c1.insert([\n        {a: 1, b: 9},\n        {a: 2, b: 8},\n        {a: 3, b: 7},\n        {a: 4, b: 6}\n      ]);\n\n      // only safe because our 'removeMeta' option will clone objects passed in\n      function graftMap(obj: C1) {\n        obj.c = obj.b - obj.a;\n        return obj;\n      }\n\n      const tx: Transform<C1>[] = [{\n        type: \"map\",\n        value: graftMap,\n        dataOptions: {removeMeta: true}\n      }];\n\n      const results = c1.chain(tx).data({removeMeta: true});\n\n      expect(results.length).toEqual(4);\n      expect(results[0].a).toEqual(1);\n      expect(results[0].b).toEqual(9);\n      expect(results[0].c).toEqual(8);\n      expect(results[3].a).toEqual(4);\n      expect(results[3].b).toEqual(6);\n      expect(results[3].c).toEqual(2);\n      results.forEach((obj) => {\n        expect(Object.keys(obj).length).toEqual(3);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/loki/spec/generic/typed.spec.ts",
    "content": "/* global describe, it, expect */\nimport { Loki } from \"../../src/loki\";\nimport { Doc } from \"../../../common/types\";\n\ndescribe(\"typed\", () => {\n  it(\"works\", () => {\n    const db = new Loki(\"test.json\");\n    let users;\n\n    class User {\n      public name?: string;\n      public customInflater?: boolean;\n      public onlyInflater?: boolean;\n\n      constructor(name: string = \"\") {\n        this.name = name;\n      }\n    }\n\n    const json = {\n      \"filename\": \"test.json\",\n      \"_collections\": [{\n        \"name\": \"users\",\n        \"_data\": [{\n          \"name\": \"joe\",\n          \"meta\": {\n            \"version\": 0,\n            \"created\": 1415467401386,\n            \"revision\": 0\n          },\n          \"$loki\": 1\n        }, {\n          \"name\": \"jack\",\n          \"meta\": {\n            \"version\": 0,\n            \"created\": 1415467401388,\n            \"revision\": 0\n          },\n          \"$loki\": 2\n        }],\n        \"idIndex\": [1, 2],\n        \"binaryIndices\": {},\n        \"transactional\": false,\n        \"maxId\": 2,\n        \"_nestedProperties\": [] as any[],\n      }],\n      \"events\": {},\n      \"ENV\": \"NODEJS\",\n      \"fs\": {}\n    };\n\n    // Loading only using proto:\n    db.loadJSON(JSON.stringify(json), {\n      users: {\n        proto: User\n      }\n    });\n\n    users = db.getCollection<User>(\"users\");\n\n    expect(users.get(1) instanceof User).toBe(true);\n    expect(users.get(1).name).toBe(\"joe\");\n\n    // Loading using proto and inflate:\n    db.loadJSON(JSON.stringify(json), {\n      users: {\n        proto: User,\n        inflate: function (src: Doc<User>, dest: Doc<User>) {\n          dest.$loki = src.$loki;\n          dest.meta = src.meta;\n          dest.customInflater = true;\n        }\n      }\n    });\n\n    users = db.getCollection<User>(\"users\");\n\n    expect(users.get(1) instanceof User).toBe(true);\n    expect(users.get(1).name).toBe(\"\");\n    expect(users.get(1).customInflater).toBe(true);\n\n    // Loading only using inflate:\n    db.loadJSON(JSON.stringify(json), {\n      users: {\n        inflate: function (src: Doc<User>) {\n          return {\n            $loki: src.$loki,\n            meta: src.meta,\n            onlyInflater: true\n          };\n        }\n      }\n    });\n\n    users = db.getCollection<User>(\"users\");\n\n    expect(users.get(1) instanceof User).toBe(false);\n    expect(users.get(1).name).toBe(undefined);\n    expect(users.get(1).onlyInflater).toBe(true);\n  });\n});\n"
  },
  {
    "path": "packages/loki/spec/generic/unique.spec.ts",
    "content": "/* global describe, it, expect */\nimport { Loki } from \"../../src/loki\";\nimport { MemoryStorage } from \"../../../memory-storage/src/memory_storage\";\n\ndescribe(\"Constraints\", () => {\n\n  interface User {\n    numb?: number;\n    username?: string;\n    name: string;\n  }\n\n  it(\"should retrieve records with by()\", () => {\n    const db = new Loki();\n\n    const coll = db.addCollection<User>(\"users\", {\n      unique: [\"username\"]\n    });\n    coll.insert({\n      username: \"joe\",\n      name: \"Joe\"\n    });\n    coll.insert({\n      username: \"jack\",\n      name: \"Jack\"\n    });\n    expect(coll.by(\"username\", \"joe\").name).toEqual(\"Joe\");\n\n    const byUsername = (value: string) => coll.by(\"username\", value);\n    expect(byUsername(\"jack\").name).toEqual(\"Jack\");\n\n    const joe = coll.by(\"username\", \"joe\");\n    joe.username = \"jack\";\n    expect(() => {\n      coll.update(joe);\n    }).toThrow(new Error(\"Duplicate key for property username: \" + joe.username));\n    joe.username = \"jim\";\n    coll.update(joe);\n    expect(byUsername(\"jim\")).toEqual(joe);\n\n    coll.update(joe);\n  });\n\n  it(\"should create a unique index\", () => {\n    const db = new Loki();\n    const coll2 = db.addCollection<User>(\"moreusers\");\n    coll2.insert({\n      name: \"jack\"\n    });\n    coll2.insert({\n      name: \"tim\"\n    });\n    coll2.ensureUniqueIndex(\"name\");\n  });\n\n  it(\"should not add record with null index\", () => {\n    const db = new Loki();\n    const coll3 = db.addCollection<User>(\"nullusers\", {\n      unique: [\"username\"]\n    });\n    coll3.insert({\n      username: \"joe\",\n      name: \"Joe\"\n    });\n    coll3.insert({\n      username: null,\n      name: \"Jack\"\n    });\n\n    expect(Object.keys(coll3[\"_constraints\"].unique[\"username\"][\"_valMap\"]).length).toEqual(1);\n    expect(Object.keys(coll3[\"_constraints\"].unique[\"username\"][\"_lokiMap\"]).length).toEqual(1);\n  });\n\n  it(\"chained search\", () => {\n    const db = new Loki();\n    const coll = db.addCollection<User>(\"morenullusers\", {\n      unique: [\"name\"]\n    });\n    coll.insert({\n      numb: 1,\n      username: \"jacky\",\n      name: \"Joe\"\n    });\n    coll.insert({\n      numb: 1,\n      username: \"jacky\",\n      name: \"Jack\"\n    });\n\n    expect(coll.find({\"name\": \"Joe\"}).length).toBe(1);\n    expect(coll.find({\"numb\": 1}).length).toBe(2);\n\n    expect(coll.chain()\n      .find({\"numb\": 1})\n      .find({\"name\": \"Jack\"}).data().length).toBe(1);\n\n    expect(coll.chain()\n      .find({\"name\": \"Jack\"})\n      .find({\"numb\": 1}).data().length).toBe(1);\n\n    expect(coll.chain()\n      .find({\"name\": \"Jack\"})\n      .find({\"numb\": 1})\n      .find({\"username\": \"jacky\"}).data().length).toBe(1);\n\n    expect(coll.chain()\n      .find({\"username\": \"jacky\"})\n      .find({\"name\": \"Jack\"}).data().length).toBe(1);\n\n    expect(coll.chain()\n      .find({\"name\": \"Joe\"})\n      .find({\"name\": \"Jack\"}).data().length).toBe(0);\n  });\n\n  it(\"does not fail if no entry is found\", () => {\n    const db = new Loki();\n    const coll = db.addCollection<User>(\"morenullusers\", {\n      unique: [\"username\"]\n    });\n\n    expect(coll.find({username: \"joe\"}).length).toBe(0);\n\n    coll.insert({\n      numb: 1,\n      username: \"jacky\",\n      name: \"Joe\"\n    });\n\n    expect(coll.chain().find({numb: 1}).find({username: \"joe\"}).data().length).toBe(0);\n    expect(coll.find({username: \"joe\"}).length).toBe(0);\n  });\n\n  it(\"should not throw an error id multiple nulls are added\", () => {\n    const db = new Loki();\n    const coll4 = db.addCollection<User>(\"morenullusers\", {\n      unique: [\"username\"]\n    });\n    coll4.insert({\n      username: \"joe\",\n      name: \"Joe\"\n    });\n    coll4.insert({\n      username: null,\n      name: \"Jack\"\n    });\n    coll4.insert({\n      username: null,\n      name: \"Jake\"\n    });\n    expect(Object.keys(coll4[\"_constraints\"].unique[\"username\"][\"_valMap\"]).length).toEqual(1);\n    expect(Object.keys(coll4[\"_constraints\"].unique[\"username\"][\"_lokiMap\"]).length).toEqual(1);\n  });\n\n  it(\"coll.clear should affect unique indices correctly\", () => {\n    let db = new Loki();\n    let coll = db.addCollection<User>(\"users\", {unique: [\"username\"]});\n    coll.insert({username: \"joe\", name: \"Joe\"});\n    coll.insert({username: \"jack\", name: \"Jack\"});\n    coll.insert({username: \"jake\", name: \"Jake\"});\n    expect(Object.keys(coll[\"_constraints\"].unique[\"username\"][\"_valMap\"]).length).toEqual(3);\n    expect(Object.keys(coll[\"_constraints\"].unique[\"username\"][\"_lokiMap\"]).length).toEqual(3);\n    coll.clear();\n    expect(Object.keys(coll[\"_constraints\"].unique[\"username\"][\"_valMap\"]).length).toEqual(0);\n    expect(Object.keys(coll[\"_constraints\"].unique[\"username\"][\"_lokiMap\"]).length).toEqual(0);\n    coll.insert({username: \"joe\", name: \"Joe\"});\n    coll.insert({username: \"jack\", name: \"Jack\"});\n    expect(Object.keys(coll[\"_constraints\"].unique[\"username\"][\"_valMap\"]).length).toEqual(2);\n    expect(Object.keys(coll[\"_constraints\"].unique[\"username\"][\"_lokiMap\"]).length).toEqual(2);\n    coll.insert({username: \"jake\", name: \"Jake\"});\n    expect(Object.keys(coll[\"_constraints\"].unique[\"username\"][\"_valMap\"]).length).toEqual(3);\n    expect(Object.keys(coll[\"_constraints\"].unique[\"username\"][\"_lokiMap\"]).length).toEqual(3);\n\n    db = new Loki();\n    coll = db.addCollection<User>(\"users\", {unique: [\"username\"]});\n\n    coll.insert({username: \"joe\", name: \"Joe\"});\n    coll.insert({username: \"jack\", name: \"Jack\"});\n    coll.insert({username: \"jake\", name: \"Jake\"});\n    expect(Object.keys(coll[\"_constraints\"].unique[\"username\"][\"_valMap\"]).length).toEqual(3);\n    expect(Object.keys(coll[\"_constraints\"].unique[\"username\"][\"_lokiMap\"]).length).toEqual(3);\n    coll.clear({removeIndices: true});\n    expect(coll[\"_constraints\"].unique.hasOwnProperty(\"username\")).toEqual(false);\n    coll.insert({username: \"joe\", name: \"Joe\"});\n    coll.insert({username: \"jack\", name: \"Jack\"});\n    coll.insert({username: \"jake\", name: \"Jake\"});\n    expect(coll[\"_constraints\"].unique.hasOwnProperty(\"username\")).toEqual(false);\n  });\n\n  it(\"persistence check\", () => {\n    let db = new Loki(\"TestUnique\");\n    let coll = db.addCollection<User>(\"users\", {unique: [\"name\"]});\n    coll.insert({\n      name: \"Joe\"\n    });\n    coll.insert({\n      name: \"Jack\"\n    });\n\n    let mem = new MemoryStorage();\n\n    expect(() => coll.insert({name: \"Jack\"})).toThrow();\n\n    db.initializePersistence({adapter: mem})\n      .then(() => {\n        return db.saveDatabase();\n      })\n      .then(() => {\n        const db2 = new Loki(\"TestUnique\");\n        return db2.initializePersistence({adapter: mem})\n          .then(() => {\n            return db2.loadDatabase();\n          })\n          .then(() => {\n            const coll2 = db2.getCollection(\"users\");\n            expect(() => coll2.insert({name: \"Jack\"})).toThrow();\n          });\n      })\n      .catch(() => {\n        expect(false).toBe(true);\n      });\n\n  });\n});\n"
  },
  {
    "path": "packages/loki/src/avl_index.ts",
    "content": "import { IRangedIndex, IRangedIndexRequest } from \"./ranged_indexes\";\nimport { ILokiComparer } from \"./comparators\";\n\n/**\n * Treenode type for binary search tree (BST) implementation.\n *\n * To support duplicates, we may need to either repurpose parent to\n * point to 'elder' sibling or add a siblingId to point to owner of\n * node represented in tree.\n */\nexport type TreeNode<T> = {\n  id: number,\n  value: T,\n  parent: number | null,\n  balance: number,\n  height: number,\n  left: number | null,\n  right: number | null,\n  siblings: number[]\n};\n\n/* using indexer than than Map since Map is not serializable. 'id' is document id (such as $loki) */\nexport interface ITreeNodeHash<T> {\n  [id: number]: TreeNode<T>;\n}\n\n/**\n * LokiDB AVL Balanced Binary Tree Index implementation.\n * To support duplicates, we use siblings (array) in tree nodes.\n * Basic AVL components guided by William Fiset tutorials at :\n * https://github.com/williamfiset/data-structures/blob/master/com/williamfiset/datastructures/balancedtree/AVLTreeRecursive.java\n * https://www.youtube.com/watch?v=g4y2h70D6Nk&list=PLDV1Zeh2NRsD06x59fxczdWLhDDszUHKt\n */\nexport class AvlTreeIndex<T> implements IRangedIndex<T> {\n  name: string;\n  comparator: ILokiComparer<T>;\n  nodes: ITreeNodeHash<T> = {};\n  apex: number | null = null;\n\n  /**\n   * Initializes index with property name and a comparer function.\n   */\n  constructor(name: string, comparator: ILokiComparer<T>) {\n    this.name = name;\n    this.comparator = comparator;\n  }\n\n  backup(): AvlTreeIndex<T> {\n    let result = new AvlTreeIndex<T>(this.name, this.comparator);\n    result.nodes = JSON.parse(JSON.stringify(this.nodes));\n    result.apex = this.apex;\n    return result;\n  }\n\n  restore(tree: AvlTreeIndex<T>) {\n    this.name = tree.name;\n    this.comparator = tree.comparator;\n    this.nodes = JSON.parse(JSON.stringify(tree.nodes));\n    this.apex = tree.apex;\n  }\n\n  /**\n   * Used for inserting a new value into the BinaryTreeIndex\n   * @param id Unique Id (such as $loki) to associate with value\n   * @param val Value to be indexed and inserted into binary tree\n   */\n  insert(id: number, val: T) {\n    if (id <= 0) {\n      throw new Error(\"avl index ids are required to be numbers greater than zero\");\n    }\n\n    let node: TreeNode<T> = this.nodes[id] = {\n      id: id,\n      value: val,\n      parent: null,\n      balance: 0,\n      height: 0,\n      left: null,\n      right: null,\n      siblings: []\n    };\n\n    if (!this.apex) {\n      this.apex = id;\n      return;\n    }\n\n    this.insertNode(this.nodes[this.apex], node);\n  }\n\n  /**\n   * Recursively inserts a treenode and re-balances if needed.\n   * @param current\n   * @param node\n   */\n  insertNode(current: TreeNode<T>, node: TreeNode<T>): number {\n    switch (this.comparator(node.value, current.value)) {\n      case 0:\n        // eq\n        current.siblings.push(node.id);\n        node.parent = current.id;\n        break;\n      case 1:\n        // gt\n        if (current.right) {\n          this.insertNode(this.nodes[current.right], node);\n          this.updateBalance(current);\n        }\n        else {\n          current.right = node.id;\n          node.parent = current.id;\n          this.updateBalance(current);\n        }\n        break;\n      case -1:\n        // lt\n        if (current.left) {\n          this.insertNode(this.nodes[current.left], node);\n          this.updateBalance(current);\n        }\n        else {\n          current.left = node.id;\n          node.parent = current.id;\n          this.updateBalance(current);\n        }\n        break;\n      default: throw new Error(\"Invalid comparator result\");\n    }\n\n    if (current.balance < -1) {\n      if (current.left === null) {\n        throw new Error(\"insertNode.balance() : left child should not be null\");\n      }\n      if (this.nodes[current.left].balance <= 0) {\n        this.leftLeftCase(current);\n      }\n      else {\n        this.leftRightCase(current);\n      }\n    }\n\n    if (current.balance > 1) {\n      if (current.right === null) {\n        throw new Error(\"insertNode.balance() : right child should not be null\");\n      }\n      if (this.nodes[current.right].balance >= 0) {\n        this.rightRightCase(current);\n      }\n      else {\n        this.rightLeftCase(current);\n      }\n    }\n\n    return current.height;\n  }\n\n  /**\n   * Updates height and balance (calculation) for tree node\n   * @param node\n   */\n  private updateBalance(node: TreeNode<T>) {\n    let hl = node.left ? this.nodes[node.left].height : -1;\n    let hr = node.right ? this.nodes[node.right].height : -1;\n\n    //node.height = 1 + Math.max(hl, hr);\n    node.height = (hl > hr) ? 1 + hl : 1 + hr;\n\n    node.balance = hr - hl;\n  }\n\n  /**\n   * Balance the 'double left-heavy' condition\n   * @param node\n   */\n  private leftLeftCase(node: TreeNode<T>) {\n    return this.rotateRight(node);\n  }\n\n  /**\n   * Balance the '(parent) left heavy, (child) right heavy' condition\n   * @param node\n   */\n  private leftRightCase(node: TreeNode<T>) {\n    if (!node.left) {\n      throw new Error(\"leftRightCase: left child not set\");\n    }\n    node.left = this.rotateLeft(this.nodes[node.left]).id;\n    return this.rotateRight(node);\n  }\n\n  /**\n   * Balance the 'double right-heavy' condition\n   * @param node\n   */\n  private rightRightCase(node: TreeNode<T>) {\n    return this.rotateLeft(node);\n  }\n\n  /**\n   * Balance the '(parent) right heavy, (child) left heavy' condition\n   * @param node\n   */\n  private rightLeftCase(node: TreeNode<T>) {\n    if (!node.right) {\n      throw new Error(\"rightLeftCase: right child not set\");\n    }\n\n    node.right = this.rotateRight(this.nodes[node.right]).id;\n    return this.rotateLeft(node);\n  }\n\n  /**\n   * Left rotation of node. Swaps right child into current location.\n   * @param node\n   */\n  private rotateLeft(node: TreeNode<T>) {\n    if (!node.right) {\n      throw new Error(\"rotateLeft: right child was unavailable.\");\n    }\n\n    let parent = (node.parent) ? this.nodes[node.parent] : null;\n    let right = this.nodes[node.right];\n\n    // assume rights (old) left branch as our (new) right branch\n    node.right = right.left;\n    if (node.right) {\n      this.nodes[node.right].parent = node.id;\n    }\n\n    // right will be new parent to node and assume old node's parent\n    right.left = node.id;\n    right.parent = node.parent;\n    node.parent = right.id;\n\n    // remap parent child pointer to right\n    if (parent) {\n      if (parent.left === node.id) {\n        parent.left = right.id;\n      }\n      else if (parent.right === node.id) {\n        parent.right = right.id;\n      }\n      else {\n        throw new Error(\"rotateLeft() : attempt to remap parent back to child failed... not found\");\n      }\n    }\n    else {\n      if (this.apex !== node.id) {\n        throw new Error(\"rightRotate expecting parentless node to be apex\");\n      }\n\n      this.apex = right.id;\n    }\n\n    // recalculate height and balance for swapped nodes\n    this.updateBalance(node);\n    this.updateBalance(right);\n\n    return right;\n  }\n\n  /**\n   * Right rotation of node. Swaps left child into current location.\n   * @param node\n   */\n  private rotateRight(node: TreeNode<T>) {\n    if (!node.left) {\n      throw new Error(\"rotateRight : left child unavailable\");\n    }\n\n    let parent = (node.parent) ? this.nodes[node.parent] : null;\n    let left = this.nodes[node.left];\n\n    // assume left's (old) right branch as our (new) left branch\n    node.left = left.right;\n    if (left.right) {\n      this.nodes[left.right].parent = node.id;\n    }\n\n    // 'node' will be right child of left\n    left.right = node.id;\n    left.parent = node.parent;\n    node.parent = left.id;\n\n    if (parent) {\n      if (parent.left === node.id) {\n        parent.left = left.id;\n      }\n      else {\n        parent.right = left.id;\n      }\n    }\n    else {\n      if (this.apex !== node.id) {\n        throw new Error(\"rightRotate expecting parentless node to be apex\");\n      }\n\n      this.apex = left.id;\n    }\n\n    // recalculate height and balance for swapped nodes\n    this.updateBalance(node);\n    this.updateBalance(left);\n\n    return left;\n  }\n\n  /**\n   * Diagnostic method for examining tree contents and structure\n   * @param node\n   */\n  getValuesAsTree(node?: TreeNode<T>): any {\n    if (this.apex === null) return null;\n\n    node = node || this.nodes[this.apex];\n\n    return {\n      id: node.id,\n      val: node.value,\n      siblings: node.siblings,\n      balance: node.balance,\n      height: node.height,\n      left: node.left ? this.getValuesAsTree(this.nodes[node.left]) : null,\n      right: node.right ? this.getValuesAsTree(this.nodes[node.right]) : null,\n    };\n  }\n\n  /**\n   * Updates a value, possibly relocating it, within binary tree\n   * @param id Unique Id (such as $loki) to associate with value\n   * @param val New value to be indexed within binary tree\n   */\n  update(id: number, val: T) {\n    let node = this.nodes[id];\n    let cmp = this.comparator(node.value, val);\n\n    // if the value did not change, or changed to value considered equal to itself, return.\n    if (cmp === 0) return;\n\n    this.remove(id);\n    this.insert(id, val);\n  }\n\n  /**\n   * Removes a value from the binary tree index\n   * @param id\n   */\n  remove(id: number) {\n    if (!this.apex) {\n      throw new Error(\"remove() : attempting remove when tree has no apex\");\n    }\n\n    this.removeNode(this.nodes[this.apex], id);\n  }\n\n  /**\n   * Recursive node removal and rebalancer\n   * @param node\n   * @param val\n   */\n  private removeNode(node: TreeNode<T>, id: number) {\n    if (!this.nodes[id]) {\n      throw new Error(\"removeNode: attempting to remove a node which is not in hashmap\");\n    }\n    let val: T = this.nodes[id].value;\n\n    switch (this.comparator(val, node.value)) {\n      case 0:\n        // eq - handle siblings if present\n        if (node.siblings.length > 0) {\n          // if node to remove is alpha sibling...\n          if (node.id === id) {\n            // get first sibling as replacement\n            let alphaSiblingId: number = <number> node.siblings.shift();\n            let alphaSibling: TreeNode<T> = this.nodes[alphaSiblingId];\n\n            // remap all properties but id and value from node onto alphasibling\n            alphaSibling.parent = node.parent;\n            this.updateChildLink(node.parent, id, alphaSiblingId);\n            if (node.left) {\n              this.nodes[node.left].parent = alphaSiblingId;\n            }\n            if (node.right) {\n              this.nodes[node.right].parent = alphaSiblingId;\n            }\n            alphaSibling.left = node.left;\n            alphaSibling.right = node.right;\n            alphaSibling.siblings = node.siblings;\n            alphaSibling.height = node.height;\n            alphaSibling.balance = node.balance;\n            if (this.apex === id) {\n              this.apex = alphaSiblingId;\n            }\n\n            // parent all remaining siblings alphaSibling (new parent)\n            for (let si of alphaSibling.siblings) {\n              this.nodes[si].parent = alphaSiblingId;\n            }\n\n            // delete old node from nodes and return\n            delete this.nodes[id];\n            return;\n          }\n          // else we are inner sibling\n          else {\n            let idx = node.siblings.indexOf(id);\n            if (idx === -1) {\n              throw new Error(\"Unable to remove sibling from parented sibling\");\n            }\n            node.siblings.splice(idx, 1);\n            delete this.nodes[id];\n            return;\n          }\n        }\n        // else we have no siblings, node will be removed\n        else {\n          // if node to delete has no children\n          if (!node.left && !node.right) {\n            // if we have a parent, remove us from either left or right child link\n            this.updateChildLink(node.parent, node.id, null);\n            delete this.nodes[id];\n            if (id === this.apex) {\n              this.apex = null;\n            }\n            return;\n          }\n\n          // if node to delete has only one child we can do simple copy/replace\n          if (!node.left || !node.right) {\n            if (node.left) {\n              this.promoteChild(node, this.nodes[node.left]);\n              if (this.apex === id) {\n                this.apex = node.left;\n              }\n            }\n\n            if (node.right) {\n              this.promoteChild(node, this.nodes[node.right]);\n              if (this.apex === id) {\n                this.apex = node.right;\n              }\n            }\n\n            return;\n          }\n\n          // node to delete has two children, need swap with inorder successor\n          // use find inorder successor by default\n          this.promoteSuccessor(node);\n          return;\n        }\n      case 1:\n        // gt - search right branch\n\n        if (!node.right) {\n          throw new Error(\"removeNode: Unable to find value in tree\");\n        }\n\n        this.removeNode(this.nodes[node.right], id);\n\n        break;\n      case -1:\n        // lt - search left branch\n\n        if (!node.left) {\n          throw new Error(\"removeNode: Unable to find value in tree\");\n        }\n\n        this.removeNode(this.nodes[node.left], id);\n\n        break;\n    }\n\n    this.updateBalance(node);\n\n    if (node.balance < -1) {\n      if (node.left === null) {\n        throw new Error(\"insertNode.balance() : left child should not be null\");\n      }\n      if (this.nodes[node.left].balance <= 0) {\n        this.leftLeftCase(node);\n      }\n      else {\n        this.leftRightCase(node);\n      }\n    }\n\n    if (node.balance > 1) {\n      if (node.right === null) {\n        throw new Error(\"insertNode.balance() : right child should not be null\");\n      }\n      if (this.nodes[node.right].balance >= 0) {\n        this.rightRightCase(node);\n      }\n      else {\n        this.rightLeftCase(node);\n      }\n    }\n\n  }\n\n  /**\n   * Utility method for updating a parent's child link when it changes\n   * @param parentId\n   * @param oldChildId\n   * @param newChildId\n   */\n  private updateChildLink(parentId: number | null, oldChildId: number, newChildId: number | null) {\n    if (parentId === null) return;\n\n    let parent = this.nodes[parentId];\n\n    if (parent.left === oldChildId) {\n      parent.left = newChildId;\n    }\n    else if (parent.right === oldChildId) {\n      parent.right = newChildId;\n    }\n  }\n\n  /**\n   * When removing a parent with only child, this does simple remap of child to grandParent.\n   * @param grandParent New parent of 'child'.\n   * @param parent Node being removed.\n   * @param child Node to reparent to grandParent.\n   */\n  private promoteChild(parent: TreeNode<T>, child: TreeNode<T>) {\n    let gpId = parent.parent;\n    if (gpId) {\n      let gp = this.nodes[gpId];\n      if (gp.left === parent.id) {\n        gp.left = child.id;\n      }\n      else if (gp.right === parent.id) {\n        gp.right = child.id;\n      }\n    }\n    // remap (grand) child's parent pointer to grandparent (new parent) or null if new apex\n    child.parent = gpId;\n\n    // remove parent from bst hashmap\n    delete this.nodes[parent.id];\n    return;\n  }\n\n  /**\n   * Finds a successor to a node and replaces that node with it.\n   * @param node\n   */\n  private promoteSuccessor(node: TreeNode<T>) {\n    let oldId = node.id;\n\n    // assume successor/right branch (for now)\n    if (!node.right || !node.left) {\n      throw new Error(\"promoteSuccessor() : node to replace does not have two children\");\n    }\n\n    let successor: TreeNode<T> | null = null;\n    let glsId: number;\n    let glsValue: T;\n    let glsSiblings: number[];\n\n    // if tree is already left heavy,\n    // let's replace with predecessor (greatest val in left branch)\n    if (node.balance < 0) {\n      let lchild = this.nodes[node.left];\n      successor = this.findGreaterLeaf(lchild);\n      glsId = successor.id;\n      glsValue = successor.value;\n      glsSiblings = successor.siblings;\n      successor.siblings = [];\n      this.removeNode(lchild, glsId);\n    }\n    // otherwise the tree is either balanced or right heavy,\n    // so let's use sucessor (least value in right branch)\n    else {\n      let rchild = this.nodes[node.right];\n      successor = this.findLesserLeaf(rchild);\n      glsId = successor.id;\n      glsValue = successor.value;\n      glsSiblings = successor.siblings;\n      // dont leave any siblings when we (temporarily) 'remove' or they will assume ownership of old node\n      successor.siblings = [];\n      this.removeNode(rchild, glsId);\n    }\n\n    // update any parent pointers to node being replaced\n    if (node.parent) {\n      let p = this.nodes[node.parent];\n      if (p.left === oldId) p.left = glsId;\n      if (p.right === oldId) p.right = glsId;\n    }\n\n    // update any child points to node being replaced\n    if (node.left) this.nodes[node.left].parent = glsId;\n    if (node.right) this.nodes[node.right].parent = glsId;\n\n    // update (reuse) node instance id and value with that of successor\n    node.id = glsId;\n    node.value = glsValue;\n    node.siblings = glsSiblings;\n\n    // update hashmap\n    this.nodes[glsId] = node;\n    delete this.nodes[oldId];\n\n    // if old was apex, update apex to point to successor\n    if (this.apex === oldId) this.apex = glsId;\n\n    this.updateBalance(node);\n  }\n\n  /**\n   * Utility method for finding In-Order predecessor to the provided node\n   * @param node Parent node to find leaf node of greatest 'value'\n  */\n  private findGreaterLeaf(node: TreeNode<T>): TreeNode<T> {\n    if (!node.right) {\n      return node;\n    }\n\n    let result: TreeNode<T> = this.findGreaterLeaf(this.nodes[node.right]);\n\n    return result ? result : node;\n  }\n\n  /**\n   * Utility method for finding In-Order successor to the provided node\n   * @param node Parent Node to find leaf node of least 'value'\n   */\n  private findLesserLeaf(node: TreeNode<T>): TreeNode<T> {\n    if (!node.left) {\n      return node;\n    }\n\n    let result: TreeNode<T> = this.findLesserLeaf(this.nodes[node.left]);\n\n    return result ? result : node;\n  }\n\n  /**\n   *  Interface method to support ranged queries.  Results sorted by index property.\n   * @param range Options for ranged request.\n   */\n  rangeRequest(range?: IRangedIndexRequest<T>): number[] {\n    if (!this.apex) return [];\n\n    // if requesting all id's sorted by their value\n    if (!range) {\n      return this.collateIds(this.nodes[this.apex]);\n    }\n\n    if (range.op === \"$eq\") {\n      let match = this.locate(this.nodes[this.apex], range.val);\n      if (match === null) {\n        return [];\n      }\n\n      if (match.siblings.length) {\n        return [match.id, ...match.siblings];\n      }\n\n      return [match.id];\n    }\n\n    let result = this.collateRequest(this.nodes[this.apex], range);\n\n    return result;\n  }\n\n  /**\n   * Implements ranged request operations.\n   * @param node\n   * @param range\n   */\n  private collateRequest(node: TreeNode<T>, range: IRangedIndexRequest<T>): number[] {\n    let result: number[] = [];\n\n    if (range.op === \"$eq\") {\n      // we use locate instead for $eq range requests\n      throw new Error(\"collateRequest does not support $eq range request\");\n    }\n\n    let cmp1: number = this.comparator(node.value, range.val);\n    let cmp2: number = 0;\n\n    if (range.op === \"$between\") {\n      if (range.high === null || range.high === undefined) {\n        throw new Error(\"collateRequest: $between request missing high range value\");\n      }\n      cmp2 = this.comparator(node.value, range.high);\n    }\n\n    if (node.left) {\n      switch (range.op) {\n        case \"$lt\":\n        case \"$lte\":\n          result = this.collateRequest(this.nodes[node.left], range);\n          break;\n        case \"$gt\":\n        case \"$gte\":\n          // if the current node is still greater than compare value,\n          // it's possible left child will be too\n          if (cmp1 === 1) {\n            result = this.collateRequest(this.nodes[node.left], range);\n          }\n          break;\n        case \"$between\":\n          // only pursue left path if current node greater than (low) range val\n          if (cmp1 === 1) {\n            result = this.collateRequest(this.nodes[node.left], range);\n          }\n          break;\n        default: break;\n      }\n    }\n\n    if (!range) {\n      result.push(node.id);\n      result.push(...node.siblings);\n    }\n    else {\n      switch (range.op) {\n        case \"$lt\":\n          if (cmp1 === -1) {\n            result.push(node.id);\n            result.push(...node.siblings);\n          }\n          break;\n        case \"$lte\":\n          if (cmp1 === -1 || cmp1 === 0) {\n            result.push(node.id);\n            result.push(...node.siblings);\n          }\n          break;\n        case \"$gt\":\n          if (cmp1 === 1) {\n            result.push(node.id);\n            result.push(...node.siblings);\n          }\n          break;\n        case \"$gte\":\n          if (cmp1 === 1 || cmp1 === 0) {\n            result.push(node.id);\n            result.push(...node.siblings);\n          }\n          break;\n        case \"$between\":\n          if (cmp1 >= 0 && cmp2 <= 0) {\n            result.push(node.id);\n            result.push(...node.siblings);\n          }\n          break;\n        default: break;\n      }\n    }\n\n    if (node.right) {\n      if (!range) {\n        result.push(...this.collateRequest(this.nodes[node.right], range));\n      }\n      else {\n        switch (range.op) {\n          case \"$lt\":\n          case \"$lte\":\n            // if the current node is still less than compare value,\n            // it's possible right child will be too\n            if (cmp1 === -1) {\n              result.push(...this.collateRequest(this.nodes[node.right], range));\n            }\n            break;\n          case \"$gt\":\n          case \"$gte\":\n            result.push(...this.collateRequest(this.nodes[node.right], range));\n            break;\n          case \"$between\":\n            // only pursue right path if current node less than (high) range val\n            if (cmp2 === -1) {\n              result.push(...this.collateRequest(this.nodes[node.right], range));\n            }\n            break;\n          default: break;\n        }\n      }\n    }\n\n    return result;\n  }\n\n  /**\n   * Used on a branch node to return an array of id within that branch, sorted by their value\n   * @param node\n   */\n  private collateIds(node: TreeNode<T>): number[] {\n    let result: number[] = [];\n\n    // debug diagnostic\n    if (!node) {\n      return [];\n    }\n\n    if (node.left) {\n      result = this.collateIds(this.nodes[node.left]);\n    }\n\n    result.push(node.id);\n    result.push(...node.siblings);\n\n    if (node.right) {\n      result.push(...this.collateIds(this.nodes[node.right]));\n    }\n\n    return result;\n  }\n\n  /**\n   * Traverses tree to a node matching the provided value.\n   * @param node\n   * @param val\n   */\n  /*\n  private locate(node: TreeNode<T>, val: any): TreeNode<T> {\n     switch (this.comparator.compare(val, node.value)) {\n        case 0: return node;\n        case 1:\n           if (!node.right) {\n              return null;\n           }\n\n           return this.locate(this.nodes[node.right], val);\n        case -1:\n           if (!node.left) {\n              return null;\n           }\n\n           return this.locate(this.nodes[node.left], val);\n     }\n  }\n  */\n\n  /**\n   * Inline/Non-recusive 'single value' ($eq) lookup.\n   * Traverses tree to a node matching the provided value.\n   * @param node\n   * @param val\n   */\n  private locate(node: TreeNode<T>, val: T): TreeNode<T> | null {\n    while (node !== null) {\n      switch (this.comparator(val, node.value)) {\n        case 0: return node;\n        case 1:\n          if (!node.right) {\n            return null;\n          }\n\n          node = this.nodes[node.right];\n          break;\n        case -1:\n          if (!node.left) {\n            return null;\n          }\n\n          node = this.nodes[node.left];\n          break;\n      }\n    }\n\n    return null;\n  }\n\n  /**\n   * Index integrity check (IRangedIndex interface function)\n   */\n  validateIndex(): boolean {\n    // handle null apex condition and verify empty tree and nodes\n    if (!this.apex) {\n      if (Object.keys(this.nodes).length !== 0) {\n        return false;\n      }\n      return true;\n    }\n\n    // ensure apex has no parent\n    if (this.nodes[this.apex].parent !== null) {\n      return false;\n    }\n\n    // high level verification - retrieve all node ids ordered by their values\n    let result: number[] = this.collateIds(this.nodes[this.apex]);\n    let nc = Object.keys(this.nodes).length;\n    // verify the inorder traversal returned same number of elements as nodes hashmap\n    if (result.length !== nc) {\n      return false;\n    }\n    // if only one result\n    if (result.length === 1) {\n      if (this.nodes[result[0]].parent !== null) return false;\n      if (this.nodes[result[0]].left !== null) return false;\n      if (this.nodes[result[0]].right !== null) return false;\n\n      return true;\n    }\n\n    // iterate results and ensure next value is greater or equal to current\n    for (let i = 0; i < result.length - 1; i++) {\n      if (this.comparator(this.nodes[result[i]].value, this.nodes[result[i + 1]].value) === 1) {\n        return false;\n      }\n\n    }\n\n    return this.validateNode(this.nodes[this.apex]);\n  }\n\n  /**\n   * Recursive Node validation routine\n   * @param node\n   */\n  private validateNode(node: TreeNode<T>): boolean {\n    // should never have parent or child pointers reference self\n    if ([node.parent, node.left, node.right].indexOf(node.id) !== -1) {\n      return false;\n    }\n\n    // validate height and balance\n    let hl = (node.left) ? this.nodes[node.left].height : -1;\n    let hr = (node.right) ? this.nodes[node.right].height : -1;\n    let eh = 1 + Math.max(hl, hr);\n    if (node.height !== eh) {\n      return false;\n    }\n    if (node.balance !== hr - hl) {\n      return false;\n    }\n\n    // verify any siblings parent back to self\n    if (node.siblings.length > 0) {\n      for (let sid of node.siblings) {\n        if (this.nodes[sid].parent !== node.id) return false;\n      }\n    }\n\n    // if there is a left child, verify it parents to self and recurse it\n    if (node.left) {\n      if (this.nodes[node.left].parent !== node.id) {\n        return false;\n      }\n      if (!this.validateNode(this.nodes[node.left])) {\n        return false;\n      }\n    }\n\n    // if there is a right child, verify it parents to self and recurse it\n    if (node.right) {\n      if (this.nodes[node.right].parent !== node.id) {\n        return false;\n      }\n\n      if (!this.validateNode(this.nodes[node.right])) {\n        return false;\n      }\n    }\n\n    return true;\n  }\n}\n"
  },
  {
    "path": "packages/loki/src/clone.ts",
    "content": "export type CloneMethod = \"parse-stringify\" | \"deep\" | \"shallow\" | \"shallow-recurse\";\n\nfunction add(copy: any, key: any, value: any): any {\n  if (copy instanceof Array) {\n    copy.push(value);\n    return copy[copy.length - 1];\n  } else if (copy instanceof Object) {\n    copy[key] = value;\n    return copy[key];\n  }\n}\n\nfunction walk(target: any, copy: any): void {\n  for (let key in target) {\n    let obj = target[key];\n    if (obj instanceof Date) {\n      let value = new Date(obj.getTime());\n      add(copy, key, value);\n    } else if (obj instanceof Function) {\n      let value = obj;\n      add(copy, key, value);\n    } else if (obj instanceof Array) {\n      let value: any[] = [];\n      let last = add(copy, key, value);\n      walk(obj, last);\n    } else if (obj instanceof Object) {\n      let value = {};\n      let last = add(copy, key, value);\n      walk(obj, last);\n    } else {\n      let value = obj;\n      add(copy, key, value);\n    }\n  }\n}\n\n// Deep copy from Simeon Velichkov.\n/**\n * @param target\n * @returns {any}\n */\nfunction deepCopy(target: any) {\n  if (/number|string|boolean/.test(typeof target)) {\n    return target;\n  } else if (target instanceof Date) {\n    return new Date(target.getTime());\n  }\n\n  const copy = (target instanceof Array) ? [] : {};\n  walk(target, copy);\n  return copy;\n}\n\n/**\n * @hidden\n */\nexport function clone<T>(data: T, method: CloneMethod = \"parse-stringify\"): T {\n  if (data === null || data === undefined) {\n    return null;\n  }\n\n  let cloned: any;\n\n  switch (method) {\n    case \"parse-stringify\":\n      cloned = JSON.parse(JSON.stringify(data));\n      break;\n    case \"deep\":\n      cloned = deepCopy(data);\n      break;\n    case \"shallow\":\n      cloned = Object.create(data.constructor.prototype);\n      Object.assign(cloned, data);\n      break;\n    case \"shallow-recurse\":\n      // shallow clone top level properties\n      cloned = clone(data, \"shallow\");\n      const keys = Object.keys(data);\n      // for each of the top level properties which are object literals, recursively shallow copy\n      for (let i = 0; i < keys.length; i++) {\n        const key = keys[i];\n        if (typeof data[key] === \"object\" && data[key].constructor.name === \"Object\") {\n          cloned[key] = clone(data[key], \"shallow-recurse\");\n        }\n      }\n      break;\n    default:\n      break;\n  }\n\n  return cloned as any as T;\n}\n"
  },
  {
    "path": "packages/loki/src/collection.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { UniqueIndex } from \"./unique_index\";\nimport { ResultSet } from \"./result_set\";\nimport { DynamicView } from \"./dynamic_view\";\nimport { IRangedIndex, RangedIndexFactoryMap } from \"./ranged_indexes\";\nimport { ComparatorMap } from \"./comparators\";\nimport { clone, CloneMethod } from \"./clone\";\nimport { Doc, Dict } from \"../../common/types\";\nimport { FullTextSearch } from \"../../full-text-search/src/full_text_search\";\nimport { PLUGINS } from \"../../common/plugin\";\nimport { Analyzer } from \"../../full-text-search/src/analyzer/analyzer\";\n\nfunction average(array: number[]): number {\n  return (array.reduce((a, b) => a + b, 0)) / array.length;\n}\n\nfunction standardDeviation(values: number[]): number {\n  const avg = average(values);\n  const squareDiffs = values.map((value) => {\n    const diff = value - avg;\n    return diff * diff;\n  });\n\n  const avgSquareDiff = average(squareDiffs);\n  return Math.sqrt(avgSquareDiff);\n}\n\n/**\n * Returns an array with the value of a nested property of an object.\n * Returns an array of values if the nested property is across child arrays.\n * @param {object} obj - the object\n * @param {string[]} path - the path of the nested property\n * @param {any[]} array - the result array\n * @param {number} pathIdx - the current path idx\n * @returns {boolean} true if nested property is across child arrays, otherwise false\n */\nfunction getNestedPropertyValue(obj: object, path: string[], array: any[], pathIdx: number = 0): boolean {\n  if (obj === undefined) {\n    return false;\n  }\n\n  if (pathIdx + 1 === path.length) {\n    array.push(obj[path[pathIdx]]);\n    return false;\n  }\n\n  const curr = obj[path[pathIdx]];\n  if (Array.isArray(curr)) {\n    for (let i = 0; i < curr.length; i++) {\n      getNestedPropertyValue(curr[i], path, array, pathIdx + 1);\n    }\n    return true;\n  } else {\n    return getNestedPropertyValue(curr, path, array, pathIdx + 1);\n  }\n}\n\n/**\n * Collection class that handles documents of same type\n * @extends LokiEventEmitter\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport class Collection<TData extends object = object, TNested extends object = object, T extends TData & TNested = TData & TNested> extends LokiEventEmitter {\n  // the name of the collection\n  public name: string;\n  // the data held by the collection\n  public _data: Doc<T>[] = [];\n  // index of id\n  private _idIndex: number[] = [];\n  // user defined indexes\n  public _rangedIndexes: { [P in keyof T]?: Collection.RangedIndexMeta } = {};\n  // loki obj map\n  public _lokimap: { [$loki : number]: Doc<T> } = {};\n  // default comparator name to use for unindexed sorting\n  public _unindexedSortComparator: string = \"js\";\n  // default LokiOperatorPackage ('default' uses fastest 'javascript' comparisons)\n  public _defaultLokiOperatorPackage: string = \"js\";\n\n  /**\n   * Unique constraints contain duplicate object references, so they are not persisted.\n   * We will keep track of properties which have unique constraints applied here, and regenerate on load.\n   */\n  public _constraints: {\n    unique: {\n      [P in keyof T]?: UniqueIndex;\n    }\n  } = {unique: {}};\n\n  /**\n   * Transforms will be used to store frequently used query chains as a series of steps which itself can be stored along\n   * with the database.\n   */\n  public _transforms: Dict<Collection.Transform<T>[]> = {};\n\n  /**\n   * In autosave scenarios we will use collection level dirty flags to determine whether save is needed.\n   * currently, if any collection is dirty we will autosave the whole database if autosave is configured.\n   * Defaulting to true since this is called from addCollection and adding a collection should trigger save.\n   */\n  public _dirty: boolean = true;\n\n  // private holder for cached data\n  private _cached: {\n    index: number[];\n    data: Doc<T>[];\n    rangedIndexes: { [name: string]: Collection.RangedIndexMeta };\n  } = null;\n\n  /**\n   * Is collection transactional.\n   */\n  private _transactional: boolean;\n\n  /**\n   * Options to clone objects when inserting them.\n   */\n  public _cloneObjects: boolean;\n\n  /**\n   * Default clone method (if enabled) is parse-stringify.\n   */\n  public _cloneMethod: CloneMethod;\n\n  /**\n   * If set to true we will not maintain a meta property for a document.\n   */\n  private _disableMeta: boolean;\n\n  /**\n   * Disable track changes.\n   */\n  private _disableChangesApi: boolean;\n\n  /**\n   * Disable delta update object style on changes.\n   */\n  public _disableDeltaChangesApi: boolean;\n\n  /**\n   * By default, if you insert a document with a Date value for an indexed property, we will convert that value to number.\n   */\n  private _serializableIndexes: boolean;\n\n  /**\n   * Name of path of used nested properties.\n   */\n  private _nestedProperties: { name: keyof TNested, path: string[] }[] = [];\n\n  /**\n   * Option to activate a cleaner daemon - clears \"aged\" documents at set intervals.\n   */\n  public _ttl: Collection.TTL = {\n    age: null,\n    ttlInterval: null,\n    daemon: null\n  };\n\n  // currentMaxId - change manually at your own peril!\n  private _maxId: number = 0;\n  private _dynamicViews: DynamicView<T>[] = [];\n\n  /**\n   * Changes are tracked by collection and aggregated by the db.\n   */\n  private _changes: Collection.Change[] = [];\n\n  /**\n   * stages: a map of uniquely identified 'stages', which hold copies of objects to be\n   * manipulated without affecting the data in the original collection\n   */\n  private _stages: object = {};\n  private _commitLog: { timestamp: number; message: string; data: any }[] = [];\n\n  public _fullTextSearch: FullTextSearch;\n\n  /**\n   * @param {string} name - collection name\n   * @param {(object)} [options={}] - a configuration object\n   * @param {string[]} [options.unique=[]] - array of property names to define unique constraints for\n   * @param {string[]} [options.exact=[]] - array of property names to define exact constraints for\n   * @param {RangedIndexOptions} [options.rangedIndexes] - configuration object for ranged indexes\n   * @param {boolean} [options.asyncListeners=false] - whether listeners are invoked asynchronously\n   * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n   * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes API\n   * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n   * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n   * @param {boolean} [options.serializableIndexes=true] - converts date values on binary indexed property values are serializable\n   * @param {string} [options.cloneMethod=\"deep\"] - the clone method\n   * @param {number} [options.transactional=false] - ?\n   * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale.\n   * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n   * @param {string} [options.unindexedSortComparator=\"js\"] \"js\", \"abstract\", \"abstract-date\", \"loki\" or other registered comparator name\n   * @param {string} [options.defaultLokiOperatorPackage=\"js\"] \"js\", \"loki\", \"comparator\" (or user defined) query ops package\n   * @param {FullTextSearch.FieldOptions} [options.fullTextSearch=] - the full-text search options\n   * @see {@link Loki#addCollection} for normal creation of collections\n   */\n  constructor(name: string, options: Collection.Options<TData, TNested> = {}) {\n    super();\n\n    // Consistency checks.\n    if (options && options.disableMeta === true) {\n      if (options.disableChangesApi === false) {\n        throw new Error(\"disableMeta option cannot be passed as true when disableChangesApi is passed as false\");\n      }\n      if (options.disableDeltaChangesApi === false) {\n        throw new Error(\"disableMeta option cannot be passed as true when disableDeltaChangesApi is passed as false\");\n      }\n      if (typeof options.ttl === \"number\" && options.ttl > 0) {\n        throw new Error(\"disableMeta option cannot be passed as true when ttl is enabled\");\n      }\n    }\n\n    // the name of the collection\n    this.name = name;\n\n    /* OPTIONS */\n    this._unindexedSortComparator = options.unindexedSortComparator || \"js\";\n    this._defaultLokiOperatorPackage = options.defaultLokiOperatorPackage || \"js\";\n\n    // exact match and unique constraints\n    if (options.unique !== undefined) {\n      if (!Array.isArray(options.unique)) {\n        options.unique = [options.unique];\n      }\n      options.unique.forEach((prop) => {\n        this._constraints.unique[prop] = new UniqueIndex(prop as string);\n      });\n    }\n\n    // Full text search\n    if (PLUGINS[\"FullTextSearch\"] !== undefined) {\n      this._fullTextSearch = options.fullTextSearch !== undefined\n        ? new (PLUGINS[\"FullTextSearch\"])(options.fullTextSearch) : null;\n    } else {\n      this._fullTextSearch = null;\n    }\n\n    // .\n    this._transactional = options.transactional !== undefined ? options.transactional : false;\n\n    // .\n    this._cloneObjects = options.clone !== undefined ? options.clone : false;\n\n    // .\n    this._asyncListeners = options.asyncListeners !== undefined ? options.asyncListeners : false;\n\n    // .\n    this._disableMeta = options.disableMeta !== undefined ? options.disableMeta : false;\n\n    // .\n    this._disableChangesApi = options.disableChangesApi !== undefined ? options.disableChangesApi : true;\n\n    // .\n    this._disableDeltaChangesApi = options.disableDeltaChangesApi !== undefined ? options.disableDeltaChangesApi : true;\n\n    // .\n    this._cloneMethod = options.cloneMethod !== undefined ? options.cloneMethod : \"deep\";\n    if (this._disableChangesApi) {\n      this._disableDeltaChangesApi = true;\n    }\n\n    // .\n    this._serializableIndexes = options.serializableIndexes !== undefined ? options.serializableIndexes : true;\n\n    // .\n    if (options.nestedProperties != undefined) {\n      for (let i = 0; i < options.nestedProperties.length; i++) {\n        const nestedProperty = options.nestedProperties[i];\n        if (typeof nestedProperty === \"string\") {\n          this._nestedProperties.push({name: nestedProperty, path: nestedProperty.split(\".\")});\n        } else {\n          this._nestedProperties.push(nestedProperty as { name: keyof TNested, path: string[] });\n        }\n      }\n    }\n\n    this.setTTL(options.ttl || -1, options.ttlInterval);\n\n    // events\n    this._events = {\n      \"insert\": [],\n      \"update\": [],\n      \"pre-insert\": [],\n      \"pre-update\": [],\n      \"close\": [],\n      \"flushbuffer\": [],\n      \"error\": [],\n      \"delete\": [],\n      \"warning\": []\n    };\n\n    // initialize the id index\n    this._ensureId();\n    let rangedIndexes: Collection.RangedIndexOptions = options.rangedIndexes || {};\n    for (let ri in rangedIndexes) {\n      // Todo: any way to type annotate this as typesafe generic?\n      this.ensureRangedIndex(ri, rangedIndexes[ri].indexTypeName, rangedIndexes[ri].comparatorName);\n    }\n\n    this.setChangesApi(this._disableChangesApi, this._disableDeltaChangesApi);\n\n    // for de-serialization purposes\n    this.flushChanges();\n  }\n\n  toJSON(): Collection.Serialized {\n    return {\n      name: this.name,\n      unindexedSortComparator: this._unindexedSortComparator,\n      defaultLokiOperatorPackage: this._defaultLokiOperatorPackage,\n      _dynamicViews: this._dynamicViews,\n      uniqueNames: Object.keys(this._constraints.unique),\n      transforms: this._transforms as any,\n      rangedIndexes: this._rangedIndexes as any,\n      _data: this._data,\n      idIndex: this._idIndex,\n      maxId: this._maxId,\n      _dirty: this._dirty,\n      _nestedProperties: this._nestedProperties,\n      transactional: this._transactional,\n      asyncListeners: this._asyncListeners,\n      disableMeta: this._disableMeta,\n      disableChangesApi: this._disableChangesApi,\n      disableDeltaChangesApi: this._disableDeltaChangesApi,\n      cloneObjects: this._cloneObjects,\n      cloneMethod: this._cloneMethod,\n      changes: this._changes,\n      _fullTextSearch: this._fullTextSearch\n    };\n  }\n\n  static fromJSONObject(obj: Collection.Serialized, options?: Collection.DeserializeOptions) {\n    // instantiate collection with options needed by constructor\n    let coll = new Collection<any>(obj.name, {\n      disableChangesApi: obj.disableChangesApi,\n      disableDeltaChangesApi: obj.disableDeltaChangesApi,\n      unindexedSortComparator: obj.unindexedSortComparator,\n      defaultLokiOperatorPackage: obj.defaultLokiOperatorPackage\n    });\n\n    coll._transactional = obj.transactional;\n    coll._asyncListeners = obj.asyncListeners;\n    coll._disableMeta = obj.disableMeta;\n    coll._disableChangesApi = obj.disableChangesApi;\n    coll._cloneObjects = obj.cloneObjects;\n    coll._cloneMethod = obj.cloneMethod || \"deep\";\n    coll._changes = obj.changes;\n    coll._nestedProperties = obj._nestedProperties as any[];\n    coll._rangedIndexes = obj.rangedIndexes || {};\n\n    coll._dirty = (options && options.retainDirtyFlags === true) ? obj._dirty : false;\n\n    function makeLoader(coll: Collection.Serialized) {\n      const collOptions = options[coll.name];\n\n      if (collOptions.proto) {\n        const inflater = collOptions.inflate || ((src: Doc<any>, dest: Doc<any>) => {\n          for (let prop in src) {\n            dest[prop] = src[prop];\n          }\n        });\n\n        return (data: Doc<any>) => {\n          const collObj = new (collOptions.proto)();\n          inflater(data, collObj);\n          return collObj;\n        };\n      }\n\n      return collOptions.inflate;\n    }\n\n    // load each element individually\n    if (options && options[obj.name] !== undefined) {\n      let loader = makeLoader(obj);\n\n      for (let j = 0; j < obj._data.length; j++) {\n        coll._data[j] = coll._defineNestedProperties(loader(obj._data[j]));\n        // regenerate lokimap\n        coll._lokimap[coll._data[j].$loki] = coll._data[j];\n      }\n    } else {\n      for (let j = 0; j < obj._data.length; j++) {\n        coll._data[j] = coll._defineNestedProperties(obj._data[j]);\n        // regenerate lokimap\n        coll._lokimap[coll._data[j].$loki] = coll._data[j];\n      }\n    }\n\n    coll._maxId = (obj.maxId === undefined) ? 0 : obj.maxId;\n    coll._idIndex = obj.idIndex;\n    if (obj.transforms !== undefined) {\n      coll._transforms = obj.transforms;\n    }\n\n    // inflate rangedindexes\n    for (let ri in obj.rangedIndexes) {\n      // shortcut reference to serialized meta\n      let sri = obj.rangedIndexes[ri];\n      // lookup index factory function in map based on index type name\n      let rif = RangedIndexFactoryMap[sri.indexTypeName];\n      // lookup comparator function in map based on comparator name\n      let ricmp = ComparatorMap[sri.comparatorName];\n      // using index type (from meta), index factory and comparator... create instance of ranged index\n      let rii = rif(ri, ricmp);\n      // now ask new index instance to inflate from plain object\n      rii.restore(sri.index);\n      // attach class instance to our collection's ranged index's (index) instance property\n      coll._rangedIndexes[ri].index = rii;\n    }\n\n    coll._ensureId();\n\n    // regenerate unique indexes\n    if (obj.uniqueNames !== undefined) {\n      for (let j = 0; j < obj.uniqueNames.length; j++) {\n        coll.ensureUniqueIndex(obj.uniqueNames[j]);\n      }\n    }\n\n    // in case they are loading a database created before we added dynamic views, handle undefined\n    if (obj._dynamicViews !== undefined) {\n      // reinflate DynamicViews and attached ResultSets\n      for (let idx = 0; idx < obj._dynamicViews.length; idx++) {\n        coll._dynamicViews.push(DynamicView.fromJSONObject(coll, obj._dynamicViews[idx] as any));\n      }\n    }\n\n    if (obj._fullTextSearch) {\n      coll._fullTextSearch = PLUGINS[\"FullTextSearch\"].fromJSONObject(obj._fullTextSearch, options.fullTextSearch);\n    }\n\n    return coll;\n  }\n\n  /**\n   * Adds a named collection transform to the collection\n   * @param {string} name - name to associate with transform\n   * @param {array} transform - an array of transformation 'step' objects to save into the collection\n   */\n  public addTransform(name: string, transform: Collection.Transform<T>[]): void {\n    if (this._transforms[name] !== undefined) {\n      throw new Error(\"a transform by that name already exists\");\n    }\n    this._transforms[name] = transform;\n  }\n\n  /**\n   * Retrieves a named transform from the collection.\n   * @param {string} name - name of the transform to lookup.\n   */\n  public getTransform(name: string): Collection.Transform<T>[] {\n    return this._transforms[name];\n  }\n\n  /**\n   * Updates a named collection transform to the collection\n   * @param {string} name - name to associate with transform\n   * @param {object} transform - a transformation object to save into collection\n   */\n  public setTransform(name: string, transform: Collection.Transform<T>[]): void {\n    this._transforms[name] = transform;\n  }\n\n  /**\n   * Removes a named collection transform from the collection\n   * @param {string} name - name of collection transform to remove\n   */\n  public removeTransform(name: string): void {\n    delete this._transforms[name];\n  }\n\n  /*----------------------------+\n   | TTL                        |\n   +----------------------------*/\n  private setTTL(age: number, interval: number): void {\n    if (age < 0) {\n      clearInterval(this._ttl.daemon);\n    } else {\n      this._ttl.age = age;\n      this._ttl.ttlInterval = interval;\n      this._ttl.daemon = setInterval(() => {\n        const now = Date.now();\n        const toRemove = this.chain().where((member: Doc<T>) => {\n          const timestamp = member.meta.updated || member.meta.created;\n          const diff = now - timestamp;\n          return this._ttl.age < diff;\n        });\n        toRemove.remove();\n      }, interval);\n    }\n  }\n\n  /*----------------------------+\n   | INDEXING                   |\n   +----------------------------*/\n\n  /**\n   * Create a row filter that covers all documents in the collection.\n   */\n  _prepareFullDocIndex(): number[] {\n    const indexes = new Array(this._data.length);\n    for (let i = 0; i < indexes.length; i++) {\n      indexes[i] = i;\n    }\n    return indexes;\n  }\n\n  /**\n   * Ensure rangedIndex of a field.\n   * @param field\n   * @param indexTypeName\n   * @param comparatorName\n   */\n  public ensureIndex(field: string, indexTypeName?: string, comparatorName?: string) {\n    this.ensureRangedIndex(field, indexTypeName, comparatorName);\n  }\n\n  /**\n   * Ensure rangedIndex of a field.\n   * @param field Property to create an index on (need to look into contraining on keyof T)\n   * @param indexTypeName Name of IndexType factory within (global?) hashmap to create IRangedIndex from\n   * @param comparatorName Name of Comparator within (global?) hashmap\n   */\n  public ensureRangedIndex(field: string, indexTypeName?: string, comparatorName?: string) {\n    indexTypeName = indexTypeName || \"avl\";\n    comparatorName = comparatorName || \"loki\";\n\n    if (!RangedIndexFactoryMap[indexTypeName]) {\n      throw new Error(\"ensureRangedIndex: Unknown range index type\");\n    }\n\n    if (!ComparatorMap[comparatorName]) {\n      throw new Error(\"ensureRangedIndex: Unknown comparator\");\n    }\n\n    let rif = RangedIndexFactoryMap[indexTypeName];\n    let comparator = ComparatorMap[comparatorName];\n\n    this._rangedIndexes[field] = {\n      index: rif(field, comparator),\n      indexTypeName: indexTypeName,\n      comparatorName: comparatorName\n    };\n\n    let rii = this._rangedIndexes[field].index;\n\n    for (let i = 0; i < this._data.length; i++) {\n      rii.insert(this._data[i].$loki, this._data[i][field]);\n    }\n  }\n\n  public ensureUniqueIndex(field: keyof T) {\n    let index = new UniqueIndex(field as string);\n\n    // if index already existed, (re)loading it will likely cause collisions, rebuild always\n    this._constraints.unique[field] = index;\n    for (let i = 0; i < this._data.length; i++) {\n      index.set(this._data[i].$loki, this._data[i][field]);\n    }\n    return index;\n  }\n\n  /**\n   * Quickly determine number of documents in collection (or query)\n   * @param {object} query - (optional) query object to count results of\n   * @returns {number} number of documents in the collection\n   */\n  public count(query?: ResultSet.Query<Doc<T>>): number {\n    if (!query) {\n      return this._data.length;\n    }\n    return this.chain().find(query)._filteredRows.length;\n  }\n\n  /**\n   * Rebuild idIndex\n   */\n  private _ensureId(): void {\n    this._idIndex = [];\n    for (let i = 0; i < this._data.length; i++) {\n      this._idIndex.push(this._data[i].$loki);\n    }\n  }\n\n  /**\n   * Add a dynamic view to the collection\n   * @param {string} name - name of dynamic view to add\n   * @param {object} options - (optional) options to configure dynamic view with\n   * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n   * @param {string} [options.sortPriority=SortPriority.PASSIVE] - the sort priority\n   * @param {number} options.minRebuildInterval - minimum rebuild interval (need clarification to docs here)\n   * @returns {DynamicView} reference to the dynamic view added\n   **/\n  public addDynamicView(name: string, options?: DynamicView.Options): DynamicView<T> {\n    const dv = new DynamicView<T>(this as any as Collection<T>, name, options);\n    this._dynamicViews.push(dv);\n\n    return dv;\n  }\n\n  /**\n   * Remove a dynamic view from the collection\n   * @param {string} name - name of dynamic view to remove\n   **/\n  public removeDynamicView(name: string): void {\n    for (let idx = 0; idx < this._dynamicViews.length; idx++) {\n      if (this._dynamicViews[idx].name === name) {\n        this._dynamicViews.splice(idx, 1);\n      }\n    }\n  }\n\n  /**\n   * Look up dynamic view reference from within the collection\n   * @param {string} name - name of dynamic view to retrieve reference of\n   * @returns {DynamicView} A reference to the dynamic view with that name\n   **/\n  public getDynamicView(name: string): DynamicView<T> {\n    for (let idx = 0; idx < this._dynamicViews.length; idx++) {\n      if (this._dynamicViews[idx].name === name) {\n        return this._dynamicViews[idx];\n      }\n    }\n\n    return null;\n  }\n\n  /**\n   * Applies a 'mongo-like' find query object and passes all results to an update function.\n   * @param {object} filterObject - the 'mongo-like' query object\n   * @param {function} updateFunction - the update function\n   */\n  public findAndUpdate(filterObject: ResultSet.Query<Doc<T>>, updateFunction: (obj: Doc<T>) => any) {\n    this.chain().find(filterObject).update(updateFunction);\n  }\n\n  /**\n   * Applies a 'mongo-like' find query object removes all documents which match that filter.\n   * @param {object} filterObject - 'mongo-like' query object\n   */\n  public findAndRemove(filterObject: ResultSet.Query<Doc<T>>) {\n    this.chain().find(filterObject).remove();\n  }\n\n  /**\n   * Adds object(s) to collection, ensure object(s) have meta properties, clone it if necessary, etc.\n   * @param {(object|array)} doc - the document (or array of documents) to be inserted\n   * @returns {(object|array)} document or documents inserted\n   */\n  public insert(doc: TData): Doc<T>;\n  public insert(doc: TData[]): Doc<T>[];\n  public insert(doc: TData | TData[]): Doc<T> | Doc<T>[] {\n    if (!Array.isArray(doc)) {\n      return this.insertOne(doc);\n    }\n\n    // holder to the clone of the object inserted if collections is set to clone objects\n    let obj;\n    let results = [];\n\n    this.emit(\"pre-insert\", doc);\n    for (let i = 0; i < doc.length; i++) {\n      obj = this.insertOne(doc[i], true);\n      if (!obj) {\n        return undefined;\n      }\n      results.push(obj);\n    }\n    // at the 'batch' level, if clone option is true then emitted docs are clones\n    this.emit(\"insert\", results);\n\n    // if clone option is set, clone return values\n    results = this._cloneObjects ? clone(results, this._cloneMethod) : results;\n\n    return results.length === 1 ? results[0] : results;\n  }\n\n  /**\n   * Adds a single object, ensures it has meta properties, clone it if necessary, etc.\n   * @param {object} doc - the document to be inserted\n   * @param {boolean} bulkInsert - quiet pre-insert and insert event emits\n   * @returns {object} document or 'undefined' if there was a problem inserting it\n   */\n  public insertOne(doc: TData, bulkInsert = false): Doc<T> {\n    let err = null;\n    let returnObj;\n\n    if (typeof doc !== \"object\") {\n      err = new TypeError(\"Document needs to be an object\");\n    } else if (doc === null) {\n      err = new TypeError(\"Object cannot be null\");\n    }\n\n    if (err !== null) {\n      this.emit(\"error\", err);\n      throw err;\n    }\n\n    // if configured to clone, do so now... otherwise just use same obj reference\n    const obj = this._defineNestedProperties(this._cloneObjects ? clone(doc, this._cloneMethod) : doc) as T;\n\n    if (!this._disableMeta && (obj as Doc<TData>).meta === undefined) {\n      (obj as Doc<TData>).meta = {\n        version: 0,\n        revision: 0,\n        created: 0\n      };\n    }\n\n    // both 'pre-insert' and 'insert' events are passed internal data reference even when cloning\n    // insert needs internal reference because that is where loki itself listens to add meta\n    if (!bulkInsert) {\n      this.emit(\"pre-insert\", obj);\n    }\n    if (!this._add(obj)) {\n      return undefined;\n    }\n\n    // update meta and store changes if ChangesAPI is enabled\n    // (moved from \"insert\" event listener to allow internal reference to be used)\n    if (this._disableChangesApi) {\n      this._insertMeta(obj as Doc<TData>);\n    } else {\n      this._insertMetaWithChange(obj as Doc<TData>);\n    }\n\n    // if cloning is enabled, emit insert event with clone of new object\n    returnObj = this._cloneObjects ? clone(obj, this._cloneMethod) : obj;\n    if (!bulkInsert) {\n      this.emit(\"insert\", returnObj);\n    }\n\n    return returnObj as Doc<T>;\n  }\n\n  /**\n   * Refers nested properties of an object to the root of it.\n   * @param {T} data - the object\n   * @returns {T & TNested} the object with nested properties\n   * @hidden\n   */\n  _defineNestedProperties<U extends TData>(data: U): U & TNested {\n    for (let i = 0; i < this._nestedProperties.length; i++) {\n      const name = this._nestedProperties[i].name;\n      const path = this._nestedProperties[i].path;\n      Object.defineProperty(data, name, {\n        get() {\n          // Get the value of the nested property.\n          const array: any[] = [];\n          if (getNestedPropertyValue(this, path, array)) {\n            return array;\n          } else {\n            return array[0];\n          }\n        },\n        set(val: any) {\n          // Set the value of the nested property.\n          path.slice(0, path.length - 1).reduce((obj: any, part: string) =>\n            (obj && obj[part]) ? obj[part] : null, this)[path[path.length - 1]] = val;\n        },\n        enumerable: false,\n        configurable: true\n      });\n    }\n    return data as U & TNested;\n  }\n\n  /**\n   * Empties the collection.\n   * @param {boolean} [removeIndices=false] - remove indices\n   */\n  public clear({removeIndices: removeIndices = false} = {}) {\n    this._data = [];\n    this._idIndex = [];\n    this._cached = null;\n    this._maxId = 0;\n    this._dynamicViews = [];\n    this._dirty = true;\n\n    // if removing indices entirely\n    if (removeIndices === true) {\n      this._rangedIndexes = {};\n\n      this._constraints = {\n        unique: {}\n      };\n    }\n    // clear indices but leave definitions in place\n    else {\n      // re-instance ranged indexes\n      for (let ri in this._rangedIndexes) {\n        this.ensureRangedIndex(ri, this._rangedIndexes[ri].indexTypeName, this._rangedIndexes[ri].comparatorName);\n      }\n\n      // clear entire unique indices definition\n      const uniqueNames = Object.keys(this._constraints.unique);\n      for (let i = 0; i < uniqueNames.length; i++) {\n        this._constraints.unique[uniqueNames[i]].clear();\n      }\n    }\n\n    if (this._fullTextSearch !== null) {\n      this._fullTextSearch.clear();\n    }\n  }\n\n  /**\n   * Updates an object and notifies collection that the document has changed.\n   * @param {object} doc - document to update within the collection\n   */\n  public update(doc: Doc<T> | Doc<T>[]): void {\n    if (Array.isArray(doc)) {\n\n      for (let i = 0; i < doc.length; i++) {\n        this.update(doc[i]);\n      }\n\n      return;\n    }\n    // Verify object is a properly formed document.\n    if (doc.$loki === undefined) {\n      throw new Error(\"Trying to update unsynced document. Please save the document first by using insert() or addMany()\");\n    }\n\n    try {\n      this.startTransaction();\n      const arr = this.get(doc.$loki, true);\n\n      if (!arr) {\n        throw new Error(\"Trying to update a document not in collection.\");\n      }\n\n      // ref to existing obj\n      let oldInternal = arr[0]; // -internal- obj ref\n      let position = arr[1]; // position in data array\n\n      // ref to new internal obj\n      // if configured to clone, do so now... otherwise just use same obj reference\n      let newInternal = this._defineNestedProperties(this._cloneObjects || !this._disableDeltaChangesApi ? clone(doc, this._cloneMethod) : doc);\n\n      this.emit(\"pre-update\", doc);\n\n      Object.keys(this._constraints.unique).forEach((key) => {\n        this._constraints.unique[key].update(newInternal.$loki, newInternal[key]);\n      });\n\n      // operate the update\n      this._data[position] = newInternal;\n      this._lokimap[doc.$loki] = newInternal;\n\n      // now that we can efficiently determine the data[] position of newly added document,\n      // submit it for all registered DynamicViews to evaluate for inclusion/exclusion\n      for (let idx = 0; idx < this._dynamicViews.length; idx++) {\n        this._dynamicViews[idx]._evaluateDocument(position, false);\n      }\n\n      // Notify all ranged indexes of (possible) value update\n      for (let ri in this._rangedIndexes) {\n        this._rangedIndexes[ri].index.update(doc.$loki, doc[ri]);\n      }\n\n      this._idIndex[position] = newInternal.$loki;\n\n      // FullTextSearch.\n      if (this._fullTextSearch !== null) {\n        this._fullTextSearch.updateDocument(doc, position);\n      }\n\n      this.commit();\n      this._dirty = true; // for autosave scenarios\n\n      // update meta and store changes if ChangesAPI is enabled\n      if (this._disableChangesApi) {\n        this._updateMeta(newInternal);\n      }\n      else {\n        this._updateMetaWithChange(newInternal, oldInternal);\n      }\n\n      let returnObj = newInternal;\n      // if cloning is enabled, emit 'update' event and return with clone of new object\n      if (this._cloneObjects) {\n        returnObj = clone(newInternal, this._cloneMethod);\n      }\n\n      this.emit(\"update\", returnObj, oldInternal);\n    } catch (err) {\n      this.rollback();\n      this.emit(\"error\", err);\n      throw (err); // re-throw error so user does not think it succeeded\n    }\n  }\n\n  /**\n   * Add object to collection\n   */\n  private _add(obj: T) {\n    // if parameter isn't object exit with throw\n    if (\"object\" !== typeof obj) {\n      throw new TypeError(\"Object being added needs to be an object\");\n    }\n    // if object you are adding already has id column it is either already in the collection\n    // or the object is carrying its own 'id' property.  If it also has a meta property,\n    // then this is already in collection so throw error, otherwise rename to originalId and continue adding.\n    if (obj[\"$loki\"] !== undefined) {\n      throw new Error(\"Document is already in collection, please use update()\");\n    }\n\n    /*\n     * try adding object to collection\n     */\n    try {\n      this.startTransaction();\n      this._maxId++;\n\n      if (isNaN(this._maxId)) {\n        this._maxId = (this._data[this._data.length - 1].$loki + 1);\n      }\n\n      const newDoc = obj as Doc<T>;\n      newDoc.$loki = this._maxId;\n      if (!this._disableMeta) {\n        newDoc.meta.version = 0;\n      }\n\n      const constrUnique = this._constraints.unique;\n      for (const key in constrUnique) {\n        if (constrUnique[key] !== undefined) {\n          constrUnique[key].set(newDoc.$loki, newDoc[key]);\n        }\n      }\n\n      // add new obj id to idIndex\n      this._idIndex.push(newDoc.$loki);\n      // update lokimap\n      this._lokimap[newDoc.$loki] = newDoc;\n\n      // add the object\n      this._data.push(newDoc);\n\n      const addedPos = this._data.length - 1;\n\n      // now that we can efficiently determine the data[] position of newly added document,\n      // submit it for all registered DynamicViews to evaluate for inclusion/exclusion\n      const dvlen = this._dynamicViews.length;\n      for (let i = 0; i < dvlen; i++) {\n        this._dynamicViews[i]._evaluateDocument(addedPos, true);\n      }\n\n      // add id/val kvp to ranged index\n      for (let ri in this._rangedIndexes) {\n        // ensure Dates are converted to unix epoch time if serializableIndexes is true\n        if (this._serializableIndexes && newDoc[ri] instanceof Date) {\n          newDoc[ri] = newDoc[ri].getTime();\n        }\n        this._rangedIndexes[ri].index.insert(obj[\"$loki\"], obj[ri]);\n      }\n\n      // FullTextSearch.\n      if (this._fullTextSearch !== null) {\n        this._fullTextSearch.addDocument(newDoc, addedPos);\n      }\n\n      this.commit();\n      this._dirty = true; // for autosave scenarios\n\n      return (this._cloneObjects) ? (clone(newDoc, this._cloneMethod)) : (newDoc);\n    } catch (err) {\n      this.rollback();\n      this.emit(\"error\", err);\n      throw (err); // re-throw error so user does not think it succeeded\n    }\n  }\n\n  /**\n   * Applies a filter function and passes all results to an update function.\n   * @param {function} filterFunction - the filter function\n   * @param {function} updateFunction - the update function\n   */\n  updateWhere(filterFunction: (obj: Doc<T>) => boolean, updateFunction: (obj: Doc<T>) => Doc<T>) {\n    const results = this.where(filterFunction);\n    try {\n      for (let i = 0; i < results.length; i++) {\n        this.update(updateFunction(results[i]));\n      }\n    } catch (err) {\n      this.rollback();\n      throw err;\n    }\n  }\n\n  /**\n   * Remove all documents matching supplied filter function.\n   * @param {function} filterFunction - the filter function\n   */\n  public removeWhere(filterFunction: (obj: Doc<T>) => boolean) {\n    this.remove(this._data.filter(filterFunction));\n  }\n\n  public removeDataOnly() {\n    this.remove(this._data.slice());\n  }\n\n  /**\n   * Remove a document from the collection\n   * @param {number|object} doc - document to remove from collection\n   */\n  remove(doc: number | Doc<T> | Doc<T>[]): void {\n    if (typeof doc === \"number\") {\n      doc = this.get(doc);\n    }\n\n    if (Array.isArray(doc)) {\n      let k = 0;\n      const len = doc.length;\n      for (k; k < len; k++) {\n        this.remove(doc[k]);\n      }\n      return;\n    }\n    if (doc.$loki === undefined) {\n      throw new Error(\"Object is not a document stored in the collection\");\n    }\n\n    try {\n      this.startTransaction();\n      const arr = this.get(doc.$loki, true);\n\n      const position = arr[1];\n\n      // already converted but let's narrow to make typescript happy\n      let aDoc : Doc<T> = (typeof doc === \"number\") ? this.get(doc) : doc;\n      Object.keys(this._constraints.unique).forEach((key) => {\n        if (key in aDoc) {\n          this._constraints.unique[key].remove(aDoc.$loki);\n        }\n      });\n      // now that we can efficiently determine the data[] position of newly added document,\n      // submit it for all registered DynamicViews to remove\n      for (let idx = 0; idx < this._dynamicViews.length; idx++) {\n        this._dynamicViews[idx]._removeDocument(position);\n      }\n\n      this._data.splice(position, 1);\n\n      // remove id from idIndex\n      this._idIndex.splice(position, 1);\n      // remove from lokimap\n      delete this._lokimap[doc.$loki];\n\n      // remove id/val kvp from binary tree index\n      for (let ri in this._rangedIndexes) {\n        this._rangedIndexes[ri].index.remove(doc.$loki);\n      }\n\n      // FullTextSearch.\n      if (this._fullTextSearch !== null) {\n        this._fullTextSearch.removeDocument(doc, position);\n      }\n\n      this.commit();\n      this._dirty = true; // for autosave scenarios\n\n      if (!this._disableChangesApi) {\n        this._createChange(this.name, \"R\", arr[0]);\n      }\n\n      this.emit(\"delete\", arr[0]);\n      delete doc.$loki;\n      delete doc.meta;\n    } catch (err) {\n      this.rollback();\n      this.emit(\"error\", err);\n      throw err;\n    }\n  }\n\n  /*------------+\n   | Change API |\n   +------------*/\n  /**\n   * Returns all changes.\n   * @returns {Collection.Change[]}\n   */\n  public getChanges(): Collection.Change[] {\n    return this._changes;\n  }\n\n  /**\n   * Enables/disables changes api.\n   * @param {boolean} disableChangesApi\n   * @param {boolean} disableDeltaChangesApi\n   */\n  public setChangesApi(disableChangesApi: boolean, disableDeltaChangesApi: boolean = true) {\n    this._disableChangesApi = disableChangesApi;\n    this._disableDeltaChangesApi = disableChangesApi ? true : disableDeltaChangesApi;\n  }\n\n  /**\n   * Clears all the changes.\n   */\n  public flushChanges() {\n    this._changes = [];\n  }\n\n  private _getObjectDelta(oldObject: Doc<TData>, newObject: Doc<TData>) {\n    const propertyNames = newObject !== null && typeof newObject === \"object\" ? Object.keys(newObject) : null;\n    if (propertyNames && propertyNames.length && [\"string\", \"boolean\", \"number\"].indexOf(typeof(newObject)) < 0) {\n      const delta = {};\n      for (let i = 0; i < propertyNames.length; i++) {\n        const propertyName = propertyNames[i];\n        if (newObject.hasOwnProperty(propertyName)) {\n          if (!oldObject.hasOwnProperty(propertyName) || this._constraints.unique[propertyName] !== undefined\n            || propertyName === \"$loki\" || propertyName === \"meta\") {\n            delta[propertyName] = newObject[propertyName];\n          } else {\n            const propertyDelta = this._getObjectDelta(oldObject[propertyName], newObject[propertyName]);\n            if (propertyDelta !== undefined && propertyDelta !== {}) {\n              delta[propertyName] = propertyDelta;\n            }\n          }\n        }\n      }\n      return Object.keys(delta).length === 0 ? undefined : delta;\n    } else {\n      return oldObject === newObject ? undefined : newObject;\n    }\n  }\n\n  /**\n   * Compare changed object (which is a forced clone) with existing object and return the delta\n   */\n  private _getChangeDelta(obj: Doc<TData>, old: Doc<TData>) {\n    if (old) {\n      return this._getObjectDelta(old, obj);\n    } else {\n      return JSON.parse(JSON.stringify(obj));\n    }\n  }\n\n  /**\n   * Creates a clone of the current status of an object and associates operation and collection name,\n   * so the parent db can aggregate and generate a changes object for the entire db\n   */\n  private _createChange(name: string, op: string, obj: Doc<TData>, old?: Doc<TData>) {\n    this._changes.push({\n      name,\n      operation: op,\n      obj: op === \"U\" && !this._disableDeltaChangesApi\n        ? this._getChangeDelta(obj, old)\n        : JSON.parse(JSON.stringify(obj))\n    });\n  }\n\n  private _createInsertChange(obj: Doc<TData>) {\n    this._createChange(this.name, \"I\", obj);\n  }\n\n  private _createUpdateChange(obj: Doc<TData>, old: Doc<TData>) {\n    this._createChange(this.name, \"U\", obj, old);\n  }\n\n  private _insertMetaWithChange(obj: Doc<TData>) {\n    this._insertMeta(obj);\n    this._createInsertChange(obj);\n  }\n\n  private _updateMetaWithChange(obj: Doc<TData>, old: Doc<TData>) {\n    this._updateMeta(obj);\n    this._createUpdateChange(obj, old);\n  }\n\n  private _insertMeta(obj: Doc<TData>) {\n    if (this._disableMeta) {\n      return;\n    }\n\n    if (!obj.meta) {\n      obj.meta = {\n        version: 0,\n        revision: 0,\n        created: 0\n      };\n    }\n    obj.meta.created = (new Date()).getTime();\n    obj.meta.revision = 0;\n  }\n\n  private _updateMeta(obj: Doc<TData>) {\n    if (this._disableMeta) {\n      return;\n    }\n\n    obj.meta.updated = (new Date()).getTime();\n    obj.meta.revision += 1;\n  }\n\n  /*---------------------+\n   | Finding methods     |\n   +----------------------*/\n\n  /**\n   * Get by Id - faster than other methods because of the searching algorithm\n   * @param {int} id - $loki id of document you want to retrieve\n   * @param {boolean} returnPosition - if 'true' we will return [object, position]\n   * @returns {(object|array|null)} Object reference if document was found, null if not,\n   *     or an array if 'returnPosition' was passed.\n   */\n  public get(id: number): Doc<T>;\n  public get(id: number, returnPosition: boolean): Doc<T> | [Doc<T>, number];\n  public get(id: number, returnPosition = false) {\n    if (!returnPosition) {\n      let doc = this._lokimap[id];\n\n      if (doc === undefined) return null;\n\n      return doc;\n    }\n    const data = this._idIndex;\n    let max = data.length - 1;\n    let min = 0;\n    let mid = (min + max) >> 1;\n\n    id = typeof id === \"number\" ? id : parseInt(id, 10);\n\n    if (isNaN(id)) {\n      throw new TypeError(\"Passed id is not an integer\");\n    }\n\n    while (data[min] < data[max]) {\n      mid = (min + max) >> 1;\n\n      if (data[mid] < id) {\n        min = mid + 1;\n      } else {\n        max = mid;\n      }\n    }\n\n    if (max === min && data[min] === id) {\n      if (returnPosition) {\n        return [this._data[min], min];\n      }\n      return this._data[min];\n    }\n    return null;\n  }\n\n  /**\n   * Retrieve doc by Unique index\n   * @param {string} field - name of uniquely indexed property to use when doing lookup\n   * @param {any} value - unique value to search for\n   * @returns {object} document matching the value passed\n   */\n  public by(field: keyof T, value: any): Doc<T> {\n    // for least amount of overhead, we will directly\n    // access index rather than use find codepath\n    let lokiId = this._constraints.unique[field].get(value);\n\n    if (!this._cloneObjects) {\n      return this._lokimap[lokiId];\n    } else {\n      return clone(this._lokimap[lokiId], this._cloneMethod);\n    }\n  }\n\n  /**\n   * Find one object by index property, by property equal to value\n   * @param {object} query - query object used to perform search with\n   * @returns {(object|null)} First matching document, or null if none\n   */\n  public findOne(query: ResultSet.Query<Doc<T>>): Doc<T> {\n    query = query || {};\n\n    // Instantiate ResultSet and exec find op passing firstOnly = true param\n    const result = this.chain().find(query, true).data();\n\n    if (Array.isArray(result) && result.length === 0) {\n      return null;\n    } else {\n      if (!this._cloneObjects) {\n        return result[0];\n      } else {\n        return clone(result[0], this._cloneMethod);\n      }\n    }\n  }\n\n  /**\n   * Chain method, used for beginning a series of chained find() and/or view() operations\n   * on a collection.\n   *\n   * @param {array} transform - Ordered array of transform step objects similar to chain\n   * @param {object} parameters - Object containing properties representing parameters to substitute\n   * @returns {ResultSet} (this) ResultSet, or data array if any map or join functions where called\n   */\n  public chain(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T> {\n    const rs = new ResultSet<T>(this as any as Collection<T>);\n    if (transform === undefined) {\n      return rs;\n    }\n    return rs.transform(transform, parameters);\n  }\n\n  /**\n   * Find method, api is similar to mongodb.\n   * for more complex queries use [chain()]{@link Collection#chain} or [where()]{@link Collection#where}.\n   * @example {@tutorial Query Examples}\n   * @param {object} query - 'mongo-like' query object\n   * @returns {array} Array of matching documents\n   */\n  public find(query?: ResultSet.Query<Doc<T>>): Doc<T>[] {\n    return this.chain().find(query).data();\n  }\n\n  /**\n   * Find object by unindexed field by property equal to value,\n   * simply iterates and returns the first element matching the query\n   */\n  public findOneUnindexed(prop: string, value: any) {\n    let i = this._data.length;\n    let doc;\n    while (i--) {\n      if (this._data[i][prop] === value) {\n        doc = this._data[i];\n        return doc;\n      }\n    }\n    return null;\n  }\n\n  /**\n   * Transaction methods\n   */\n\n  /**\n   * start the transation\n   */\n  public startTransaction(): void {\n    if (this._transactional) {\n      // backup any ranged indexes\n      let rib: { [name: string]: Collection.RangedIndexMeta } = {};\n      for (let ri in this._rangedIndexes) {\n        rib[ri].indexTypeName = this._rangedIndexes[ri].indexTypeName;\n        rib[ri].comparatorName = this._rangedIndexes[ri].comparatorName;\n        rib[ri].index = this._rangedIndexes[ri].index.backup();\n      }\n\n      this._cached = {\n        index: this._idIndex,\n        data: clone(this._data, this._cloneMethod),\n        rangedIndexes: rib,\n      };\n\n      // propagate startTransaction to dynamic views\n      for (let idx = 0; idx < this._dynamicViews.length; idx++) {\n        this._dynamicViews[idx].startTransaction();\n      }\n    }\n  }\n\n  /**\n   * Commit the transaction.\n   */\n  public commit(): void {\n    if (this._transactional) {\n      this._cached = null;\n\n      // propagate commit to dynamic views\n      for (let idx = 0; idx < this._dynamicViews.length; idx++) {\n        this._dynamicViews[idx].commit();\n      }\n    }\n  }\n\n  /**\n   * Rollback the transaction.\n   */\n  public rollback(): void {\n    if (this._transactional) {\n      if (this._cached !== null) {\n        this._idIndex = this._cached.index;\n        this._data = this._cached.data;\n        for (let i = 0; i < this._data.length; i++) {\n          this._data[i] = this._defineNestedProperties(this._data[i]);\n        }\n\n        // restore ranged indexes\n        for (let ri in this._cached.rangedIndexes) {\n          // shortcut reference to serialized meta\n          let sri = this._cached.rangedIndexes[ri];\n          // lookup index factory function in map based on index type name\n          let rif = RangedIndexFactoryMap[sri.indexTypeName];\n          // lookup comparator function in map based on comparator name\n          let ricmp = ComparatorMap[sri.comparatorName];\n          // using index type (from meta), index factory and comparator... create instance of ranged index\n          let rii = rif(ri, ricmp);\n          // now ask new index instance to inflate from plain object\n          rii.restore(sri.index);\n          // attach class instance to our collection's ranged index's (index) instance property\n          this._rangedIndexes[ri].index = rii;\n        }\n\n        // propagate rollback to dynamic views\n        for (let idx = 0; idx < this._dynamicViews.length; idx++) {\n          this._dynamicViews[idx].rollback();\n        }\n      }\n    }\n  }\n\n  /**\n   * Query the collection by supplying a javascript filter function.\n   * @example\n   * let results = coll.where(function(obj) {\n\t *   return obj.legs === 8;\n\t * });\n   * @param {function} fun - filter function to run against all collection docs\n   * @returns {array} all documents which pass your filter function\n   */\n  public where(fun: (obj: Doc<T>) => boolean): Doc<T>[] {\n    return this.chain().where(fun).data();\n  }\n\n  /**\n   * Map Reduce operation\n   * @param {function} mapFunction - function to use as map function\n   * @param {function} reduceFunction - function to use as reduce function\n   * @returns {data} The result of your mapReduce operation\n   */\n  public mapReduce<U1, U2>(mapFunction: (value: Doc<T>, index: number, array: Doc<T>[]) => U1, reduceFunction: (array: U1[]) => U2): U2 {\n    return reduceFunction(this._data.map(mapFunction));\n  }\n\n  /**\n   * Join two collections on specified properties\n   * @param {array} joinData - array of documents to 'join' to this collection\n   * @param {string} leftJoinProp - property name in collection\n   * @param {string} rightJoinProp - property name in joinData\n   * @param {function} mapFun - (Optional) map function to use\n   * @param dataOptions - options to data() before input to your map function\n   * @param [dataOptions.removeMeta] - allows removing meta before calling mapFun\n   * @param [dataOptions.forceClones] - forcing the return of cloned objects to your map object\n   * @param [dataOptions.forceCloneMethod] - allows overriding the default or collection specified cloning method\n   * @returns {ResultSet} Result of the mapping operation\n   */\n  public eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinProp: string | ((obj: any) => string),\n                rightJoinProp: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any,\n                dataOptions?: ResultSet.DataOptions): ResultSet<any> {\n    return new ResultSet(this).eqJoin(joinData, leftJoinProp, rightJoinProp, mapFun, dataOptions);\n  }\n\n  /* ------ STAGING API -------- */\n\n  /**\n   * (Staging API) create a stage and/or retrieve it\n   */\n  getStage(name: string) {\n    if (!this._stages[name]) {\n      this._stages[name] = {};\n    }\n    return this._stages[name];\n  }\n\n  /**\n   * a collection of objects recording the changes applied through a commmitStage\n   */\n\n  /**\n   * (Staging API) create a copy of an object and insert it into a stage\n   */\n  public stage<F extends TData>(stageName: string, obj: Doc<F>): F {\n    const copy = JSON.parse(JSON.stringify(obj));\n    this.getStage(stageName)[obj.$loki] = copy;\n    return copy;\n  }\n\n  /**\n   * (Staging API) re-attach all objects to the original collection, so indexes and views can be rebuilt\n   * then create a message to be inserted in the commitlog\n   * @param {string} stageName - name of stage\n   * @param {string} message\n   */\n  public commitStage(stageName: string, message: string) {\n    const stage = this.getStage(stageName);\n    const timestamp = new Date().getTime();\n\n    for (const prop in stage) {\n      this.update(stage[prop]);\n      this._commitLog.push({\n        timestamp,\n        message,\n        data: JSON.parse(JSON.stringify(stage[prop]))\n      });\n    }\n    this._stages[stageName] = {};\n  }\n\n  /**\n   * Returns all values of a field.\n   * @param {string} field - the field name\n   * @return {any}: the array of values\n   */\n  public extract(field: keyof T): any[] {\n    const result = [];\n    for (let i = 0; i < this._data.length; i++) {\n      result.push(this._data[i][field]);\n    }\n    return result;\n  }\n\n  /**\n   * Finds the minimum value of a field.\n   * @param {string} field - the field name\n   * @return {number} the minimum value\n   */\n  public min(field: keyof T): number {\n    return Math.min.apply(null, this.extractNumerical(field));\n  }\n\n  /**\n   * Finds the maximum value of a field.\n   * @param {string} field - the field name\n   * @return {number} the maximum value\n   */\n  public max(field: keyof T): number {\n    return Math.max.apply(null, this.extractNumerical(field));\n  }\n\n  /**\n   * Finds the minimum value and its index of a field.\n   * @param {string} field - the field name\n   * @return {object} - index and value\n   */\n  public minRecord(field: keyof T) {\n    const result = {\n      index: 0,\n      value: 0\n    };\n\n    if (this._data.length === 0) {\n      result.index = null;\n      result.value = null;\n      return result;\n    }\n\n    result.index = this._data[0].$loki;\n    result.value = parseFloat(this._data[0][field] as any);\n    for (let i = 1; i < this._data.length; i++) {\n      const val = parseFloat(this._data[i][field] as any);\n      if (result.value > val) {\n        result.value = val;\n        result.index = this._data[i].$loki;\n      }\n    }\n    return result;\n  }\n\n  /**\n   * Finds the maximum value and its index of a field.\n   * @param {string} field - the field name\n   * @return {object} - index and value\n   */\n  public maxRecord(field: keyof T) {\n    const result = {\n      index: 0,\n      value: 0\n    };\n\n    if (this._data.length === 0) {\n      result.index = null;\n      result.value = null;\n      return result;\n    }\n\n    result.index = this._data[0].$loki;\n    result.value = parseFloat(this._data[0][field] as any);\n    for (let i = 1; i < this._data.length; i++) {\n      const val = parseFloat(this._data[i][field] as any);\n      if (result.value < val) {\n        result.value = val;\n        result.index = this._data[i].$loki;\n      }\n    }\n    return result;\n  }\n\n  /**\n   * Returns all values of a field as numbers (if possible).\n   * @param {string} field - the field name\n   * @return {number[]} - the number array\n   */\n  public extractNumerical(field: keyof T) {\n    return this.extract(field).map(parseFloat).filter(Number).filter((n) => !(isNaN(n)));\n  }\n\n  /**\n   * Calculates the average numerical value of a field\n   * @param {string} field - the field name\n   * @returns {number} average of property in all docs in the collection\n   */\n  public avg(field: keyof T): number {\n    return average(this.extractNumerical(field));\n  }\n\n  /**\n   * Calculate the standard deviation of a field.\n   * @param {string} field - the field name\n   * @return {number} the standard deviation\n   */\n  public stdDev(field: keyof T): number {\n    return standardDeviation(this.extractNumerical(field));\n  }\n\n  /**\n   * Calculates the mode of a field.\n   * @param {string} field - the field name\n   * @return {number} the mode\n   */\n  public mode(field: keyof T): number {\n    const dict = {};\n    const data = this.extractNumerical(field);\n\n    let mode = data[0];\n    let maxCount = -Infinity;\n    for (let i = 0; i < data.length; i++) {\n      const el = data[i];\n      if (dict[el]) {\n        dict[el]++;\n      } else {\n        dict[el] = 1;\n      }\n      if (dict[el] > maxCount) {\n        mode = el;\n        maxCount = dict[el];\n      }\n    }\n    return mode;\n  }\n\n  /**\n   * Calculates the median of a field.\n   * @param {string} field - the field name\n   * @return {number} the median\n   */\n  public median(field: keyof T) {\n    const values = this.extractNumerical(field);\n    values.sort((a, b) => a - b);\n\n    const half = Math.floor(values.length / 2);\n\n    if (values.length % 2) {\n      return values[half];\n    } else {\n      return (values[half - 1] + values[half]) / 2.0;\n    }\n  }\n}\n\nexport namespace Collection {\n  export interface Options<TData extends object, TNested extends object = {}, T extends object = TData & TNested> {\n    unique?: (keyof T)[];\n    unindexedSortComparator?: string;\n    defaultLokiOperatorPackage?: string;\n    rangedIndexes?: RangedIndexOptions;\n    serializableIndexes?: boolean;\n    asyncListeners?: boolean;\n    disableMeta?: boolean;\n    disableChangesApi?: boolean;\n    disableDeltaChangesApi?: boolean;\n    clone?: boolean;\n    serializableIndices?: boolean;\n    cloneMethod?: CloneMethod;\n    transactional?: boolean;\n    ttl?: number;\n    ttlInterval?: number;\n    nestedProperties?: (keyof TNested | { name: keyof TNested, path: string[] })[];\n    fullTextSearch?: FullTextSearch.FieldOptions[];\n  }\n\n  export interface RangedIndexOptions {\n    [prop: string]: RangedIndexMeta;\n  }\n\n  export interface DeserializeOptions {\n    retainDirtyFlags?: boolean;\n    fullTextSearch?: Dict<Analyzer>;\n\n    [collName: string]: any | { proto?: any; inflate?: (src: object, dest?: object) => void };\n  }\n\n  export interface BinaryIndex {\n    dirty: boolean;\n    values: any;\n  }\n\n  export interface RangedIndexMeta {\n    index?: IRangedIndex<any>;\n    indexTypeName?: string;\n    comparatorName?: string;\n  }\n\n  export interface Change {\n    name: string;\n    operation: string;\n    obj: any;\n  }\n\n  export interface Serialized {\n    name: string;\n    unindexedSortComparator: string;\n    defaultLokiOperatorPackage: string;\n    _dynamicViews: DynamicView[];\n    _nestedProperties: { name: string, path: string[] }[];\n    uniqueNames: string[];\n    transforms: Dict<Transform[]>;\n    rangedIndexes: RangedIndexOptions;\n    _data: Doc<any>[];\n    idIndex: number[];\n    maxId: number;\n    _dirty: boolean;\n    transactional: boolean;\n    asyncListeners: boolean;\n    disableMeta: boolean;\n    disableChangesApi: boolean;\n    disableDeltaChangesApi: boolean;\n    cloneObjects: boolean;\n    cloneMethod: CloneMethod;\n    changes: any;\n    _fullTextSearch: FullTextSearch;\n  }\n\n  export interface CheckIndexOptions {\n    randomSampling?: boolean;\n    randomSamplingFactor?: number;\n    repair?: boolean;\n  }\n\n  export type Transform<T extends object = object> = {\n    type: \"find\";\n    value: ResultSet.Query<Doc<T>> | string;\n  } | {\n    type: \"where\";\n    value: ((obj: Doc<T>) => boolean) | string;\n  } | {\n    type: \"simplesort\";\n    property: keyof T;\n    options?: boolean | ResultSet.SimpleSortOptions;\n  } | {\n    type: \"compoundsort\";\n    value: (keyof T | [keyof T, boolean])[];\n  } | {\n    type: \"sort\";\n    value: (a: Doc<T>, b: Doc<T>) => number;\n  } | {\n    type: \"sortByScoring\";\n    desc?: boolean;\n  } | {\n    type: \"limit\";\n    value: number;\n  } | {\n    type: \"offset\";\n    value: number;\n  } | {\n    type: \"map\";\n    value: (obj: Doc<T>, index: number, array: Doc<T>[]) => any;\n    dataOptions?: ResultSet.DataOptions;\n  } | {\n    type: \"eqJoin\";\n    joinData: Collection<any> | ResultSet<any>;\n    leftJoinKey: string | ((obj: any) => string);\n    rightJoinKey: string | ((obj: any) => string);\n    mapFun?: (left: any, right: any) => any;\n    dataOptions?: ResultSet.DataOptions;\n  } | {\n    type: \"mapReduce\";\n    mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => any;\n    reduceFunction: (array: any[]) => any;\n  } | {\n    type: \"update\";\n    value: (obj: Doc<T>) => any;\n  } | {\n    type: \"remove\";\n  };\n\n  export interface TTL {\n    age: number;\n    ttlInterval: number;\n    daemon: any; // setInterval Timer\n  }\n}\n"
  },
  {
    "path": "packages/loki/src/comparators.ts",
    "content": "/**\n * This file contains LokiOperatorPackages, RangedIndex and Comparator interfaces, as well as\n * global map object instances for registered LokiOperatorPackages, RangedIndex implementations, and Comparator functions\n */\n\nimport { aeqHelper, ltHelper } from \"./operator_packages\";\n\n/* Loki Comparator interface for dependency injection to ranged indexes */\nexport interface ILokiComparer<T> {\n  (a: T, b: T): -1 | 0 | 1;\n}\n\nexport interface IComparatorMap {\n  [name: string]: ILokiComparer<any>;\n}\n\n/** Map/Register of named ILokiComparer functions returning -1, 0, 1 for lt/eq/gt assertions for two passed parameters */\nexport let ComparatorMap: IComparatorMap = {\n  \"js\": CreateJavascriptComparator<any>(),\n  \"abstract-js\": CreateAbstractJavascriptComparator<any>(),\n  \"abstract-date\": CreateAbstractDateJavascriptComparator<any>(),\n  \"loki\": CreateLokiComparator()\n};\n\n/** Typescript-friendly factory for strongly typed 'js' comparators */\nexport function CreateJavascriptComparator<T>(): ILokiComparer<T> {\n  return (val: T, val2: T) => {\n    if (val === val2) return 0;\n    if (val < val2) return -1;\n    return 1;\n  };\n}\n\n/** Typescript-friendly factory for strongly typed 'abstract js' comparators */\nexport function CreateAbstractJavascriptComparator<T>(): ILokiComparer<T> {\n  return (val: T, val2: T) => {\n    if (val == val2) return 0;\n    if (val < val2) return -1;\n    return 1;\n  };\n}\n\n/**\n * Comparator which attempts to deal with deal with dates at comparator level.\n * Should work for dates in any of the object, string, and number formats\n */\nexport function CreateAbstractDateJavascriptComparator<T>(): ILokiComparer<T> {\n  return (val: T, val2: T) => {\n    let v1: string = (new Date(val as any).toISOString());\n    let v2: string = (new Date(val2 as any).toISOString());\n    if (v1 == v2) return 0;\n    if (v1 < v2) return -1;\n    return 1;\n  };\n}\n\n/** Typescript-friendly factory for strongly typed 'loki' comparators */\nexport function CreateLokiComparator(): ILokiComparer<any> {\n  return (val: any, val2: any) => {\n    if (aeqHelper(val, val2)) return 0;\n    if (ltHelper(val, val2, false)) return -1;\n    return 1;\n  };\n}\n\n\n"
  },
  {
    "path": "packages/loki/src/dynamic_view.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { ResultSet } from \"./result_set\";\nimport { Collection } from \"./collection\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\n\n/**\n * DynamicView class is a versatile 'live' view class which can have filters and sorts applied.\n *    Collection.addDynamicView(name) instantiates this DynamicView object and notifies it\n *    whenever documents are add/updated/removed so it can remain up-to-date. (chainable)\n *\n * @example\n * let mydv = mycollection.addDynamicView('test');  // default is non-persistent\n * mydv.applyFind({ 'doors' : 4 });\n * mydv.applyWhere(function(obj) { return obj.name === 'Toyota'; });\n * let results = mydv.data();\n *\n * @extends LokiEventEmitter\n\n * @see {@link Collection#addDynamicView} to construct instances of DynamicView\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport class DynamicView<T extends object = object> extends LokiEventEmitter {\n\n  public readonly name: string;\n  private _collection: Collection<T>;\n  private _persistent: boolean;\n  private _sortPriority: DynamicView.SortPriority;\n  private _minRebuildInterval: number;\n  private _rebuildPending: boolean = false;\n\n  private _resultSet: ResultSet<T>;\n  private _resultData: Doc<T>[] = [];\n  private _resultDirty: boolean = false;\n\n  private _cachedResultSet: ResultSet<T> = null;\n\n  // keep ordered filter pipeline\n  private _filterPipeline: DynamicView.Filter<T>[] = [];\n\n  // sorting member variables\n  // we only support one active search, applied using applySort() or applySimpleSort()\n  private _sortFunction: (lhs: Doc<T>, rhs: Doc<T>) => number = null;\n  private _sortCriteria: (keyof T | [keyof T, boolean])[] = null;\n  private _sortCriteriaSimple: { field: keyof T, options: boolean | ResultSet.SimpleSortOptions } = null;\n  private _sortByScoring: boolean = null;\n  private _sortDirty: boolean = false;\n\n  /**\n   * Constructor.\n   * @param {Collection} collection - a reference to the collection to work agains\n   * @param {string} name - the name of this dynamic view\n   * @param {object} options - the options\n   * @param {boolean} [options.persistent=false] - indicates if view is to main internal results array in 'resultdata'\n   * @param {string} [options.sortPriority=\"passive\"] - the sort priority\n   * @param {number} [options.minRebuildInterval=1] - minimum rebuild interval (need clarification to docs here)\n   */\n  constructor(collection: Collection<T>, name: string, options: DynamicView.Options = {}) {\n    super();\n    (\n      {\n        persistent: this._persistent = false,\n        // 'passive' will defer the sort phase until they call data(). (most efficient overall)\n        // 'active' will sort async whenever next idle. (prioritizes read speeds)\n        sortPriority: this._sortPriority = \"passive\",\n        minRebuildInterval: this._minRebuildInterval = 1\n      } = options\n    );\n\n    this._collection = collection;\n    this.name = name;\n    this._resultSet = new ResultSet(collection);\n\n    // for now just have 1 event for when we finally rebuilt lazy view\n    // once we refactor transactions, i will tie in certain transactional events\n    this._events = {\n      \"rebuild\": []\n    };\n  }\n\n  /**\n   * Internally used immediately after deserialization (loading)\n   *    This will clear out and reapply filterPipeline ops, recreating the view.\n   *    Since where filters do not persist correctly, this method allows\n   *    restoring the view to state where user can re-apply those where filters.\n   *\n   * @param removeWhereFilters\n   * @returns {DynamicView} This dynamic view for further chained ops.\n   * @fires DynamicView.rebuild\n   */\n  private _rematerialize({removeWhereFilters = false}): this {\n    this._resultData = [];\n    this._resultDirty = true;\n    this._resultSet = new ResultSet(this._collection);\n\n    if (this._sortFunction || this._sortCriteria || this._sortCriteriaSimple || this._sortByScoring !== null) {\n      this._sortDirty = true;\n    }\n\n    if (removeWhereFilters) {\n      // for each view see if it had any where filters applied... since they don't\n      // serialize those functions lets remove those invalid filters\n      let fpi = this._filterPipeline.length;\n      while (fpi--) {\n        if (this._filterPipeline[fpi].type === \"where\") {\n          if (fpi !== this._filterPipeline.length - 1) {\n            this._filterPipeline[fpi] = this._filterPipeline[this._filterPipeline.length - 1];\n          }\n          this._filterPipeline.length--;\n        }\n      }\n    }\n\n    // back up old filter pipeline, clear filter pipeline, and reapply pipeline ops\n    const ofp = this._filterPipeline;\n    this._filterPipeline = [];\n\n    // now re-apply 'find' filterPipeline ops\n    for (let idx = 0; idx < ofp.length; idx++) {\n      this.applyFind(ofp[idx].val);\n    }\n\n    // during creation of unit tests, i will remove this forced refresh and leave lazy\n    this.data();\n\n    // emit rebuild event in case user wants to be notified\n    this.emit(\"rebuild\", this);\n\n    return this;\n  }\n\n  /**\n   * Makes a copy of the internal ResultSet for branched queries.\n   * Unlike this dynamic view, the branched ResultSet will not be 'live' updated,\n   * so your branched query should be immediately resolved and not held for future evaluation.\n   * @param {(string|array=)} transform - Optional name of collection transform, or an array of transform steps\n   * @param {object} parameters - optional parameters (if optional transform requires them)\n   * @returns {ResultSet} A copy of the internal ResultSet for branched queries.\n   */\n  public branchResultSet(transform?: string | Collection.Transform<T>[], parameters?: object): ResultSet<T> {\n    const rs = this._resultSet.copy();\n    if (transform === undefined) {\n      return rs;\n    }\n    return rs.transform(transform, parameters);\n  }\n\n  /**\n   * Override of toJSON to avoid circular references.\n   */\n  public toJSON(): DynamicView.Serialized {\n    return {\n      name: this.name,\n      _persistent: this._persistent,\n      _sortPriority: this._sortPriority,\n      _minRebuildInterval: this._minRebuildInterval,\n      _resultSet: this._resultSet,\n      _filterPipeline: this._filterPipeline,\n      _sortCriteria: this._sortCriteria,\n      _sortCriteriaSimple: this._sortCriteriaSimple,\n      _sortByScoring: this._sortByScoring,\n      _sortDirty: this._sortDirty,\n    };\n  }\n\n  public static fromJSONObject(collection: Collection, obj: DynamicView.Serialized): DynamicView {\n    let dv = new DynamicView(collection, obj.name);\n    dv._resultDirty = true;\n    dv._filterPipeline = obj._filterPipeline;\n    dv._resultData = [];\n    dv._sortCriteria = obj._sortCriteria as any;\n    dv._sortCriteriaSimple = obj._sortCriteriaSimple as any;\n    dv._sortByScoring = obj._sortByScoring;\n    dv._sortDirty = obj._sortDirty;\n    dv._resultSet._filteredRows = obj._resultSet._filteredRows;\n    dv._resultSet._filterInitialized = obj._resultSet._filterInitialized;\n    dv._rematerialize({\n      removeWhereFilters: true\n    });\n    return dv;\n  }\n\n  /**\n   * Used to clear pipeline and reset dynamic view to initial state.\n   * Existing options should be retained.\n   * @param {boolean} queueSortPhase - (default: false) if true we will async rebuild view (maybe set default to true in future?)\n   */\n  public removeFilters({queueSortPhase = false} = {}): void {\n    this._rebuildPending = false;\n    this._resultSet.reset();\n    this._resultData = [];\n    this._resultDirty = true;\n\n    this._cachedResultSet = null;\n\n    // keep ordered filter pipeline\n    this._filterPipeline = [];\n\n    // sorting member variables\n    // we only support one active search, applied using applySort() or applySimpleSort()\n    this._sortFunction = null;\n    this._sortCriteria = null;\n    this._sortCriteriaSimple = null;\n    this._sortByScoring = null;\n    this._sortDirty = false;\n\n    if (queueSortPhase === true) {\n      this._queueSortPhase();\n    }\n  }\n\n  /**\n   * Used to apply a sort to the dynamic view\n   * @example\n   * dv.applySort(function(obj1, obj2) {\n\t *   if (obj1.name === obj2.name) return 0;\n\t *   if (obj1.name > obj2.name) return 1;\n\t *   if (obj1.name < obj2.name) return -1;\n\t * });\n   * @param {function} comparefun - a javascript compare function used for sorting\n   * @returns {DynamicView} this DynamicView object, for further chain ops.\n   */\n  public applySort(comparefun: (lhs: Doc<T>, rhs: Doc<T>) => number): this {\n    this._sortFunction = comparefun;\n    this._sortCriteria = null;\n    this._sortCriteriaSimple = null;\n    this._sortByScoring = null;\n    this._queueSortPhase();\n    return this;\n  }\n\n  /**\n   * Used to specify a property used for view translation.\n   * @param {string} field - the field name\n   * @param {boolean|object=} options - boolean for sort descending or options object\n   * @param {boolean} [options.desc=false] - whether we should sort descending.\n   * @param {boolean} [options.disableIndexIntersect=false] - whether we should explicity not use array intersection.\n   * @param {boolean} [options.forceIndexIntersect=false] - force array intersection (if binary index exists).\n   * @param {boolean} [options.useJavascriptSorting=false] - whether results are sorted via basic javascript sort.\n   * @returns {DynamicView} this DynamicView object, for further chain ops.\n   * @example\n   * dv.applySimpleSort(\"name\");\n   */\n  public applySimpleSort(field: keyof T, options: boolean | ResultSet.SimpleSortOptions = false): this {\n    this._sortCriteriaSimple = {field, options};\n    this._sortFunction = null;\n    this._sortCriteria = null;\n    this._sortByScoring = null;\n    this._queueSortPhase();\n    return this;\n  }\n\n  /**\n   * Allows sorting a ResultSet based on multiple columns.\n   * @param {Array} criteria - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n   * @returns {DynamicView} Reference to this DynamicView, sorted, for future chain operations.\n   * @example\n   * // to sort by age and then name (both ascending)\n   * dv.applySortCriteria(['age', 'name']);\n   * // to sort by age (ascending) and then by name (descending)\n   * dv.applySortCriteria(['age', ['name', true]]);\n   * // to sort by age (descending) and then by name (descending)\n   * dv.applySortCriteria([['age', true], ['name', true]]);\n   */\n  public applySortCriteria(criteria: (keyof T | [keyof T, boolean])[]): this {\n    this._sortCriteria = criteria;\n    this._sortCriteriaSimple = null;\n    this._sortFunction = null;\n    this._sortByScoring = null;\n    this._queueSortPhase();\n    return this;\n  }\n\n  /**\n   * Used to apply a sort by the latest full-text-search scoring.\n   * @param {boolean} [ascending=false] - sort ascending\n   */\n  public applySortByScoring(ascending = false): this {\n    this._sortFunction = null;\n    this._sortCriteria = null;\n    this._sortCriteriaSimple = null;\n    this._sortByScoring = ascending;\n    this._queueSortPhase();\n    return this;\n  }\n\n  /**\n   * Returns the scoring of the last full-text-search.\n   * @returns {ScoreResult[]}\n   */\n  public getScoring(): Scorer.ScoreResult[] {\n    return this._resultSet.getScoring();\n  }\n\n  /**\n   * Marks the beginning of a transaction.\n   * @returns {DynamicView} this DynamicView object, for further chain ops.\n   */\n  public startTransaction(): this {\n    this._cachedResultSet = this._resultSet.copy();\n    return this;\n  }\n\n  /**\n   * Commits a transaction.\n   * @returns {DynamicView} this DynamicView object, for further chain ops.\n   */\n  public commit(): this {\n    this._cachedResultSet = null;\n    return this;\n  }\n\n  /**\n   * Rolls back a transaction.\n   * @returns {DynamicView} this DynamicView object, for further chain ops.\n   */\n  public rollback(): this {\n    this._resultSet = this._cachedResultSet;\n\n    if (this._persistent) {\n      // for now just rebuild the persistent dynamic view data in this worst case scenario\n      // (a persistent view utilizing transactions which get rolled back), we already know the filter so not too bad.\n      this._resultData = this._resultSet.data();\n\n      this.emit(\"rebuild\", this);\n    }\n    return this;\n  }\n\n  /**\n   * Find the index of a filter in the pipeline, by that filter's ID.\n   * @param {(string|number)} uid - The unique ID of the filter.\n   * @returns {number}: index of the referenced filter in the pipeline; -1 if not found.\n   */\n  private _indexOfFilterWithId(uid: string | number): number {\n    if (typeof uid === \"string\" || typeof uid === \"number\") {\n      for (let idx = 0, len = this._filterPipeline.length; idx < len; idx++) {\n        if (uid === this._filterPipeline[idx].uid) {\n          return idx;\n        }\n      }\n    }\n    return -1;\n  }\n\n  /**\n   * Add the filter object to the end of view's filter pipeline and apply the filter to the ResultSet.\n   * @param {object} filter - The filter object. Refer to applyFilter() for extra details.\n   */\n  private _addFilter(filter: DynamicView.Filter<T>): void {\n    this._filterPipeline.push(filter);\n    this._resultSet[filter.type as string](filter.val);\n  }\n\n  /**\n   * Reapply all the filters in the current pipeline.\n   *\n   * @returns {DynamicView} this DynamicView object, for further chain ops.\n   */\n  public reapplyFilters(): this {\n    this._resultSet.reset();\n\n    this._cachedResultSet = null;\n    if (this._persistent) {\n      this._resultData = [];\n      this._resultDirty = true;\n    }\n\n    const filters = this._filterPipeline;\n    this._filterPipeline = [];\n\n    for (let idx = 0, len = filters.length; idx < len; idx++) {\n      this._addFilter(filters[idx]);\n    }\n\n    if (this._sortFunction || this._sortCriteria || this._sortCriteriaSimple || this._sortByScoring !== null) {\n      this._queueSortPhase();\n    } else {\n      this._queueRebuildEvent();\n    }\n\n    return this;\n  }\n\n  /**\n   * Adds or updates a filter in the DynamicView filter pipeline\n   * @param {object} filter - A filter object to add to the pipeline.\n   *    The object is in the format { 'type': filter_type, 'val', filter_param, 'uid', optional_filter_id }\n   * @returns {DynamicView} this DynamicView object, for further chain ops.\n   */\n  public applyFilter(filter: DynamicView.Filter<T>): this {\n    const idx = this._indexOfFilterWithId(filter.uid);\n    if (idx >= 0) {\n      this._filterPipeline[idx] = filter;\n      return this.reapplyFilters();\n    }\n\n    this._cachedResultSet = null;\n    if (this._persistent) {\n      this._resultData = [];\n      this._resultDirty = true;\n    }\n\n    this._addFilter(filter);\n\n    if (this._sortFunction || this._sortCriteria || this._sortCriteriaSimple || this._sortByScoring !== null) {\n      this._queueSortPhase();\n    } else {\n      this._queueRebuildEvent();\n    }\n    return this;\n  }\n\n  /**\n   * applyFind() - Adds or updates a mongo-style query option in the DynamicView filter pipeline\n   *\n   * @param {object} query - A mongo-style query object to apply to pipeline\n   * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n   * @returns {DynamicView} this DynamicView object, for further chain ops.\n   */\n  public applyFind(query: object, uid: string | number = \"\"): this {\n    this.applyFilter({\n      type: \"find\",\n      val: query,\n      uid\n    });\n    return this;\n  }\n\n  /**\n   * Adds or updates a javascript filter function in the DynamicView filter pipeline\n   * @param {function} fun - A javascript filter function to apply to pipeline\n   * @param {(string|number)} uid - Optional: The unique ID of this filter, to reference it in the future.\n   * @returns {DynamicView} this DynamicView object, for further chain ops.\n   */\n  public applyWhere(fun: (obj: Doc<T>) => boolean, uid?: string | number): this {\n    this.applyFilter({\n      type: \"where\",\n      val: fun,\n      uid\n    });\n    return this;\n  }\n\n  /**\n   * Remove the specified filter from the DynamicView filter pipeline\n   * @param {(string|number)} uid - The unique ID of the filter to be removed.\n   * @returns {DynamicView} this DynamicView object, for further chain ops.\n   */\n  public removeFilter(uid: string | number): this {\n    const idx = this._indexOfFilterWithId(uid);\n    if (idx < 0) {\n      throw new Error(\"Dynamic view does not contain a filter with ID: \" + uid);\n    }\n\n    this._filterPipeline.splice(idx, 1);\n    this.reapplyFilters();\n    return this;\n  }\n\n  /**\n   * Returns the number of documents representing the current DynamicView contents.\n   * @returns {number} The number of documents representing the current DynamicView contents.\n   */\n  public count(): number {\n    // in order to be accurate we will pay the minimum cost (and not alter dv state management)\n    // recurring ResultSet data resolutions should know internally its already up to date.\n    // for persistent data this will not update resultdata nor fire rebuild event.\n    if (this._resultDirty) {\n      this._resultData = this._resultSet.data();\n    }\n\n    return this._resultSet.count();\n  }\n\n  /**\n   * Resolves and pending filtering and sorting, then returns document array as result.\n   * @param {object} options - optional parameters to pass to ResultSet.data() if non-persistent\n   * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n   *        the collection is not configured for clone object.\n   * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n   *        Possible values include 'parse-stringify', 'jquery-extend-deep', 'shallow', 'shallow-assign'\n   * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n   *\n   * @returns {Array} An array of documents representing the current DynamicView contents.\n   */\n  public data(options: ResultSet.DataOptions = {}): Doc<T>[] {\n    // using final sort phase as 'catch all' for a few use cases which require full rebuild\n    if (this._sortDirty || this._resultDirty) {\n      this._performSortPhase({\n        suppressRebuildEvent: true\n      });\n    }\n    return (this._persistent) ? (this._resultData) : (this._resultSet.data(options));\n  }\n\n  /**\n   * When the view is not sorted we may still wish to be notified of rebuild events.\n   * This event will throttle and queue a single rebuild event when batches of updates affect the view.\n   */\n  private _queueRebuildEvent(): void {\n    if (this._rebuildPending) {\n      return;\n    }\n    this._rebuildPending = true;\n\n    setTimeout(() => {\n      if (this._rebuildPending) {\n        this._rebuildPending = false;\n        this.emit(\"rebuild\", this);\n      }\n    }, this._minRebuildInterval);\n  }\n\n  /**\n   * If the view is sorted we will throttle sorting to either :\n   * (1) passive - when the user calls data(), or\n   * (2) active - once they stop updating and yield js thread control\n   */\n  private _queueSortPhase(): void {\n    // already queued? exit without queuing again\n    if (this._sortDirty) {\n      return;\n    }\n    this._sortDirty = true;\n\n    if (this._sortPriority === \"active\") {\n      // active sorting... once they are done and yield js thread, run async performSortPhase()\n      setTimeout(() => {\n        this._performSortPhase();\n      }, this._minRebuildInterval);\n    } else {\n      // must be passive sorting... since not calling performSortPhase (until data call), lets use queueRebuildEvent to\n      // potentially notify user that data has changed.\n      this._queueRebuildEvent();\n    }\n  }\n\n  /**\n   * Invoked synchronously or asynchronously to perform final sort phase (if needed)\n   */\n  private _performSortPhase(options: { suppressRebuildEvent?: boolean } = {}): void {\n    // async call to this may have been pre-empted by synchronous call to data before async could fire\n    if (!this._sortDirty && !this._resultDirty) {\n      return;\n    }\n\n    if (this._sortDirty) {\n      if (this._sortFunction) {\n        this._resultSet.sort(this._sortFunction);\n      } else if (this._sortCriteria) {\n        this._resultSet.compoundsort(this._sortCriteria);\n      } else if (this._sortCriteriaSimple) {\n        this._resultSet.simplesort(this._sortCriteriaSimple.field, this._sortCriteriaSimple.options);\n      } else if (this._sortByScoring !== null) {\n        this._resultSet.sortByScoring(this._sortByScoring);\n      }\n\n      this._sortDirty = false;\n    }\n\n    if (this._persistent) {\n      // persistent view, rebuild local resultdata array\n      this._resultData = this._resultSet.data();\n      this._resultDirty = false;\n    }\n\n    if (!options.suppressRebuildEvent) {\n      this.emit(\"rebuild\", this);\n    }\n  }\n\n  /**\n   * (Re)evaluating document inclusion.\n   * Called by : collection.insert() and collection.update().\n   * @param {int} objIndex - index of document to (re)run through filter pipeline.\n   * @param {boolean} isNew - true if the document was just added to the collection.\n   * @hidden\n   */\n  _evaluateDocument(objIndex: number, isNew: boolean): void {\n    // if no filter applied yet, the result 'set' should remain 'everything'\n    if (!this._resultSet._filterInitialized) {\n      if (this._persistent) {\n        this._resultData = this._resultSet.data();\n      }\n      // need to re-sort to sort new document\n      if (this._sortFunction || this._sortCriteria || this._sortCriteriaSimple) {\n        this._queueSortPhase();\n      } else {\n        this._queueRebuildEvent();\n      }\n      return;\n    }\n\n    const ofr = this._resultSet._filteredRows;\n    const oldPos = (isNew) ? (-1) : (ofr.indexOf(+objIndex));\n    const oldlen = ofr.length;\n\n    // creating a 1-element ResultSet to run filter chain ops on to see if that doc passes filters;\n    // mostly efficient algorithm, slight stack overhead price (this function is called on inserts and updates)\n    const evalResultSet = new ResultSet(this._collection);\n    evalResultSet._filteredRows = [objIndex];\n    evalResultSet._filterInitialized = true;\n    let filter;\n    for (let idx = 0, len = this._filterPipeline.length; idx < len; idx++) {\n      filter = this._filterPipeline[idx];\n      evalResultSet[filter.type as string](filter.val);\n    }\n\n    // not a true position, but -1 if not pass our filter(s), 0 if passed filter(s)\n    const newPos = (evalResultSet._filteredRows.length === 0) ? -1 : 0;\n\n    // wasn't in old, shouldn't be now... do nothing\n    if (oldPos === -1 && newPos === -1) return;\n\n    // wasn't in ResultSet, should be now... add\n    if (oldPos === -1 && newPos !== -1) {\n      ofr.push(objIndex);\n\n      if (this._persistent) {\n        this._resultData.push(this._collection._data[objIndex]);\n      }\n\n      // need to re-sort to sort new document\n      if (this._sortFunction || this._sortCriteria || this._sortCriteriaSimple) {\n        this._queueSortPhase();\n      } else {\n        this._queueRebuildEvent();\n      }\n\n      return;\n    }\n\n    // was in ResultSet, shouldn't be now... delete\n    if (oldPos !== -1 && newPos === -1) {\n      if (oldPos < oldlen - 1) {\n        ofr.splice(oldPos, 1);\n\n        if (this._persistent) {\n          this._resultData.splice(oldPos, 1);\n        }\n      } else {\n        ofr.length = oldlen - 1;\n\n        if (this._persistent) {\n          this._resultData.length = oldlen - 1;\n        }\n      }\n\n      // in case changes to data altered a sort column\n      if (this._sortFunction || this._sortCriteria || this._sortCriteriaSimple) {\n        this._queueSortPhase();\n      } else {\n        this._queueRebuildEvent();\n      }\n      return;\n    }\n\n    // was in ResultSet, should still be now... (update persistent only?)\n    if (oldPos !== -1 && newPos !== -1) {\n      if (this._persistent) {\n        // in case document changed, replace persistent view data with the latest collection._data document\n        this._resultData[oldPos] = this._collection._data[objIndex];\n      }\n\n      // in case changes to data altered a sort column\n      if (this._sortFunction || this._sortCriteria || this._sortCriteriaSimple) {\n        this._queueSortPhase();\n      } else {\n        this._queueRebuildEvent();\n      }\n    }\n  }\n\n  /**\n   * Internal function called on collection.delete().\n   * @hidden\n   */\n  _removeDocument(objIndex: number): void {\n    // if no filter applied yet, the result 'set' should remain 'everything'\n    if (!this._resultSet._filterInitialized) {\n      if (this._persistent) {\n        this._resultData = this._resultSet.data();\n      }\n      // in case changes to data altered a sort column\n      if (this._sortFunction || this._sortCriteria || this._sortCriteriaSimple) {\n        this._queueSortPhase();\n      } else {\n        this._queueRebuildEvent();\n      }\n      return;\n    }\n\n    const ofr = this._resultSet._filteredRows;\n    const oldPos = ofr.indexOf(+objIndex);\n    let oldlen = ofr.length;\n    if (oldPos !== -1) {\n      // if not last row in resultdata, swap last to hole and truncate last row\n      if (oldPos < oldlen - 1) {\n        ofr[oldPos] = ofr[oldlen - 1];\n        ofr.length = oldlen - 1;\n\n        if (this._persistent) {\n          this._resultData[oldPos] = this._resultData[oldlen - 1];\n          this._resultData.length = oldlen - 1;\n        }\n      }\n      // last row, so just truncate last row\n      else {\n        ofr.length = oldlen - 1;\n\n        if (this._persistent) {\n          this._resultData.length = oldlen - 1;\n        }\n      }\n\n      // in case changes to data altered a sort column\n      if (this._sortFunction || this._sortCriteria || this._sortCriteriaSimple) {\n        this._queueSortPhase();\n      } else {\n        this._queueRebuildEvent();\n      }\n    }\n\n    // since we are using filteredRows to store data array positions\n    // if they remove a document (whether in our view or not),\n    // we need to adjust array positions -1 for all document array references after that position\n    oldlen = ofr.length;\n    for (let idx = 0; idx < oldlen; idx++) {\n      if (ofr[idx] > objIndex) {\n        ofr[idx]--;\n      }\n    }\n  }\n\n  /**\n   * Data transformation via user supplied functions\n   * @param {function} mapFunction - this function accepts a single document for you to transform and return\n   * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n   * @returns The output of your reduceFunction\n   */\n  public mapReduce<U1, U2>(mapFunction: (item: T, index: number, array: T[]) => U1, reduceFunction: (array: U1[]) => U2): U2 {\n    try {\n      return reduceFunction(this.data().map(mapFunction));\n    } catch (err) {\n      throw err;\n    }\n  }\n}\n\nexport namespace DynamicView {\n  export interface Options {\n    persistent?: boolean;\n    sortPriority?: SortPriority;\n    minRebuildInterval?: number;\n  }\n\n  export type SortPriority = \"passive\" | \"active\";\n\n  export interface Serialized {\n    name: string;\n    _persistent: boolean;\n    _sortPriority: SortPriority;\n    _minRebuildInterval: number;\n    _resultSet: ResultSet<any>;\n    _filterPipeline: Filter<any>[];\n    _sortCriteria: (string | [string, boolean])[];\n    _sortCriteriaSimple: { field: string, options: boolean | ResultSet.SimpleSortOptions };\n    _sortByScoring: boolean;\n    _sortDirty: boolean;\n  }\n\n  export type Filter<T extends object = object> = {\n    type: \"find\";\n    val: ResultSet.Query<Doc<T>>;\n    uid: number | string;\n  } | {\n    type: \"where\";\n    val: (obj: Doc<T>) => boolean;\n    uid: number | string;\n  };\n}\n"
  },
  {
    "path": "packages/loki/src/event_emitter.ts",
    "content": "/**\n * LokiEventEmitter is a minimalist version of EventEmitter. It enables any\n * constructor that inherits EventEmitter to emit events and trigger\n * listeners that have been added to the event through the on(event, callback) method\n *\n * @constructor LokiEventEmitter\n */\nexport class LokiEventEmitter {\n  /**\n   * A map, with each property being an array of callbacks.\n   */\n  protected _events: object = {};\n\n  /**\n   * Determines whether or not the callbacks associated with each event should happen in an async fashion or not.\n   * Default is false, which means events are synchronous\n   */\n  protected _asyncListeners: boolean = false;\n\n  /**\n   * Adds a listener to the queue of callbacks associated to an event\n   * @param {string|string[]} eventName - the name(s) of the event(s) to listen to\n   * @param {function} listener - callback function of listener to attach\n   * @returns {int} the index of the callback in the array of listeners for a particular event\n   */\n  public on(eventName: string | string[], listener: Function): Function {\n    let event;\n\n    if (Array.isArray(eventName)) {\n      eventName.forEach((currentEventName) => {\n        this.on(currentEventName, listener);\n      });\n      return listener;\n    }\n\n    event = this._events[eventName];\n    if (!event) {\n      event = this._events[eventName] = [];\n    }\n    event.push(listener);\n    return listener;\n  }\n\n  /**\n   * Emits a particular event\n   * with the option of passing optional parameters which are going to be processed by the callback\n   * provided signatures match (i.e. if passing emit(event, arg0, arg1) the listener should take two parameters)\n   * @param {string} eventName - the name of the event\n   * @param {object} data - optional object passed with the event\n   */\n  protected emit(eventName: string, ...data: any[]): void {\n    if (eventName && this._events[eventName]) {\n      this._events[eventName].forEach((listener: Function) => {\n        if (this._asyncListeners) {\n          setTimeout(() => {\n            listener(...data);\n          }, 1);\n        } else {\n          listener(...data);\n        }\n      });\n    }\n  }\n\n  /**\n   * Alias of EventEmitter.on().\n   */\n  public addListener(eventName: string | string[], listener: Function) {\n    return this.on(eventName, listener);\n  }\n\n  /**\n   * Removes the listener at position 'index' from the event 'eventName'\n   * @param {string|string[]} eventName - the name(s) of the event(s) which the listener is attached to\n   * @param {function} listener - the listener callback function to remove from emitter\n   */\n  public removeListener(eventName: string | string[], listener: Function) {\n    if (Array.isArray(eventName)) {\n      eventName.forEach((currentEventName) => {\n        this.removeListener(currentEventName, listener);\n      });\n    }\n\n    if (this._events[eventName as string]) {\n      const listeners = this._events[eventName as string];\n      listeners.splice(listeners.indexOf(listener), 1);\n    }\n  }\n}\n"
  },
  {
    "path": "packages/loki/src/index.ts",
    "content": "import { Loki } from \"./loki\";\nimport { Collection } from \"./collection\";\n\nLoki[\"Collection\"] = Collection;\n\nexport {Loki, Collection};\nexport default Loki;\n"
  },
  {
    "path": "packages/loki/src/loki.ts",
    "content": "import { LokiEventEmitter } from \"./event_emitter\";\nimport { Collection } from \"./collection\";\nimport { Doc, StorageAdapter } from \"../../common/types\";\nimport { PLUGINS } from \"../../common/plugin\";\nimport { ComparatorMap, IComparatorMap } from \"./comparators\";\nimport { RangedIndexFactoryMap, IRangedIndexFactoryMap } from \"./ranged_indexes\";\nimport { LokiOperatorPackageMap, ILokiOperatorPackageMap } from \"./operator_packages\";\n\nfunction getENV(): Loki.Environment {\n  if (global !== undefined && (global[\"android\"] || global[\"NSObject\"])) {\n    return \"NATIVESCRIPT\";\n  }\n\n  const isNode = global !== undefined && ({}).toString.call(global.process) === \"[object process]\";\n  if (isNode) {\n    if (global[\"window\"]) {\n      return \"NODEJS\"; //node-webkit\n    } else {\n      return \"NODEJS\";\n    }\n  }\n\n  if (document !== undefined) {\n    if (document.URL.indexOf(\"http://\") === -1 && document.URL.indexOf(\"https://\") === -1) {\n      return \"CORDOVA\";\n    }\n    return \"BROWSER\";\n  }\n\n  const isBrowser = window !== undefined && ({}).toString.call(window) === \"[object Window]\";\n  if (isBrowser) {\n    return \"BROWSER\";\n  }\n  throw SyntaxError(\"Unknown environment...\");\n}\n\nexport class Loki extends LokiEventEmitter {\n  public filename: string;\n\n  // persist version of code which created the database to the database.\n  // could use for upgrade scenarios\n  private databaseVersion: number = 1.5; // TODO\n  private engineVersion: number = 1.5;\n\n  public _collections: Collection[];\n\n  private _env: Loki.Environment;\n\n  // currently keeping persistenceMethod and persistenceAdapter as loki level properties that\n  // will not or cannot be deserialized  You are required to configure persistence every time\n  // you instantiate a loki object (or use default environment detection) in order to load the database anyways.\n  private _serializationMethod: Loki.SerializationMethod;\n  private _destructureDelimiter: string;\n  // persistenceMethod could be 'fs', 'localStorage', or 'adapter'\n  // this is optional option param, otherwise environment detection will be used\n  // if user passes their own adapter we will force this method to 'adapter' later, so no need to pass method option.\n  private _persistenceMethod: Loki.PersistenceMethod = null;\n  // retain reference to optional (non-serializable) persistenceAdapter 'instance'\n  private _persistenceAdapter: StorageAdapter = null;\n\n  // flags used to throttle saves\n  private _throttledSaves: boolean = true;\n  private _throttledSaveRunning: Promise<void> = null;\n  private _throttledSavePending: Promise<void> = null;\n\n  // autosave support (disabled by default)\n  private _autosave: boolean = false;\n  private _autosaveInterval: number = 5000;\n  private _autosaveRunning: boolean = false;\n  private _autosaveHandler: Promise<void> = Promise.resolve();\n\n  /**\n   * Constructs the main database class.\n   * @param {string} filename - name of the file to be saved to\n   * @param {object} [options={}] - options\n   * @param {Loki.Environment} [options.env] - the javascript environment\n   * @param {Loki.SerializationMethod} [options.serializationMethod=NORMAL] - the serialization method\n   * @param {string} [options.destructureDelimiter=\"$<\\n\"] - string delimiter used for destructured serialization\n   * @param {IComparatorMap} [options.comparatorMap] allows injecting or overriding registered comparators\n   * @param {IRangedIndexFactoryMap} [options.rangedIndexFactoryMap] allows injecting or overriding registered ranged index factories\n   * @param {ILokiOperatorPackageMap} [options.lokiOperatorPackageMap] allows injecting or overriding registered loki operator packages\n   */\n  constructor(filename = \"loki.db\", options: Loki.Options = {}) {\n    super();\n\n    this.filename = filename;\n    this._collections = [];\n\n    (\n      {\n        serializationMethod: this._serializationMethod = \"normal\",\n        destructureDelimiter: this._destructureDelimiter = \"$<\\n\",\n        env: this._env = getENV()\n      } = options\n    );\n\n    this._events = {\n      \"init\": [],\n      \"loaded\": [],\n      \"flushChanges\": [],\n      \"close\": [],\n      \"changes\": [],\n      \"warning\": []\n    };\n\n    // allow users to inject their own comparators\n    if (options.comparatorMap) {\n      for (let c in options.comparatorMap) {\n        ComparatorMap[c] = options.comparatorMap[c];\n      }\n    }\n\n    // allow users to register their own rangedIndex factory functions\n    if (options.rangedIndexFactoryMap) {\n      for (let rif in options.rangedIndexFactoryMap) {\n        RangedIndexFactoryMap[rif] = options.rangedIndexFactoryMap[rif];\n      }\n    }\n\n    // allow users to register their own LokiOperatorPackages or inject functionality within existing ones\n    if (options.lokiOperatorPackageMap) {\n      for (let lop in options.lokiOperatorPackageMap) {\n        LokiOperatorPackageMap[lop] = options.lokiOperatorPackageMap[lop];\n      }\n    }\n\n    this.on(\"init\", this.clearChanges);\n  }\n\n  /**\n   * configures options related to database persistence.\n   *\n   * @param {Loki.PersistenceOptions} [options={}] - options\n   * @param {adapter} [options.adapter=auto] - an instance of a loki persistence adapter\n   * @param {boolean} [options.autosave=false] - enables autosave\n   * @param {int} [options.autosaveInterval=5000] - time interval (in milliseconds) between saves (if dirty)\n   * @param {boolean} [options.autoload=false] - enables autoload on loki instantiation\n   * @param {object} options.inflate - options that are passed to loadDatabase if autoload enabled\n   * @param {boolean} [options.throttledSaves=true] - if true, it batches multiple calls to to saveDatabase reducing number of\n   *   disk I/O operations and guaranteeing proper serialization of the calls. Default value is true.\n   * @param {Loki.PersistenceMethod} options.persistenceMethod - a persistence method which should be used (FS_STORAGE, LOCAL_STORAGE...)\n   * @returns {Promise} a Promise that resolves after initialization and (if enabled) autoloading the database\n   */\n  public initializePersistence(options: Loki.PersistenceOptions = {}): Promise<void> {\n\n    let loaded = this._autosaveDisable();\n\n    (\n      {\n        autosave: this._autosave = false,\n        autosaveInterval: this._autosaveInterval = 5000,\n        persistenceMethod: this._persistenceMethod,\n        // TODO\n        //inflate: this.options.inflate,\n        throttledSaves: this._throttledSaves = true\n      } = options\n    );\n\n    const DEFAULT_PERSISTENCE = {\n      \"NODEJS\": [\"fs-storage\"],\n      \"BROWSER\": [\"local-storage\", \"indexed-storage\"],\n      \"CORDOVA\": [\"local-storage\", \"indexed-storage\"],\n      \"MEMORY\": [\"memory-storage\"]\n    };\n\n    const PERSISTENCE_METHODS = {\n      \"fs-storage\": PLUGINS[\"FSStorage\"],\n      \"local-storage\": PLUGINS[\"LocalStorage\"],\n      \"indexed-storage\": PLUGINS[\"IndexedStorage\"],\n      \"memory-storage\": PLUGINS[\"MemoryStorage\"]\n    };\n\n    // process the options\n    if (this._persistenceMethod !== undefined) {\n      // check if the specified persistence method is known\n      if (typeof(PERSISTENCE_METHODS[this._persistenceMethod]) === \"function\") {\n        this._persistenceAdapter = new (PERSISTENCE_METHODS[this._persistenceMethod]);\n      } else {\n        throw Error(\"Unknown persistence method.\");\n      }\n    }\n\n    // if user passes adapter, set persistence mode to adapter and retain persistence adapter instance\n    if (options.adapter !== undefined) {\n      this._persistenceMethod = \"adapter\";\n      this._persistenceAdapter = options.adapter;\n    }\n\n    // if by now there is no adapter specified by user nor derived from persistenceMethod: use sensible defaults\n    if (this._persistenceAdapter === null) {\n      let possiblePersistenceMethods = DEFAULT_PERSISTENCE[this._env];\n      if (possiblePersistenceMethods) {\n        for (let i = 0; i < possiblePersistenceMethods.length; i++) {\n          if (PERSISTENCE_METHODS[possiblePersistenceMethods[i]]) {\n            this._persistenceMethod = possiblePersistenceMethods[i];\n            this._persistenceAdapter = new (PERSISTENCE_METHODS[possiblePersistenceMethods[i]]);\n            break;\n          }\n        }\n      }\n    }\n\n    // if they want to load database on loki instantiation, now is a good time to load... after adapter set and before\n    // possible autosave initiation\n    if (options.autoload) {\n      loaded = loaded.then(() => this._loadDatabase(options.inflate, true));\n    }\n\n    return loaded.then(() => {\n      this._autosaveEnable();\n    });\n  }\n\n  /**\n   * Copies 'this' database into a new Loki instance. Object references are shared to make lightweight.\n   * @param {object} options - options\n   * @param {boolean} options.removeNonSerializable - nulls properties not safe for serialization.\n   */\n  public copy(options: Loki.CopyOptions = {}): Loki {\n    const databaseCopy = new Loki(this.filename, {env: this._env});\n\n    // currently inverting and letting loadJSONObject do most of the work\n    databaseCopy.loadJSONObject(this, {\n      retainDirtyFlags: true\n    });\n\n    // since our toJSON is not invoked for reference database adapters, this will let us mimic\n    if (options.removeNonSerializable) {\n      databaseCopy._persistenceAdapter = null;\n\n      for (let idx = 0; idx < databaseCopy._collections.length; idx++) {\n        databaseCopy._collections[idx]._constraints = null;\n        databaseCopy._collections[idx]._ttl = null;\n      }\n    }\n\n    return databaseCopy;\n  }\n\n  /**\n   * Adds a collection to the database.\n   * @param {string} name - name of collection to add\n   * @param {object} [options={}] - options to configure collection with.\n   * @param {array} [options.unique=[]] - array of property names to define unique constraints for\n   * @param {array} [options.exact=[]] - array of property names to define exact constraints for\n   * @param {array} [options.indices=[]] - array property names to define binary indexes for\n   * @param {boolean} [options.asyncListeners=false] - whether listeners are called asynchronously\n   * @param {boolean} [options.disableMeta=false] - set to true to disable meta property on documents\n   * @param {boolean} [options.disableChangesApi=true] - set to false to enable Changes Api\n   * @param {boolean} [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)\n   * @param {boolean} [options.clone=false] - specify whether inserts and queries clone to/from user\n   * @param {string} [options.cloneMethod=CloneMethod.DEEP] - the clone method\n   * @param {number} [options.ttl=] - age of document (in ms.) before document is considered aged/stale\n   * @param {number} [options.ttlInterval=] - time interval for clearing out 'aged' documents; not set by default\n   * @returns {Collection} a reference to the collection which was just added\n   */\n  public addCollection<TData extends object = object, TNested extends object = object>(name: string, options: Collection.Options<TData, TNested> = {}): Collection<TData, TNested> {\n    // Return an existing collection if a collection with the same name already exists.\n    for (let i = 0; i < this._collections.length; i++) {\n      if (this._collections[i].name === name) {\n        return this._collections[i] as Collection<TData, TNested>;\n      }\n    }\n    // Create a new collection otherwise.\n    const collection = new Collection<TData, TNested>(name, options);\n    this._collections.push(collection);\n    return collection;\n  }\n\n  public loadCollection(collection: Collection): void {\n    if (!collection.name) {\n      throw new Error(\"Collection must have a name property to be loaded\");\n    }\n    this._collections.push(collection);\n  }\n\n  /**\n   * Retrieves reference to a collection by name.\n   * @param {string} name - name of collection to look up\n   * @returns {Collection} Reference to collection in database by that name, or null if not found\n   */\n  public getCollection<TData extends object = object, TNested extends object = object>(name: string): Collection<TData, TNested> {\n    for (let i = 0; i < this._collections.length; i++) {\n      if (this._collections[i].name === name) {\n        return this._collections[i] as Collection<TData, TNested>;\n      }\n    }\n\n    // no such collection\n    this.emit(\"warning\", \"collection \" + name + \" not found\");\n    return null;\n  }\n\n  /**\n   * Renames an existing loki collection\n   * @param {string} oldName - name of collection to rename\n   * @param {string} newName - new name of collection\n   * @returns {Collection} reference to the newly renamed collection\n   */\n  public renameCollection<TData extends object = object, TNested extends object = object>(oldName: string, newName: string): Collection<TData, TNested> {\n    const c = this.getCollection<TData, TNested>(oldName);\n    if (c) {\n      c.name = newName;\n    }\n    return c;\n  }\n\n  public listCollections(): { name: string, count: number }[] {\n    const colls = [];\n    for (let i = 0; i < this._collections.length; i++) {\n      colls.push({\n        name: this._collections[i].name,\n        count: this._collections[i].count()\n      });\n    }\n    return colls;\n  }\n\n  /**\n   * Removes a collection from the database.\n   * @param {string} collectionName - name of collection to remove\n   */\n  public removeCollection(collectionName: string): void {\n    for (let i = 0; i < this._collections.length; i++) {\n      if (this._collections[i].name === collectionName) {\n        const tmpcol = new Collection(collectionName, {});\n        const curcol = this._collections[i];\n        for (const prop in curcol) {\n          if (curcol[prop] !== undefined && tmpcol[prop] !== undefined) {\n            curcol[prop] = tmpcol[prop];\n          }\n        }\n        this._collections.splice(i, 1);\n        return;\n      }\n    }\n  }\n\n  /**\n   * Serialize database to a string which can be loaded via {@link Loki#loadJSON}\n   *\n   * @returns {string} Stringified representation of the loki database.\n   */\n  public serialize(options: Loki.SerializeOptions = {}) {\n    if (options.serializationMethod === undefined) {\n      options.serializationMethod = this._serializationMethod;\n    }\n\n    switch (options.serializationMethod) {\n      case \"normal\":\n        return JSON.stringify(this);\n      case \"pretty\":\n        return JSON.stringify(this, null, 2);\n      case \"destructured\":\n        return this.serializeDestructured(); // use default options\n      default:\n        return JSON.stringify(this);\n    }\n  }\n\n  // alias of serialize\n  public toJSON(): Loki.Serialized {\n    return {\n      _env: this._env,\n      _serializationMethod: this._serializationMethod,\n      _autosave: this._autosave,\n      _autosaveInterval: this._autosaveInterval,\n      _collections: this._collections,\n      databaseVersion: this.databaseVersion,\n      engineVersion: this.engineVersion,\n      filename: this.filename,\n      _persistenceAdapter: this._persistenceAdapter,\n      _persistenceMethod: this._persistenceMethod,\n      _throttledSaves: this._throttledSaves\n    };\n  }\n\n  /**\n   * Database level destructured JSON serialization routine to allow alternate serialization methods.\n   * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n   * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n   * your own structured persistence or data exchange.\n   *\n   * @param {object} options - output format options for use externally to loki\n   * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n   * @param {int} options.partition - can be used to only output an individual collection or db (-1)\n   * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n   * @param {string} options.delimiter - override default delimiter\n   *\n   * @returns {string|Array} A custom, restructured aggregation of independent serializations.\n   */\n  public serializeDestructured(options: Loki.SerializeDestructuredOptions = {}): string | string[] {\n    if (options.partitioned === undefined) {\n      options.partitioned = false;\n    }\n\n    if (options.delimited === undefined) {\n      options.delimited = true;\n    }\n\n    if (options.delimiter === undefined) {\n      options.delimiter = this._destructureDelimiter;\n    }\n\n    // 'partitioned' along with 'partition' of 0 or greater is a request for single collection serialization\n    if (options.partitioned === true && options.partition !== undefined && options.partition >= 0) {\n      return this.serializeCollection({\n        delimited: options.delimited,\n        delimiter: options.delimiter,\n        collectionIndex: options.partition\n      });\n    }\n\n    // not just an individual collection, so we will need to serialize db container via shallow copy\n    let dbcopy = new Loki(this.filename);\n    dbcopy.loadJSONObject(this);\n\n    for (let idx = 0; idx < dbcopy._collections.length; idx++) {\n      dbcopy._collections[idx]._data = [];\n    }\n\n    // if we -only- wanted the db container portion, return it now\n    if (options.partitioned === true && options.partition === -1) {\n      // since we are deconstructing, override serializationMethod to normal for here\n      return dbcopy.serialize({\n        serializationMethod: \"normal\"\n      });\n    }\n\n    // at this point we must be deconstructing the entire database\n    // start by pushing db serialization into first array element\n    const reconstruct: string[] = [];\n    reconstruct.push(dbcopy.serialize({\n      serializationMethod: \"normal\"\n    }) as string);\n\n    dbcopy = null;\n\n    // push collection data into subsequent elements\n    for (let idx = 0; idx < this._collections.length; idx++) {\n      let result = this.serializeCollection({\n        delimited: options.delimited,\n        delimiter: options.delimiter,\n        collectionIndex: idx\n      });\n\n      // NDA : Non-Delimited Array : one iterable concatenated array with empty string collection partitions\n      if (options.partitioned === false && options.delimited === false) {\n        if (!Array.isArray(result)) {\n          throw new Error(\"a nondelimited, non partitioned collection serialization did not return an expected array\");\n        }\n\n        // Array.concat would probably duplicate memory overhead for copying strings.\n        // Instead copy each individually, and clear old value after each copy.\n        // Hopefully this will allow g.c. to reduce memory pressure, if needed.\n        for (let sidx = 0; sidx < result.length; sidx++) {\n          reconstruct.push(result[sidx]);\n          result[sidx] = null;\n        }\n        reconstruct.push(\"\");\n      } else {\n        reconstruct.push(result as string);\n      }\n    }\n\n    // Reconstruct / present results according to four combinations : D, DA, NDA, NDAA\n    if (options.partitioned) {\n      // DA : Delimited Array of strings [0] db [1] collection [n] collection { partitioned: true, delimited: true }\n      // useful for simple future adaptations of existing persistence adapters to save collections separately\n      if (options.delimited) {\n        return reconstruct;\n      }\n      // NDAA : Non-Delimited Array with subArrays. db at [0] and collection subarrays at [n] { partitioned: true, delimited : false }\n      // This format might be the most versatile for 'rolling your own' partitioned sync or save.\n      // Memory overhead can be reduced by specifying a specific partition, but at this code path they did not, so its all.\n      else {\n        return reconstruct;\n      }\n    } else {\n      // D : one big Delimited string { partitioned: false, delimited : true }\n      // This is the method Loki will use internally if 'destructured'.\n      // Little memory overhead improvements but does not require multiple asynchronous adapter call scheduling\n      if (options.delimited) {\n        // indicate no more collections\n        reconstruct.push(\"\");\n\n        return reconstruct.join(options.delimiter);\n      }\n      // NDA : Non-Delimited Array : one iterable array with empty string collection partitions { partitioned: false, delimited: false }\n      // This format might be best candidate for custom synchronous syncs or saves\n      else {\n        // indicate no more collections\n        reconstruct.push(\"\");\n\n        return reconstruct;\n      }\n    }\n  }\n\n  /**\n   * Collection level utility method to serialize a collection in a 'destructured' format\n   *\n   * @param {object} options - used to determine output of method\n   * @param {int} options.delimited - whether to return single delimited string or an array\n   * @param {string} options.delimiter - (optional) if delimited, this is delimiter to use\n   * @param {int} options.collectionIndex -  specify which collection to serialize data for\n   *\n   * @returns {string|array} A custom, restructured aggregation of independent serializations for a single collection.\n   */\n  public serializeCollection(options: { delimited?: boolean; collectionIndex?: number; delimiter?: string } = {}): string | string[] {\n    if (options.delimited === undefined) {\n      options.delimited = true;\n    }\n\n    if (options.collectionIndex === undefined) {\n      throw new Error(\"serializeCollection called without 'collectionIndex' option\");\n    }\n    const doccount = this._collections[options.collectionIndex].count();\n\n    let resultlines = [];\n    for (let docidx = 0; docidx < doccount; docidx++) {\n      resultlines.push(JSON.stringify(this._collections[options.collectionIndex]._data[docidx]));\n    }\n\n    // D and DA\n    if (options.delimited) {\n      // indicate no more documents in collection (via empty delimited string)\n      resultlines.push(\"\");\n\n      return resultlines.join(options.delimiter);\n    } else {\n      // NDAA and NDA\n      return resultlines;\n    }\n  }\n\n  /**\n   * Database level destructured JSON deserialization routine to minimize memory overhead.\n   * Internally, Loki supports destructuring via loki \"serializationMethod' option and\n   * the optional LokiPartitioningAdapter class. It is also available if you wish to do\n   * your own structured persistence or data exchange.\n   *\n   * @param {string|array} destructuredSource - destructured json or array to deserialize from\n   * @param {object} options - source format options\n   * @param {boolean} [options.partitioned=false] - whether db and each collection are separate\n   * @param {int} options.partition - can be used to deserialize only a single partition\n   * @param {boolean} [options.delimited=true] - whether subitems are delimited or subarrays\n   * @param {string} options.delimiter - override default delimiter\n   *\n   * @returns {object|array} An object representation of the deserialized database, not yet applied to 'this' db or document array\n   */\n  public deserializeDestructured(destructuredSource: string | string[], options: Loki.SerializeDestructuredOptions = {}) {\n    if (options.partitioned === undefined) {\n      options.partitioned = false;\n    }\n\n    if (options.delimited === undefined) {\n      options.delimited = true;\n    }\n\n    if (options.delimiter === undefined) {\n      options.delimiter = this._destructureDelimiter;\n    }\n\n    // Partitioned\n    // DA : Delimited Array of strings [0] db [1] collection [n] collection { partitioned: true, delimited: true }\n    // NDAA : Non-Delimited Array with subArrays. db at [0] and collection subarrays at [n] { partitioned: true, delimited : false }\n    // -or- single partition\n    if (options.partitioned) {\n      // handle single partition\n      if (options.partition !== undefined) {\n        // db only\n        if (options.partition === -1) {\n          return JSON.parse(destructuredSource[0]);\n        }\n\n        // single collection, return doc array\n        return this.deserializeCollection(destructuredSource[options.partition + 1], options);\n      }\n\n      // Otherwise we are restoring an entire partitioned db\n      const cdb = JSON.parse(destructuredSource[0]);\n      const collCount = cdb._collections.length;\n      for (let collIndex = 0; collIndex < collCount; collIndex++) {\n        // attach each collection docarray to container collection data, add 1 to collection array index since db is at 0\n        cdb._collections[collIndex]._data = this.deserializeCollection(destructuredSource[collIndex + 1], options);\n      }\n\n      return cdb;\n    }\n\n    // Non-Partitioned\n    // D : one big Delimited string { partitioned: false, delimited : true }\n    // NDA : Non-Delimited Array : one iterable array with empty string collection partitions { partitioned: false, delimited: false }\n\n    let workarray = [];\n\n    // D\n    if (options.delimited) {\n      workarray = (destructuredSource as string).split(options.delimiter);\n      destructuredSource = null; // lower memory pressure\n      if (workarray.length === 0) {\n        return null;\n      }\n    }\n    // NDA\n    else {\n      workarray = destructuredSource as string[];\n    }\n\n    // first line is database and collection shells\n    const cdb = JSON.parse(workarray[0]);\n    const collCount = cdb._collections.length;\n    workarray[0] = null;\n\n    let collIndex = 0;\n    let lineIndex = 1;\n    let done = false;\n    while (!done) {\n      // empty string indicates either end of collection or end of file\n      if (workarray[lineIndex] === \"\") {\n        // if no more collections to load into, we are done\n        if (++collIndex > collCount) {\n          done = true;\n        }\n      } else {\n        cdb._collections[collIndex]._data.push(JSON.parse(workarray[lineIndex]));\n      }\n\n      // lower memory pressure and advance iterator\n      workarray[lineIndex++] = null;\n    }\n\n    return cdb;\n  }\n\n  /**\n   * Collection level utility function to deserializes a destructured collection.\n   *\n   * @param {string|string[]} destructuredSource - destructured representation of collection to inflate\n   * @param {object} options - used to describe format of destructuredSource input\n   * @param {int} [options.delimited=false] - whether source is delimited string or an array\n   * @param {string} options.delimiter - if delimited, this is delimiter to use (if other than default)\n   *\n   * @returns {Array} an array of documents to attach to collection.data.\n   */\n  public deserializeCollection<T extends object = object>(destructuredSource: string | string[], options: Loki.DeserializeCollectionOptions = {}): Doc<T>[] {\n    if (options.partitioned === undefined) {\n      options.partitioned = false;\n    }\n\n    if (options.delimited === undefined) {\n      options.delimited = true;\n    }\n\n    if (options.delimiter === undefined) {\n      options.delimiter = this._destructureDelimiter;\n    }\n\n    let workarray = [];\n    if (options.delimited) {\n      workarray = (destructuredSource as string).split(options.delimiter);\n      workarray.pop();\n    } else {\n      workarray = destructuredSource as string[];\n    }\n\n    for (let idx = 0; idx < workarray.length; idx++) {\n      workarray[idx] = JSON.parse(workarray[idx]);\n    }\n    return workarray as any as Doc<T>[];\n  }\n\n  /**\n   * Inflates a loki database from a serialized JSON string\n   *\n   * @param {string} serializedDb - a serialized loki database string\n   * @param {object} options - apply or override collection level settings\n   * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n   */\n  public loadJSON(serializedDb: string | string[], options?: Collection.DeserializeOptions): void {\n    let dbObject;\n    if (serializedDb.length === 0) {\n      dbObject = {};\n    } else {\n      // using option defined in instantiated db not what was in serialized db\n      switch (this._serializationMethod) {\n        case \"normal\":\n        case \"pretty\":\n          dbObject = JSON.parse(serializedDb as string);\n          break;\n        case \"destructured\":\n          dbObject = this.deserializeDestructured(serializedDb);\n          break;\n        default:\n          dbObject = JSON.parse(serializedDb as string);\n          break;\n      }\n    }\n    this.loadJSONObject(dbObject, options);\n  }\n\n  /**\n   * Inflates a loki database from a JS object\n   *\n   * @param {object} dbObject - a serialized loki database object\n   * @param {object} options - apply or override collection level settings\n   * @param {boolean} options.retainDirtyFlags - whether collection dirty flags will be preserved\n   */\n  public loadJSONObject(dbObject: Loki, options?: Collection.DeserializeOptions): void;\n  public loadJSONObject(dbObject: Loki.Serialized, options?: Collection.DeserializeOptions): void;\n  public loadJSONObject(dbObject: any, options: Collection.DeserializeOptions = {}): void {\n    const len = dbObject._collections ? dbObject._collections.length : 0;\n\n    this.filename = dbObject.filename;\n    this._collections = [];\n\n    for (let i = 0; i < len; ++i) {\n      this._collections.push(Collection.fromJSONObject(dbObject._collections[i], options));\n    }\n  }\n\n  /**\n   * Emits the close event. In autosave scenarios, if the database is dirty, this will save and disable timer.\n   * Does not actually destroy the db.\n   *\n   * @returns {Promise} a Promise that resolves after closing the database succeeded\n   */\n  public close(): Promise<void> {\n    // for autosave scenarios, we will let close perform final save (if dirty)\n    // For web use, you might call from window.onbeforeunload to shutdown database, saving pending changes\n    if (this._autosave) {\n      return this._autosaveDisable()\n        .then(() => {\n          if (this._autosaveDirty()) {\n            return this.saveDatabase();\n          }\n          return Promise.resolve();\n        });\n    }\n\n    return Promise.resolve().then(() => {\n      this.emit(\"close\");\n    });\n  }\n\n  /**-------------------------+\n   | Changes API               |\n   +--------------------------*/\n\n  /**\n   * The Changes API enables the tracking the changes occurred in the collections since the beginning of the session,\n   * so it's possible to create a differential dataset for synchronization purposes (possibly to a remote db)\n   */\n\n  /**\n   * (Changes API) : takes all the changes stored in each\n   * collection and creates a single array for the entire database. If an array of names\n   * of collections is passed then only the included collections will be tracked.\n   *\n   * @param {Array} [arrayOfCollectionNames=] - array of collection names. No arg means all collections are processed.\n   * @returns {Array} array of changes\n   * @see private method _createChange() in Collection\n   */\n  public generateChangesNotification(arrayOfCollectionNames?: string[]): Collection.Change[] {\n    let changes: Collection.Change[] = [];\n    const selectedCollections = arrayOfCollectionNames\n      || this._collections.map((coll: Collection) => coll.name);\n\n    this._collections.forEach((coll) => {\n      if (selectedCollections.indexOf(coll.name) !== -1) {\n        changes = changes.concat(coll.getChanges());\n      }\n    });\n    return changes;\n  }\n\n  /**\n   * (Changes API) - stringify changes for network transmission\n   * @returns {string} string representation of the changes\n   */\n  public serializeChanges(collectionNamesArray?: string[]) {\n    return JSON.stringify(this.generateChangesNotification(collectionNamesArray));\n  }\n\n  /**\n   * (Changes API) : clears all the changes in all collections.\n   */\n  public clearChanges() {\n    this._collections.forEach((coll) => {\n      if (coll.flushChanges) {\n        coll.flushChanges();\n      }\n    });\n  }\n\n  /**\n   * Wait for throttledSaves to complete and invoke your callback when drained or duration is met.\n   *\n   * @param {object} options - configuration options\n   * @param {boolean} [options.recursiveWait=true] - if after queue is drained, another save was kicked off, wait for it\n   * @param {boolean} [options.recursiveWaitLimit=false] - limit our recursive waiting to a duration\n   * @param {number} [options.recursiveWaitLimitDuration=2000] - cutoff in ms to stop recursively re-draining\n   * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n   * @returns {Promise} a Promise that resolves when save queue is drained, it is passed a sucess parameter value\n   */\n  throttledSaveDrain(options: Loki.ThrottledDrainOptions = {}): Promise<void> {\n    const now = (new Date()).getTime();\n\n    if (!this._throttledSaves) {\n      return Promise.resolve();\n    }\n\n    if (options.recursiveWait === undefined) {\n      options.recursiveWait = true;\n    }\n    if (options.recursiveWaitLimit === undefined) {\n      options.recursiveWaitLimit = false;\n    }\n    if (options.recursiveWaitLimitDuration === undefined) {\n      options.recursiveWaitLimitDuration = 2000;\n    }\n    if (options.started === undefined) {\n      options.started = new Date();\n    }\n\n    // if save is pending\n    if (this._throttledSaves && this._throttledSaveRunning !== null) {\n      // if we want to wait until we are in a state where there are no pending saves at all\n      if (options.recursiveWait) {\n        // queue the following meta callback for when it completes\n        return Promise.resolve(Promise.all([this._throttledSaveRunning, this._throttledSavePending])).then(() => {\n          if (this._throttledSaveRunning !== null || this._throttledSavePending !== null) {\n            if (options.recursiveWaitLimit && (now - options.started.getTime() > options.recursiveWaitLimitDuration)) {\n              return Promise.reject({});\n            }\n            return this.throttledSaveDrain(options);\n          } else {\n            return Promise.resolve();\n          }\n        });\n      }\n      // just notify when current queue is depleted\n      else {\n        return Promise.resolve(this._throttledSaveRunning);\n      }\n    }\n    // no save pending, just callback\n    else {\n      return Promise.resolve();\n    }\n  }\n\n  /**\n   * Internal load logic, decoupled from throttling/contention logic\n   *\n   * @param {object} options - an object containing inflation options for each collection\n   * @param {boolean} ignore_not_found - does not raise an error if database is not found\n   * @returns {Promise} a Promise that resolves after the database is loaded\n   */\n  private _loadDatabase(options = {}, ignore_not_found = false) {\n    // the persistenceAdapter should be present if all is ok, but check to be sure.\n    if (this._persistenceAdapter === null) {\n      return Promise.reject(new Error(\"persistenceAdapter not configured\"));\n    }\n\n    return Promise.resolve(this._persistenceAdapter.loadDatabase(this.filename))\n      .then((dbString) => {\n        if (typeof (dbString) === \"string\") {\n          this.loadJSON(dbString, options);\n          this.emit(\"load\", this);\n          // if adapter has returned a js object (other than null or error) attempt to load from JSON object\n        } else if (typeof (dbString) === \"object\" && dbString !== null && !(dbString instanceof Error)) {\n          this.loadJSONObject(dbString, options);\n          this.emit(\"load\", this);\n        } else {\n          throw dbString;\n        }\n      }).catch(e => {\n        if (e instanceof Error) {\n          throw e;\n        } else if (e != null) {\n          throw new TypeError(\"The persistence adapter did not load a serialized DB string or object.\");\n        } else if (!ignore_not_found) {\n          throw new Error(\"Database not found.\");\n        }\n      });\n  }\n\n  /**\n   * Handles manually loading from an adapter storage (such as fs-storage)\n   *    This method utilizes loki configuration options (if provided) to determine which\n   *    persistence method to use, or environment detection (if configuration was not provided).\n   *    To avoid contention with any throttledSaves, we will drain the save queue first.\n   *\n   * If you are configured with autosave, you do not need to call this method yourself.\n   *\n   * @param {object} [options={}] - if throttling saves and loads, this controls how we drain save queue before loading\n   * @param {boolean} [options.recursiveWait=true] wait recursively until no saves are queued\n   * @param {boolean} [options.recursiveWaitLimit=false] limit our recursive waiting to a duration\n   * @param {number} [options.recursiveWaitLimitDelay=2000] cutoff in ms to stop recursively re-draining\n   * @param {Date} [options.started=now()] - the start time of the recursive wait duration\n   * @returns {Promise} a Promise that resolves after the database is loaded\n   */\n  public loadDatabase(options: Loki.LoadDatabaseOptions = {}): Promise<void> {\n    // if throttling disabled, just call internal\n    if (!this._throttledSaves) {\n      return this._loadDatabase(options);\n    }\n\n    // try to drain any pending saves in the queue to lock it for loading\n    return this.throttledSaveDrain(options).then(() => {\n      // pause/throttle saving until loading is done\n      this._throttledSaveRunning = this._loadDatabase(options).then(() => {\n        // now that we are finished loading, if no saves were throttled, disable flag\n        this._throttledSaveRunning = null;\n      });\n      return this._throttledSaveRunning;\n    }, () => {\n      throw new Error(\"Unable to pause save throttling long enough to read database\");\n    });\n  }\n\n  private _saveDatabase() {\n    // the persistenceAdapter should be present if all is ok, but check to be sure.\n    if (this._persistenceAdapter === null) {\n      return Promise.reject(new Error(\"persistenceAdapter not configured\"));\n    }\n\n    // check if the adapter is requesting (and supports) a 'reference' mode export\n    if (this._persistenceAdapter.mode === \"reference\" && typeof this._persistenceAdapter.exportDatabase === \"function\") {\n      // filename may seem redundant but loadDatabase will need to expect this same filename\n      return Promise.resolve(this._persistenceAdapter.exportDatabase(this.filename, this.copy({removeNonSerializable: true})))\n        .then(() => {\n          this._autosaveClearFlags();\n          this.emit(\"save\");\n        });\n    }\n\n    // otherwise just pass the serialized database to adapter\n    // persistenceAdapter might be asynchronous, so we must clear `dirty` immediately\n    // or autosave won't work if an update occurs between here and the callback\n    this._autosaveClearFlags();\n    return Promise.resolve(this._persistenceAdapter.saveDatabase(this.filename, this.serialize() as string))\n      .then(() => {\n        this.emit(\"save\");\n      });\n  }\n\n  /**\n   * Handles manually saving to an adapter storage (such as fs-storage)\n   *    This method utilizes loki configuration options (if provided) to determine which\n   *    persistence method to use, or environment detection (if configuration was not provided).\n   *\n   * If you are configured with autosave, you do not need to call this method yourself.\n   *\n   * @returns {Promise} a Promise that resolves after the database is persisted\n   */\n  public saveDatabase() {\n    if (!this._throttledSaves) {\n      return this._saveDatabase();\n    }\n\n    // if the db save is currently running, a new promise for a next db save is created\n    // all calls to save db will get this new promise which will be processed right after\n    // the current db save is finished\n    if (this._throttledSaveRunning !== null && this._throttledSavePending === null) {\n      this._throttledSavePending = Promise.resolve(this._throttledSaveRunning).then(() => {\n        this._throttledSaveRunning = null;\n        this._throttledSavePending = null;\n        return this.saveDatabase();\n      });\n    }\n\n    if (this._throttledSavePending !== null) {\n      return this._throttledSavePending;\n    }\n    this._throttledSaveRunning = this._saveDatabase().then(() => {\n      this._throttledSaveRunning = null;\n    });\n\n    return this._throttledSaveRunning;\n  }\n\n  /**\n   * Handles deleting a database from the underlying storage adapter\n   *\n   * @returns {Promise} a Promise that resolves after the database is deleted\n   */\n  public deleteDatabase() {\n    // the persistenceAdapter should be present if all is ok, but check to be sure.\n    if (this._persistenceAdapter === null) {\n      return Promise.reject(new Error(\"persistenceAdapter not configured\"));\n    }\n\n    return Promise.resolve(this._persistenceAdapter.deleteDatabase(this.filename));\n  }\n\n  /****************\n   * Autosave API\n   ****************/\n\n  /**\n   * Check whether any collections are \"dirty\" meaning we need to save the (entire) database\n   * @returns {boolean} - true if database has changed since last autosave, otherwise false\n   */\n  private _autosaveDirty(): boolean {\n    for (let idx = 0; idx < this._collections.length; idx++) {\n      if (this._collections[idx]._dirty) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  /**\n   * Resets dirty flags on all collections.\n   */\n  private _autosaveClearFlags() {\n    for (let idx = 0; idx < this._collections.length; idx++) {\n      this._collections[idx]._dirty = false;\n    }\n  }\n\n  /**\n   * Starts periodically saves to the underlying storage adapter.\n   */\n  private _autosaveEnable(): void {\n    if (!this._autosave || this._autosaveRunning) {\n      return;\n    }\n    this._autosaveRunning = true;\n\n    const interval = setInterval(() => {\n      if (!this._autosaveRunning) {\n        clearInterval(interval);\n      } else if (this._autosaveDirty()) {\n        this._autosaveHandler = this._autosaveHandler\n          .then(() => {\n            return this.saveDatabase();\n          });\n      }\n    }, this._autosaveInterval);\n  }\n\n  /**\n   * Stops the autosave interval timer.\n   */\n  private _autosaveDisable(): Promise<void> {\n    this._autosaveRunning = false;\n    return this._autosaveHandler;\n  }\n}\n\nexport namespace Loki {\n  export interface Options {\n    env?: Environment;\n    serializationMethod?: SerializationMethod;\n    destructureDelimiter?: string;\n    comparatorMap?: IComparatorMap;\n    rangedIndexFactoryMap?: IRangedIndexFactoryMap;\n    lokiOperatorPackageMap?: ILokiOperatorPackageMap;\n  }\n\n  export interface PersistenceOptions {\n    adapter?: StorageAdapter;\n    autosave?: boolean;\n    autosaveInterval?: number;\n    autoload?: boolean;\n    throttledSaves?: boolean;\n    persistenceMethod?: Loki.PersistenceMethod;\n    inflate?: any;\n  }\n\n  export interface CopyOptions {\n    removeNonSerializable?: boolean;\n  }\n\n  export interface SerializeOptions {\n    serializationMethod?: SerializationMethod;\n  }\n\n  export interface SerializeDestructuredOptions {\n    partitioned?: boolean;\n    partition?: number;\n    delimited?: boolean;\n    delimiter?: string;\n  }\n\n  export interface DeserializeCollectionOptions {\n    partitioned?: boolean;\n    delimited?: boolean;\n    delimiter?: string;\n  }\n\n  export interface ThrottledDrainOptions {\n    recursiveWait?: boolean;\n    recursiveWaitLimit?: boolean;\n    recursiveWaitLimitDuration?: number;\n    started?: Date;\n  }\n\n  export interface Serialized {\n    _env: Environment;\n    _serializationMethod: SerializationMethod;\n    _autosave: boolean;\n    _autosaveInterval: number;\n    _collections: Collection[];\n    databaseVersion: number;\n    engineVersion: number;\n    filename: string;\n    _persistenceAdapter: StorageAdapter;\n    _persistenceMethod: PersistenceMethod;\n    _throttledSaves: boolean;\n  }\n\n  export type LoadDatabaseOptions = Collection.DeserializeOptions & ThrottledDrainOptions;\n\n  export type SerializationMethod = \"normal\" | \"pretty\" | \"destructured\";\n\n  export type PersistenceMethod = \"fs-storage\" | \"local-storage\" | \"indexed-storage\" | \"memory-storage\" | \"adapter\";\n\n  export type Environment = \"NATIVESCRIPT\" | \"NODEJS\" | \"CORDOVA\" | \"BROWSER\" | \"MEMORY\";\n}\n"
  },
  {
    "path": "packages/loki/src/operator_packages.ts",
    "content": "import { ILokiComparer } from \"./comparators\";\n\n/** Hash interface for named LokiOperatorPackage registration */\nexport interface ILokiOperatorPackageMap {\n  [name: string]: LokiOperatorPackage;\n}\n\n/**\n * Helper function for determining 'loki' abstract equality which is a little more abstract than ==\n *     aeqHelper(5, '5') === true\n *     aeqHelper(5.0, '5') === true\n *     aeqHelper(new Date(\"1/1/2011\"), new Date(\"1/1/2011\")) === true\n *     aeqHelper({a:1}, {z:4}) === true (all objects sorted equally)\n *     aeqHelper([1, 2, 3], [1, 3]) === false\n *     aeqHelper([1, 2, 3], [1, 2, 3]) === true\n *     aeqHelper(undefined, null) === true\n * @param {any} prop1\n * @param {any} prop2\n * @returns {boolean}\n * @hidden\n */\nexport function aeqHelper(prop1: any, prop2: any): boolean {\n  if (prop1 === prop2) return true;\n\n  // 'falsy' and Boolean handling\n  if (!prop1 || !prop2 || prop1 === true || prop2 === true || prop1 !== prop1 || prop2 !== prop2) {\n    let t1: number;\n    let t2: number;\n\n    // dates and NaN conditions (typed dates before serialization)\n    switch (prop1) {\n      case undefined:\n        t1 = 1;\n        break;\n      case null:\n        t1 = 1;\n        break;\n      case false:\n        t1 = 3;\n        break;\n      case true:\n        t1 = 4;\n        break;\n      case \"\":\n        t1 = 5;\n        break;\n      default:\n        t1 = (prop1 === prop1) ? 9 : 0;\n        break;\n    }\n\n    switch (prop2) {\n      case undefined:\n        t2 = 1;\n        break;\n      case null:\n        t2 = 1;\n        break;\n      case false:\n        t2 = 3;\n        break;\n      case true:\n        t2 = 4;\n        break;\n      case \"\":\n        t2 = 5;\n        break;\n      default:\n        t2 = (prop2 === prop2) ? 9 : 0;\n        break;\n    }\n\n    // one or both is edge case\n    if (t1 !== 9 || t2 !== 9) {\n      return (t1 === t2);\n    }\n  }\n\n  // Handle 'Number-like' comparisons\n  let cv1 = Number(prop1);\n  let cv2 = Number(prop2);\n\n  // if one or both are 'number-like'...\n  if (cv1 === cv1 || cv2 === cv2) {\n    return (cv1 === cv2);\n  }\n\n  // not strict equal nor less than nor gt so must be mixed types, convert to string and use that to compare\n  cv1 = prop1.toString();\n  cv2 = prop2.toString();\n\n  return (cv1 == cv2);\n}\n\n/**\n * Helper function for determining 'less-than' conditions for ops, sorting, and binary indices.\n *     In the future we might want $lt and $gt ops to use their own functionality/helper.\n *     Since binary indices on a property might need to index [12, NaN, new Date(), Infinity], we\n *     need this function (as well as gtHelper) to always ensure one value is LT, GT, or EQ to another.\n * @hidden\n */\nexport function ltHelper(prop1: any, prop2: any, equal: boolean): boolean {\n  // if one of the params is falsy or strictly true or not equal to itself\n  // 0, 0.0, \"\", NaN, null, undefined, not defined, false, true\n  if (!prop1 || !prop2 || prop1 === true || prop2 === true || prop1 !== prop1 || prop2 !== prop2) {\n    let t1: number;\n    let t2: number;\n\n    switch (prop1) {\n      case undefined:\n        t1 = 1;\n        break;\n      case null:\n        t1 = 1;\n        break;\n      case false:\n        t1 = 3;\n        break;\n      case true:\n        t1 = 4;\n        break;\n      case \"\":\n        t1 = 5;\n        break;\n      // if strict equal probably 0 so sort higher, otherwise probably NaN so sort lower than even null\n      default:\n        t1 = (prop1 === prop1) ? 9 : 0;\n        break;\n    }\n\n    switch (prop2) {\n      case undefined:\n        t2 = 1;\n        break;\n      case null:\n        t2 = 1;\n        break;\n      case false:\n        t2 = 3;\n        break;\n      case true:\n        t2 = 4;\n        break;\n      case \"\":\n        t2 = 5;\n        break;\n      default:\n        t2 = (prop2 === prop2) ? 9 : 0;\n        break;\n    }\n\n    // one or both is edge case\n    if (t1 !== 9 || t2 !== 9) {\n      return (t1 === t2) ? equal : (t1 < t2);\n    }\n  }\n\n  // if both are numbers (string encoded or not), compare as numbers\n  let cv1 = Number(prop1);\n  let cv2 = Number(prop2);\n\n  if (cv1 === cv1 && cv2 === cv2) {\n    if (cv1 < cv2) return true;\n    if (cv1 > cv2) return false;\n    return equal;\n  }\n\n  if (cv1 === cv1 && cv2 !== cv2) {\n    return true;\n  }\n\n  if (cv2 === cv2 && cv1 !== cv1) {\n    return false;\n  }\n\n  if (prop1 < prop2) return true;\n  if (prop1 > prop2) return false;\n  if (prop1 == prop2) return equal;\n\n  // not strict equal nor less than nor gt so must be mixed types, convert to string and use that to compare\n  cv1 = prop1.toString();\n  cv2 = prop2.toString();\n\n  if (cv1 < cv2) {\n    return true;\n  }\n\n  if (cv1 == cv2) {\n    return equal;\n  }\n\n  return false;\n}\n\n/**\n * @hidden\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} equal\n * @returns {boolean}\n */\nexport function gtHelper(prop1: any, prop2: any, equal: boolean): boolean {\n  // 'falsy' and Boolean handling\n  if (!prop1 || !prop2 || prop1 === true || prop2 === true || prop1 !== prop1 || prop2 !== prop2) {\n    let t1: number;\n    let t2: number;\n\n    switch (prop1) {\n      case undefined:\n        t1 = 1;\n        break;\n      case null:\n        t1 = 1;\n        break;\n      case false:\n        t1 = 3;\n        break;\n      case true:\n        t1 = 4;\n        break;\n      case \"\":\n        t1 = 5;\n        break;\n      // NaN 0\n      default:\n        t1 = (prop1 === prop1) ? 9 : 0;\n        break;\n    }\n\n    switch (prop2) {\n      case undefined:\n        t2 = 1;\n        break;\n      case null:\n        t2 = 1;\n        break;\n      case false:\n        t2 = 3;\n        break;\n      case true:\n        t2 = 4;\n        break;\n      case \"\":\n        t2 = 5;\n        break;\n      default:\n        t2 = (prop2 === prop2) ? 9 : 0;\n        break;\n    }\n\n    // one or both is edge case\n    if (t1 !== 9 || t2 !== 9) {\n      return (t1 === t2) ? equal : (t1 > t2);\n    }\n  }\n\n  // if both are numbers (string encoded or not), compare as numbers\n  let cv1 = Number(prop1);\n  let cv2 = Number(prop2);\n  if (cv1 === cv1 && cv2 === cv2) {\n    if (cv1 > cv2) return true;\n    if (cv1 < cv2) return false;\n    return equal;\n  }\n\n  if (cv1 === cv1 && cv2 !== cv2) {\n    return false;\n  }\n\n  if (cv2 === cv2 && cv1 !== cv1) {\n    return true;\n  }\n\n  if (prop1 > prop2) return true;\n  if (prop1 < prop2) return false;\n  if (prop1 == prop2) return equal;\n\n  // not strict equal nor less than nor gt so must be dates or mixed types\n  // convert to string and use that to compare\n  cv1 = prop1.toString();\n  cv2 = prop2.toString();\n\n  if (cv1 > cv2) {\n    return true;\n  }\n\n  if (cv1 == cv2) {\n    return equal;\n  }\n\n  return false;\n}\n\n/**\n * @param {any} prop1\n * @param {any} prop2\n * @param {boolean} descending\n * @returns {number}\n * @hidden\n */\nexport function sortHelper(prop1: any, prop2: any, descending: boolean): number {\n  if (aeqHelper(prop1, prop2)) {\n    return 0;\n  }\n\n  if (ltHelper(prop1, prop2, false)) {\n    return descending ? 1 : -1;\n  }\n\n  if (gtHelper(prop1, prop2, false)) {\n    return descending ? -1 : 1;\n  }\n\n  // not lt, not gt so implied equality-- date compatible\n  return 0;\n}\n\n/**\n * Default implementation of LokiOperatorPackage, using fastest javascript comparison operators.\n */\nexport class LokiOperatorPackage {\n  // comparison operators\n  // a is the value in the collection\n  // b is the query value\n  $eq(a: any, b: any): boolean {\n    return a === b;\n  }\n\n  $ne(a: any, b: any): boolean {\n    return a !== b;\n  }\n\n  $gt(a: any, b: any): boolean {\n    return a > b;\n  }\n\n  $gte(a: any, b: any): boolean {\n    return a >= b;\n  }\n\n  $lt(a: any, b: any): boolean {\n    return a < b;\n  }\n\n  $lte(a: any, b: any): boolean {\n    return a <= b;\n  }\n\n  $between(a: any, range: [any, any]): boolean {\n    if (a === undefined || a === null) return false;\n    return a >= range[0] && a <= range[1];\n  }\n\n  $in(a: any, b: any): boolean {\n    return b.indexOf(a) !== -1;\n  }\n\n  $nin(a: any, b: any): boolean {\n    return b.indexOf(a) === -1;\n  }\n\n  $keyin(a: string, b: object): boolean {\n    return a in b;\n  }\n\n  $nkeyin(a: string, b: object): boolean {\n    return !(a in b);\n  }\n\n  $definedin(a: string, b: object): boolean {\n    return b[a] !== undefined;\n  }\n\n  $undefinedin(a: string, b: object): boolean {\n    return b[a] === undefined;\n  }\n\n  $regex(a: string, b: RegExp): boolean {\n    return b.test(a);\n  }\n\n  $containsNone(a: any, b: any): boolean {\n    return !this.$containsAny(a, b);\n  }\n\n  $containsAny(a: any, b: any): boolean {\n    const checkFn = this.containsCheckFn(a);\n    if (checkFn !== null) {\n      return (Array.isArray(b)) ? (b.some(checkFn)) : (checkFn(b));\n    }\n    return false;\n  }\n\n  $contains(a: any, b: any): boolean {\n    const checkFn = this.containsCheckFn(a);\n    if (checkFn !== null) {\n      return (Array.isArray(b)) ? (b.every(checkFn)) : (checkFn(b));\n    }\n    return false;\n  }\n\n  $type(a: any, b: any): boolean {\n    let type: string = typeof a;\n    if (type === \"object\") {\n      if (Array.isArray(a)) {\n        type = \"array\";\n      } else if (a instanceof Date) {\n        type = \"date\";\n      }\n    }\n    return (typeof b !== \"object\") ? (type === b) : this.doQueryOp(type, b);\n  }\n\n  $finite(a: number, b: boolean): boolean {\n    return (b === isFinite(a));\n  }\n\n  $size(a: any, b: any): boolean {\n    if (Array.isArray(a)) {\n      return (typeof b !== \"object\") ? (a.length === b) : this.doQueryOp(a.length, b);\n    }\n    return false;\n  }\n\n  $len(a: any, b: any): boolean {\n    if (typeof a === \"string\") {\n      return (typeof b !== \"object\") ? (a.length === b) : this.doQueryOp(a.length, b);\n    }\n    return false;\n  }\n\n  $where(a: any, b: any): boolean {\n    return b(a) === true;\n  }\n\n  // field-level logical operators\n  // a is the value in the collection\n  // b is the nested query operation (for '$not')\n  //   or an array of nested query operations (for '$and' and '$or')\n  $not(a: any, b: any): boolean {\n    return !this.doQueryOp(a, b);\n  }\n\n  $and(a: any, b: any): boolean {\n    for (let idx = 0, len = b.length; idx < len; idx++) {\n      if (!this.doQueryOp(a, b[idx])) {\n        return false;\n      }\n    }\n    return true;\n  }\n\n  $or(a: any, b: any): boolean {\n    for (let idx = 0, len = b.length; idx < len; idx++) {\n      if (this.doQueryOp(a, b[idx])) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private doQueryOp(val: any, op: object) {\n    for (let p in op) {\n      if (Object.hasOwnProperty.call(op, p)) {\n        return this[p](val, op[p]);\n      }\n    }\n    return false;\n  }\n\n  private containsCheckFn(a: any) {\n    if (typeof a === \"string\" || Array.isArray(a)) {\n      return (b: any) => (a as any).indexOf(b) !== -1;\n    } else if (typeof a === \"object\" && a !== null) {\n      return (b: string) => Object.hasOwnProperty.call(a, b);\n    }\n    return null;\n  }\n}\n\n/**\n * LokiOperatorPackage which utilizes abstract 'loki' comparisons for basic relational equality op implementations.\n */\nexport class LokiAbstractOperatorPackage extends LokiOperatorPackage {\n  constructor() {\n    super();\n  }\n\n  $eq(a: any, b: any): boolean {\n    return aeqHelper(a, b);\n  }\n\n  $ne(a: any, b: any): boolean {\n    return !aeqHelper(a, b);\n  }\n\n  $gt(a: any, b: any): boolean {\n    return gtHelper(a, b, false);\n  }\n\n  $gte(a: any, b: any): boolean {\n    return gtHelper(a, b, true);\n  }\n\n  $lt(a: any, b: any): boolean {\n    return ltHelper(a, b, false);\n  }\n\n  $lte(a: any, b: any): boolean {\n    return ltHelper(a, b, true);\n  }\n\n  $between(a: any, range: [any, any]): boolean {\n    if (a === undefined || a === null) return false;\n    return gtHelper(a, range[0], true) && ltHelper(a, range[1], true);\n  }\n\n}\n\n/**\n * LokiOperatorPackage which utilizes provided comparator for basic relational equality op implementations.\n */\nexport class ComparatorOperatorPackage<T> extends LokiOperatorPackage {\n  comparator: ILokiComparer<T>;\n\n  constructor(comparator: ILokiComparer<T>) {\n    super();\n    this.comparator = comparator;\n  }\n\n  $eq(a: any, b: any): boolean {\n    return this.comparator(a, b) === 0;\n  }\n\n  $ne(a: any, b: any): boolean {\n    return this.comparator(a, b) !== 0;\n  }\n\n  $gt(a: any, b: any): boolean {\n    return this.comparator(a, b) === 1;\n  }\n\n  $gte(a: any, b: any): boolean {\n    return this.comparator(a, b) > -1;\n  }\n\n  $lt(a: any, b: any): boolean {\n    return this.comparator(a, b) === -1;\n  }\n\n  $lte(a: any, b: any): boolean {\n    return this.comparator(a, b) < 1;\n  }\n\n  $between(a: any, range: [any, any]): boolean {\n    if (a === undefined || a === null) return false;\n    return this.comparator(a, range[0]) > -1 && this.comparator(a, range[1]) < 1;\n  }\n}\n\n/**\n * Map/Register of named LokiOperatorPackages which implement all unindexed query ops within 'find' query objects\n */\nexport let LokiOperatorPackageMap : ILokiOperatorPackageMap = {\n  \"js\" : new LokiOperatorPackage(),\n  \"loki\" : new LokiAbstractOperatorPackage()\n};\n"
  },
  {
    "path": "packages/loki/src/ranged_indexes.ts",
    "content": "import { AvlTreeIndex } from \"./avl_index\";\nimport { ILokiComparer } from \"./comparators\";\n\n/* valid range ops that the index must directly support */\nexport type RangedValueOperator = \"$gt\" | \"$gte\" | \"$lt\" | \"$lte\" | \"$eq\" | \"$neq\" | \"$between\";\n\nexport interface IRangedIndexRequest<T> {\n  op: RangedValueOperator;\n  val: T;\n  high?: T;\n}\n\n/** Defines interface which all loki ranged indexes need to implement */\nexport interface IRangedIndex<T> {\n  insert(id: number, val: T): void;\n  update(id: number, val: T): void;\n  remove(id: number): void;\n  restore(tree: any): void;\n  backup(): IRangedIndex<T>;\n\n  rangeRequest(range?: IRangedIndexRequest<T>): number[];\n\n  validateIndex(): boolean;\n}\n\n/** Hash Interface for global ranged index factory map*/\nexport interface IRangedIndexFactoryMap {\n  [name: string]: (name: string, comparator: ILokiComparer<any>) => IRangedIndex<any>;\n}\n\n/** Map/Register of named factory functions returning IRangedIndex instances */\nexport let RangedIndexFactoryMap: IRangedIndexFactoryMap = {\n  \"avl\": (name: string, comparator: ILokiComparer<any>) => { return new AvlTreeIndex(name, comparator); }\n};\n\n"
  },
  {
    "path": "packages/loki/src/result_set.ts",
    "content": "import { Collection } from \"./collection\";\nimport { clone, CloneMethod } from \"./clone\";\nimport { sortHelper, LokiOperatorPackageMap } from \"./operator_packages\";\nimport { ComparatorMap, ILokiComparer } from \"./comparators\";\nimport { Doc } from \"../../common/types\";\nimport { Scorer } from \"../../full-text-search/src/scorer\";\nimport { Query as FullTextSearchQuery } from \"../../full-text-search/src/query_types\";\n\n// used to recursively scan hierarchical transform step object for param substitution\nfunction resolveTransformObject<T extends object>(subObj: Collection.Transform<T>, params: object, depth: number = 0): Collection.Transform<T> {\n  if (++depth >= 10) {\n    return subObj;\n  }\n\n  for (const prop in subObj) {\n    if (typeof subObj[prop] === \"string\" && subObj[prop].indexOf(\"[%lktxp]\") === 0) {\n      const pname = subObj[prop].substring(8);\n      if (params[pname] !== undefined) {\n        subObj[prop] = params[pname];\n      }\n    } else if (typeof subObj[prop] === \"object\") {\n      subObj[prop] = resolveTransformObject(subObj[prop], params, depth);\n    }\n  }\n  return subObj;\n}\n\n// top level utility to resolve an entire (single) transform (array of steps) for parameter substitution\nfunction resolveTransformParams<T extends object>(transform: Collection.Transform<T>[], params: object): Collection.Transform<T>[] {\n  if (params === undefined) {\n    return transform;\n  }\n\n  // iterate all steps in the transform array\n  const resolvedTransform: Collection.Transform<T>[] = [];\n  for (let idx = 0; idx < transform.length; idx++) {\n    // clone transform so our scan/replace can operate directly on cloned transform\n    const clonedStep = clone(transform[idx], \"shallow-recurse\");\n    resolvedTransform.push(resolveTransformObject<T>(clonedStep, params));\n  }\n\n  return resolvedTransform;\n}\n\n/**\n * @hidden\n */\n// if an op is registered in this object, our 'calculateRange' can use it with our binary indices.\n// if the op is registered to a function, we will run that function/op as a 2nd pass filter on results.\n// those 2nd pass filter functions should be similar to LokiOps functions, accepting 2 vals to compare.\nconst indexedOps = {\n  $eq: true,\n  $dteq: true,\n  $gt: true,\n  $gte: true,\n  $lt: true,\n  $lte: true,\n  $in: true,\n  $between: true\n};\n\n/**\n * ResultSet class allowing chainable queries.  Intended to be instanced internally.\n *    Collection.find(), Collection.where(), and Collection.chain() instantiate this.\n *\n * @example\n *    mycollection.chain()\n *      .find({ 'doors' : 4 })\n *      .where(function(obj) { return obj.name === 'Toyota' })\n *      .data();\n *\n * @param <TData> - the data type\n * @param <TNested> - nested properties of data type\n */\nexport class ResultSet<T extends object = object> {\n\n  public _collection: Collection<T>;\n  public _filteredRows: number[] = [];\n  public _filterInitialized: boolean = false;\n  // Holds the scoring result of the last full-text search.\n  private _scoring: Scorer.ScoreResults = null;\n\n  /**\n   * Constructor.\n   * @param {Collection} collection - the collection which this ResultSet will query against\n   */\n  constructor(collection: Collection<T>) {\n    // retain reference to collection we are querying against\n    this._collection = collection;\n  }\n\n  /**\n   * Reset the ResultSet to its initial state.\n   * @returns {ResultSet} Reference to this ResultSet, for future chain operations.\n   */\n  public reset(): this {\n    if (this._filteredRows.length > 0) {\n      this._filteredRows = [];\n    }\n    this._filterInitialized = false;\n    return this;\n  }\n\n  /**\n   * Override of toJSON to avoid circular references\n   */\n  public toJSON(): ResultSet<T> {\n    const copy = this.copy();\n    copy._collection = null;\n    return copy;\n  }\n\n  /**\n   * Allows you to limit the number of documents passed to next chain operation.\n   * A ResultSet copy() is made to avoid altering original ResultSet.\n   * @param {int} qty - The number of documents to return.\n   * @returns {ResultSet} Returns a copy of the ResultSet, limited by qty, for subsequent chain ops.\n   */\n  public limit(qty: number): this {\n    // if this has no filters applied, we need to populate filteredRows first\n    if (!this._filterInitialized && this._filteredRows.length === 0) {\n      this._filteredRows = this._collection._prepareFullDocIndex();\n    }\n\n    this._filteredRows = this._filteredRows.slice(0, qty);\n    this._filterInitialized = true;\n    return this;\n  }\n\n  /**\n   * Used for skipping 'pos' number of documents in the ResultSet.\n   * @param {int} pos - Number of documents to skip; all preceding documents are filtered out.\n   * @returns {ResultSet} Returns a copy of the ResultSet, containing docs starting at 'pos' for subsequent chain ops.\n   */\n  public offset(pos: number): this {\n    // if this has no filters applied, we need to populate filteredRows first\n    if (!this._filterInitialized && this._filteredRows.length === 0) {\n      this._filteredRows = this._collection._prepareFullDocIndex();\n    }\n\n    this._filteredRows = this._filteredRows.slice(pos);\n    this._filterInitialized = true;\n    return this;\n  }\n\n  /**\n   * To support reuse of ResultSet in branched query situations.\n   * @returns {ResultSet} Returns a copy of the ResultSet (set) but the underlying document references will be the same.\n   */\n  public copy(): ResultSet<T> {\n    const result = new ResultSet<T>(this._collection);\n    result._filteredRows = this._filteredRows.slice();\n    result._filterInitialized = this._filterInitialized;\n    return result;\n  }\n\n  /**\n   * Executes a named collection transform or raw array of transform steps against the ResultSet.\n   * @param {(string|array)} transform - name of collection transform or raw transform array\n   * @param {object} [parameters=] - object property hash of parameters, if the transform requires them.\n   * @returns {ResultSet} either (this) ResultSet or a clone of of this ResultSet (depending on steps)\n   */\n  public transform(transform: string | Collection.Transform<T>[], parameters?: object): this {\n    // if transform is name, then do lookup first\n    if (typeof transform === \"string\") {\n      transform = this._collection._transforms[transform];\n    }\n\n    if (parameters !== undefined) {\n      transform = resolveTransformParams(transform, parameters);\n    }\n\n    let rs = this;\n    for (let idx = 0; idx < transform.length; idx++) {\n      const step = transform[idx];\n\n      switch (step.type) {\n        case \"find\":\n          rs.find(step.value as ResultSet.Query<Doc<T>>);\n          break;\n        case \"where\":\n          rs.where(step.value as (obj: Doc<T>) => boolean);\n          break;\n        case \"simplesort\":\n          rs.simplesort(step.property, step.options);\n          break;\n        case \"compoundsort\":\n          rs.compoundsort(step.value);\n          break;\n        case \"sort\":\n          rs.sort(step.value);\n          break;\n        case \"sortByScoring\":\n          rs.sortByScoring(step.desc);\n          break;\n        case \"limit\":\n          rs = rs.limit(step.value);\n          break; // limit makes copy so update reference\n        case \"offset\":\n          rs = rs.offset(step.value);\n          break; // offset makes copy so update reference\n        case \"map\":\n          rs = rs.map(step.value, step.dataOptions) as any as this;\n          break;\n        case \"eqJoin\":\n          rs = rs.eqJoin(step.joinData, step.leftJoinKey, step.rightJoinKey, step.mapFun, step.dataOptions) as this;\n          break;\n        // following cases break chain by returning array data so make any of these last in transform steps\n        case \"mapReduce\":\n          rs = rs.mapReduce(step.mapFunction, step.reduceFunction);\n          break;\n        // following cases update documents in current filtered ResultSet (use carefully)\n        case \"update\":\n          rs.update(step.value);\n          break;\n        case \"remove\":\n          rs.remove();\n          break;\n        default:\n          break;\n      }\n    }\n    return rs;\n  }\n\n  /**\n   * User supplied compare function is provided two documents to compare. (chainable)\n   * @example\n   *    rslt.sort(function(obj1, obj2) {\n\t *      if (obj1.name === obj2.name) return 0;\n\t *      if (obj1.name > obj2.name) return 1;\n\t *      if (obj1.name < obj2.name) return -1;\n\t *    });\n   * @param {function} comparefun - A javascript compare function used for sorting.\n   * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n   */\n  public sort(comparefun: (a: Doc<T>, b: Doc<T>) => number): this {\n    // if this has no filters applied, just we need to populate filteredRows first\n    if (!this._filterInitialized && this._filteredRows.length === 0) {\n      this._filteredRows = this._collection._prepareFullDocIndex();\n    }\n\n    const data = this._collection._data;\n    const wrappedComparer = (a: number, b: number) => comparefun(data[a], data[b]);\n\n    this._filteredRows.sort(wrappedComparer);\n\n    return this;\n  }\n\n  /**\n   * Simpler, loose evaluation for user to sort based on a property name. (chainable).\n   * Sorting based on the same lt/gt helper functions used for binary indices.\n   * @param {string} propname - name of property to sort by.\n   * @param {boolean|object=} options - boolean for sort descending or options object\n   * @param {boolean} [options.desc=false] - whether to sort descending\n   * @param {string} [options.sortComparator] override default with name of comparator registered in ComparatorMap\n   * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n   */\n  public simplesort(propname: keyof T, options: boolean | ResultSet.SimpleSortOptions = { desc: false }): this {\n    if (typeof options === \"boolean\") {\n      options = {\n        desc: options\n      };\n    }\n\n    if (!this._filterInitialized && this._collection._rangedIndexes.hasOwnProperty(propname)) {\n      let sortedIds: number[] = this._collection._rangedIndexes[propname].index.rangeRequest();\n      let dataPositions: number[] = [];\n\n      // until we refactor resultset to store $loki ids in filteredrows,\n      // we need to convert $loki ids to data array positions\n      for (let id of sortedIds) {\n        dataPositions.push(this._collection.get(id, true)[1]);\n      }\n\n      this._filteredRows = options.desc ? dataPositions.reverse() : dataPositions;\n      this._filterInitialized = true;\n      return this;\n    }\n\n    // if this has no filters applied, just we need to populate filteredRows first\n    if (!this._filterInitialized && this._filteredRows.length === 0) {\n      this._filteredRows = this._collection._prepareFullDocIndex();\n    }\n\n    const data = this._collection._data;\n\n    let comparator : ILokiComparer<any> =\n      (options.sortComparator) ?\n        ComparatorMap[options.sortComparator] :\n        ComparatorMap[this._collection._unindexedSortComparator];\n\n    const wrappedComparer = (a: number, b: number) => {\n      return comparator(data[a][propname], data[b][propname]);\n    };\n\n    this._filteredRows.sort(wrappedComparer);\n\n    if (options.desc) {\n      this._filteredRows.reverse();\n    }\n\n    return this;\n  }\n\n  /**\n   * Allows sorting a ResultSet based on multiple columns.\n   * @example\n   * // to sort by age and then name (both ascending)\n   * rs.compoundsort(['age', 'name']);\n   * // to sort by age (ascending) and then by name (descending)\n   * rs.compoundsort(['age', ['name', true]);\n   * @param {array} properties - array of property names or subarray of [propertyname, isdesc] used evaluate sort order\n   * @returns {ResultSet} Reference to this ResultSet, sorted, for future chain operations.\n   */\n  public compoundsort(properties: (keyof T | [keyof T, boolean])[]): this {\n    if (properties.length === 0) {\n      throw new Error(\"Invalid call to compoundsort, need at least one property\");\n    }\n\n    if (properties.length === 1) {\n      const prop = properties[0];\n      if (typeof prop === \"string\") {\n        return this.simplesort(prop, false);\n      } else {\n        return this.simplesort(prop[0] as keyof T, prop[1] as boolean | ResultSet.SimpleSortOptions);\n      }\n    }\n\n    // unify the structure of 'properties' to avoid checking it repeatedly while sorting\n    for (let i = 0, len = properties.length; i < len; i++) {\n      const prop = properties[i];\n      if (typeof prop === \"string\") {\n        properties[i] = [prop, false];\n      }\n    }\n\n    // if this has no filters applied, just we need to populate filteredRows first\n    if (!this._filterInitialized && this._filteredRows.length === 0) {\n      this._filteredRows = this._collection._prepareFullDocIndex();\n    }\n\n    const data = this._collection._data;\n    const wrappedComparer = (a: number, b: number) =>\n      this._compoundeval(properties as [keyof T, boolean][], data[a], data[b]);\n\n    this._filteredRows.sort(wrappedComparer);\n\n    return this;\n  }\n\n  /**\n   * Helper function for compoundsort(), performing individual object comparisons\n   * @param {Array} properties - array of property names, in order, by which to evaluate sort order\n   * @param {object} obj1 - first object to compare\n   * @param {object} obj2 - second object to compare\n   * @returns {number} 0, -1, or 1 to designate if identical (sortwise) or which should be first\n   */\n  private _compoundeval(properties: [keyof T, boolean][], obj1: T, obj2: T): number {\n    for (let i = 0, len = properties.length; i < len; i++) {\n      const prop = properties[i];\n      const field = prop[0];\n      const res = sortHelper(obj1[field], obj2[field], prop[1]);\n      if (res !== 0) {\n        return res;\n      }\n    }\n    return 0;\n  }\n\n  /**\n   * Sorts the ResultSet based on the last full-text-search scoring.\n   * @param {boolean} [ascending=false] - sort ascending\n   * @returns {ResultSet}\n   */\n  public sortByScoring(ascending = false): this {\n    if (this._scoring === null) {\n      throw new Error(\"No scoring available\");\n    }\n\n    if (ascending) {\n      this._filteredRows.sort((a: number, b: number) => this._scoring[a].score - this._scoring[b].score);\n    } else {\n      this._filteredRows.sort((a: number, b: number) => this._scoring[b].score - this._scoring[a].score);\n    }\n\n    return this;\n  }\n\n  /**\n   * Returns the scoring of the last full-text-search.\n   * @returns {ScoreResult[]}\n   */\n  public getScoring(): Scorer.ScoreResult[] {\n    if (this._scoring === null) {\n      throw new Error(\"No scoring available\");\n    }\n    const scoring: Scorer.ScoreResult[] = [];\n    for (let i = 0; i < this._filteredRows.length; i++) {\n      scoring.push(this._scoring[this._filteredRows[i]]);\n    }\n    return scoring;\n  }\n\n  /**\n   * Oversee the operation of OR'ed query expressions.\n   * OR'ed expression evaluation runs each expression individually against the full collection,\n   * and finally does a set OR on each expression's results.\n   * Each evaluation can utilize a binary index to prevent multiple linear array scans.\n   * @param {array} expressionArray - array of expressions\n   * @returns {ResultSet} this ResultSet for further chain ops.\n   */\n  public findOr(expressionArray: ResultSet.Query<Doc<T>>[]): this {\n    const docset = [];\n    const idxset = [];\n    const origCount = this.count();\n\n    // If filter is already initialized, then we query against only those items already in filter.\n    // This means no index utilization for fields, so hopefully its filtered to a smallish filteredRows.\n    for (let ei = 0, elen = expressionArray.length; ei < elen; ei++) {\n      // we need to branch existing query to run each filter separately and combine results\n      const fr = this.copy().find(expressionArray[ei])._filteredRows;\n      const frlen = fr.length;\n      // if the find operation did not reduce the initial set, then the initial set is the actual result\n      if (frlen === origCount) {\n        return this;\n      }\n\n      // add any document 'hits'\n      for (let fri = 0; fri < frlen; fri++) {\n        const idx = fr[fri];\n        if (idxset[idx] === undefined) {\n          idxset[idx] = true;\n          docset.push(idx);\n        }\n      }\n    }\n\n    this._filteredRows = docset;\n    this._filterInitialized = true;\n\n    return this;\n  }\n\n  public $or(expressionArray: ResultSet.Query<Doc<T>>[]): this {\n    return this.findOr(expressionArray);\n  }\n\n  /**\n   * Oversee the operation of AND'ed query expressions.\n   * AND'ed expression evaluation runs each expression progressively against the full collection,\n   * internally utilizing existing chained ResultSet functionality.\n   * Only the first filter can utilize a binary index.\n   * @param {array} expressionArray - array of expressions\n   * @returns {ResultSet} this ResultSet for further chain ops.\n   */\n  public findAnd(expressionArray: ResultSet.Query<Doc<T>>[]): this {\n    // we have already implementing method chaining in this (our ResultSet class)\n    // so lets just progressively apply user supplied and filters\n    for (let i = 0, len = expressionArray.length; i < len; i++) {\n      if (this.count() === 0) {\n        return this;\n      }\n      this.find(expressionArray[i]);\n    }\n    return this;\n  }\n\n  public $and(expressionArray: ResultSet.Query<Doc<T>>[]): this {\n    return this.findAnd(expressionArray);\n  }\n\n  /**\n   * Used for querying via a mongo-style query object.\n   *\n   * @param {object} query - A mongo-style query object used for filtering current results.\n   * @param {boolean} firstOnly - (Optional) Used by collection.findOne() - flag if this was invoked via findOne()\n   * @returns {ResultSet} this ResultSet for further chain ops.\n   */\n  public find(query?: ResultSet.Query<Doc<T>>, firstOnly = false): this {\n    if (this._collection._data.length === 0) {\n      this._filteredRows = [];\n      this._filterInitialized = true;\n      return this;\n    }\n\n    const queryObject = query || \"getAll\";\n    let property: any;\n    let queryObjectOp: any;\n    let value: any;\n\n    if (typeof queryObject === \"object\") {\n      let filters = [];\n      for (let p in queryObject) {\n        let obj = {};\n        obj[p as any] = queryObject[p];\n        filters.push(obj);\n\n        if (queryObject[p] !== undefined) {\n          property = p;\n          queryObjectOp = queryObject[p];\n        }\n      }\n      // if more than one expression in single query object,\n      // convert implicit $and to explicit $and\n      if (filters.length > 1) {\n        return this.find({ \"$and\": filters } as any, firstOnly);\n      }\n    }\n\n    // apply no filters if they want all\n    if (!property || queryObject === \"getAll\") {\n      if (firstOnly) {\n        this._filteredRows = (this._collection._data.length > 0) ? [0] : [];\n        this._filterInitialized = true;\n      }\n      return this;\n    }\n\n    // injecting $and and $or expression tree evaluation here.\n    if (property === \"$and\" || property === \"$or\") {\n      this[property](queryObjectOp);\n\n      // for chained find with firstOnly,\n      if (firstOnly && this._filteredRows.length > 1) {\n        this._filteredRows = this._filteredRows.slice(0, 1);\n      }\n\n      return this;\n    }\n\n    // see if query object is in shorthand mode (assuming eq operator)\n    let operator = \"\";\n    if (queryObjectOp === null || (typeof queryObjectOp !== \"object\" || queryObjectOp instanceof Date)) {\n      operator = \"$eq\";\n      value = queryObjectOp;\n    } else if (typeof queryObjectOp === \"object\") {\n      for (let key in queryObjectOp) {\n        if (queryObjectOp[key] !== undefined) {\n          operator = key;\n          value = queryObjectOp[key];\n          break;\n        }\n      }\n    } else {\n      throw new Error(\"Do not know what you want to do.\");\n    }\n\n    // for regex ops, precompile\n    if (operator === \"$regex\") {\n      if (Array.isArray(value)) {\n        value = new RegExp(value[0], value[1]);\n      } else if (!(value instanceof RegExp)) {\n        value = new RegExp(value as any);\n      }\n    }\n\n    // if an index exists for the property being queried against, use it\n    // for now only enabling where it is the first filter applied and prop is indexed\n    const doIndexCheck = !this._filterInitialized;\n\n    let searchByIndex = false;\n\n    if (doIndexCheck && this._collection._rangedIndexes[property] && indexedOps[operator]) {\n      searchByIndex = true;\n    }\n\n    // the comparison function\n    const operatorPackage = LokiOperatorPackageMap[this._collection._defaultLokiOperatorPackage];\n    // \"shortcut\" for collection data\n    const data = this._collection._data;\n\n    // Query executed differently depending on :\n    //    - whether the property being queried has an index defined\n    //    - if chained, we handle first pass differently for initial filteredRows[] population\n    //\n    // For performance reasons, each case has its own if block to minimize in-loop calculations\n\n    let result: number[] = [];\n    // If the filteredRows[] is already initialized, use it\n    if (this._filterInitialized) {\n      let filter = this._filteredRows;\n\n      if (property === \"$fts\") {\n        this._scoring = this._collection._fullTextSearch.search(queryObject.$fts as FullTextSearchQuery);\n        let keys = Object.keys(this._scoring);\n        for (let i = 0; i < keys.length; i++) {\n          if (filter.indexOf(+keys[i]) !== -1) {\n            result.push(+keys[i]);\n          }\n        }\n      } else if (this._collection._constraints.unique[property] !== undefined && operator === \"$eq\") {\n        // convert back to position for filtered rows (until we refactor filteredrows to store $loki instead of data pos)\n        const id = this._collection._constraints.unique[property].get(value);\n        if (id !== undefined) {\n          const row = this._collection.get(id, true)[1];\n          if (filter.indexOf(row) !== -1) {\n            result.push(row);\n          }\n        }\n      } else {\n        for (let i = 0; i < filter.length; i++) {\n          let rowIdx = filter[i];\n\n          // calling operator as method property of operator package preserves 'this'\n          if (operatorPackage[operator](data[rowIdx][property], value)) {\n            result.push(rowIdx);\n          }\n        }\n      }\n\n      this._filteredRows = result;\n      this._filterInitialized = true; // next time work against filteredRows[]\n      return this;\n    }\n\n    this._filteredRows = result;\n    this._filterInitialized = true; // next time work against filteredRows[]\n\n    if (property === \"$fts\") {\n      this._scoring = this._collection._fullTextSearch.search(queryObject.$fts as FullTextSearchQuery);\n      let keys = Object.keys(this._scoring);\n      for (let i = 0; i < keys.length; i++) {\n        result.push(+keys[i]);\n      }\n      return this;\n    }\n\n    // Use unique constraint for search.\n    if (this._collection._constraints.unique[property] !== undefined && operator === \"$eq\") {\n      // convert back to position for filtered rows (until we refactor filteredrows to store $loki instead of data pos)\n      const id = this._collection._constraints.unique[property].get(value);\n      if (id !== undefined) {\n        result.push(this._collection.get(id, true)[1]);\n      }\n      return this;\n    }\n\n    // if not searching by index\n    if (!searchByIndex) {\n      // determine comparator to use for ops\n      for (let i = 0; i < data.length; i++) {\n        // calling operator as method property of operator package preserves 'this'\n        if (operatorPackage[operator](data[i][property], value)) {\n          result.push(i);\n          if (firstOnly) {\n            return this;\n          }\n        }\n      }\n      return this;\n    }\n\n    // If we have a rangedIndex defined, use that and bail\n    if (this._collection._rangedIndexes[property]) {\n\n      if (operator === \"$in\") {\n        let ri: Collection.RangedIndexMeta = this._collection._rangedIndexes[property];\n\n        // iterate each $in array value\n        for (let val of value) {\n          // request matches where val eq current iterated val\n          let idResult = ri.index.rangeRequest({ op: \"$eq\", val: val });\n          // for each result in match\n          for (let id of idResult) {\n            // convert $loki id to data position and add to result (filteredrows)\n            result.push(this._collection.get(id, true)[1]);\n          }\n        }\n\n        return this;\n      }\n\n      if (operator === \"$between\") {\n        let idResult = this._collection._rangedIndexes[property].index.rangeRequest({\n          op: operator,\n          val: value[0],\n          high: value[1]\n        });\n\n        // for now we will have to 'shim' the binary tree index's $loki ids back\n        // into data array indices, ideally i would like to repurpose filteredrows to use loki ids\n        for (let id of idResult) {\n          result.push(this._collection.get(id, true)[1]);\n        }\n\n        return this;\n      }\n\n      let idResult = this._collection._rangedIndexes[property].index.rangeRequest({\n        op: operator,\n        val: value\n      });\n\n      // if our op requires 'second pass'\n      if (indexedOps[operator] !== true) {\n        for (let id of idResult) {\n          let pos = this._collection.get(id, true)[1];\n          if (indexedOps[operator](data[pos][property], value)) {\n            result.push(pos);\n          }\n        }\n      }\n      else {\n        // for now we will have to 'shim' the binary tree index's $loki ids back\n        // into data array indices, ideally i would like to repurpose filteredrows to use loki ids\n        for (let id of idResult) {\n          result.push(this._collection.get(id, true)[1]);\n        }\n      }\n    }\n\n    return this;\n  }\n\n\n  /**\n   * Used for filtering via a javascript filter function.\n   * @param {function} fun - A javascript function used for filtering current results by.\n   * @returns {ResultSet} this ResultSet for further chain ops.\n   */\n  public where(fun: (obj: Doc<T>) => boolean): this {\n    let viewFunction;\n    let result = [];\n\n    if (\"function\" === typeof fun) {\n      viewFunction = fun;\n    } else {\n      throw new TypeError(\"Argument is not a stored view or a function\");\n    }\n\n    // If the filteredRows[] is already initialized, use it\n    if (this._filterInitialized) {\n      let j = this._filteredRows.length;\n\n      while (j--) {\n        if (viewFunction(this._collection._data[this._filteredRows[j]]) === true) {\n          result.push(this._filteredRows[j]);\n        }\n      }\n\n      this._filteredRows = result;\n\n      return this;\n    }\n    // otherwise this is initial chained op, work against data, push into filteredRows[]\n    else {\n      let k = this._collection._data.length;\n\n      while (k--) {\n        if (viewFunction(this._collection._data[k]) === true) {\n          result.push(k);\n        }\n      }\n\n      this._filteredRows = result;\n      this._filterInitialized = true;\n\n      return this;\n    }\n  }\n\n  /**\n   * Returns the number of documents in the ResultSet.\n   * @returns {number} The number of documents in the ResultSet.\n   */\n  public count(): number {\n    if (this._filterInitialized) {\n      return this._filteredRows.length;\n    }\n    return this._collection.count();\n  }\n\n  /**\n   * Terminates the chain and returns array of filtered documents\n   * @param {object} options\n   * @param {boolean} [options.forceClones] - Allows forcing the return of cloned objects even when\n   *        the collection is not configured for clone object.\n   * @param {string} [options.forceCloneMethod] - Allows overriding the default or collection specified cloning method.\n   *        Possible values 'parse-stringify', 'deep', and 'shallow' and\n   * @param {boolean} [options.removeMeta] - will force clones and strip $loki and meta properties from documents\n   *\n   * @returns {Array} Array of documents in the ResultSet\n   */\n  public data(options: ResultSet.DataOptions = {}): Doc<T>[] {\n    let forceClones: boolean;\n    let forceCloneMethod: CloneMethod;\n    let removeMeta: boolean;\n    (\n      {\n        forceClones = false,\n        forceCloneMethod = this._collection._cloneMethod,\n        removeMeta = false\n      } = options\n    );\n\n    let result = [];\n    let data = this._collection._data;\n    let obj;\n    let method: CloneMethod;\n\n    // if user opts to strip meta, then force clones and use 'shallow' if 'force' options are not present\n    if (removeMeta && !forceClones) {\n      forceClones = true;\n      forceCloneMethod = \"shallow\";\n    }\n\n    // if collection has delta changes active, then force clones and use CloneMethod.DEEP for effective change tracking of nested objects\n    if (!this._collection._disableDeltaChangesApi) {\n      forceClones = true;\n      forceCloneMethod = \"deep\";\n    }\n\n    // if this has no filters applied, just return collection.data\n    if (!this._filterInitialized) {\n      if (this._filteredRows.length === 0) {\n        // determine whether we need to clone objects or not\n        if (this._collection._cloneObjects || forceClones) {\n          method = forceCloneMethod;\n\n          for (let i = 0; i < data.length; i++) {\n            obj = this._collection._defineNestedProperties(clone(data[i], method));\n            if (removeMeta) {\n              delete obj.$loki;\n              delete obj.meta;\n            }\n            result.push(obj);\n          }\n          return result;\n        }\n        // otherwise we are not cloning so return sliced array with same object references\n        else {\n          return data.slice();\n        }\n      } else {\n        // filteredRows must have been set manually, so use it\n        this._filterInitialized = true;\n      }\n    }\n\n    const fr = this._filteredRows;\n    if (this._collection._cloneObjects || forceClones) {\n      method = forceCloneMethod;\n      for (let i = 0; i < fr.length; i++) {\n        obj = this._collection._defineNestedProperties(clone(data[fr[i]], method));\n        if (removeMeta) {\n          delete obj.$loki;\n          delete obj.meta;\n        }\n        result.push(obj);\n      }\n    } else {\n      for (let i = 0; i < fr.length; i++) {\n        result.push(data[fr[i]]);\n      }\n    }\n    return result;\n  }\n\n  /**\n   * Used to run an update operation on all documents currently in the ResultSet.\n   * @param {function} updateFunction - User supplied updateFunction(obj) will be executed for each document object.\n   * @returns {ResultSet} this ResultSet for further chain ops.\n   */\n  public update(updateFunction: (obj: Doc<T>) => Doc<T>): this {\n    // if this has no filters applied, we need to populate filteredRows first\n    if (!this._filterInitialized && this._filteredRows.length === 0) {\n      this._filteredRows = this._collection._prepareFullDocIndex();\n    }\n\n    const len = this._filteredRows.length;\n    const rcd = this._collection._data;\n\n    // pass in each document object currently in ResultSet to user supplied updateFunction\n    for (let idx = 0; idx < len; idx++) {\n      // if we have cloning option specified or are doing differential delta changes, clone object first\n      if (this._collection._cloneObjects || !this._collection._disableDeltaChangesApi) {\n        const obj = clone(rcd[this._filteredRows[idx]], this._collection._cloneMethod);\n        updateFunction(obj);\n        this._collection.update(obj);\n      }\n      else {\n        // no need to clone, so just perform update on collection data object instance\n        updateFunction(rcd[this._filteredRows[idx]]);\n        this._collection.update(rcd[this._filteredRows[idx]]);\n      }\n    }\n\n    return this;\n  }\n\n  /**\n   * Removes all document objects which are currently in ResultSet from collection (as well as ResultSet)\n   * @returns {ResultSet} this (empty) ResultSet for further chain ops.\n   */\n  public remove(): this {\n    // if this has no filters applied, we need to populate filteredRows first\n    if (!this._filterInitialized && this._filteredRows.length === 0) {\n      this._filteredRows = this._collection._prepareFullDocIndex();\n    }\n    this._collection.remove(this.data());\n    this._filteredRows = [];\n    return this;\n  }\n\n  /**\n   * data transformation via user supplied functions\n   *\n   * @param {function} mapFunction - this function accepts a single document for you to transform and return\n   * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value\n   * @returns {value} The output of your reduceFunction\n   */\n  public mapReduce<U1, U2>(mapFunction: (item: Doc<T>, index: number, array: Doc<T>[]) => U1,\n    reduceFunction: (array: U1[]) => U2): U2 {\n    try {\n      return reduceFunction(this.data().map(mapFunction));\n    } catch (err) {\n      throw err;\n    }\n  }\n\n  /**\n   * Left joining two sets of data. Join keys can be defined or calculated properties\n   * eqJoin expects the right join key values to be unique.  Otherwise left data will be joined on the last joinData object with that key\n   * @param {Array|ResultSet|Collection} joinData - Data array to join to.\n   * @param {(string|function)} leftJoinKey - Property name in this result set to join on or a function to produce a value to join on\n   * @param {(string|function)} rightJoinKey - Property name in the joinData to join on or a function to produce a value to join on\n   * @param {function} [mapFun=] - a function that receives each matching pair and maps them into output objects - function(left,right){return joinedObject}\n   * @param {object} [dataOptions=] - optional options to apply to data() calls for left and right sides\n   * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n   * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n   * @param {string} dataOptions.forceCloneMethod - allows overriding the default or collection specified cloning method\n   * @returns {ResultSet} A ResultSet with data in the format [{left: leftObj, right: rightObj}]\n   */\n  public eqJoin(joinData: Collection<any> | ResultSet<any> | any[], leftJoinKey: string | ((obj: any) => string),\n    rightJoinKey: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any,\n    dataOptions?: ResultSet.DataOptions): ResultSet<any> {\n    let rightData = [];\n    let rightDataLength;\n    let key;\n    let result = [];\n    let leftKeyisFunction = typeof leftJoinKey === \"function\";\n    let rightKeyisFunction = typeof rightJoinKey === \"function\";\n    let joinMap = {};\n\n    //get the left data\n    let leftData = this.data(dataOptions);\n    let leftDataLength = leftData.length;\n\n    //get the right data\n    if (joinData instanceof Collection) {\n      rightData = joinData.chain().data(dataOptions);\n    } else if (joinData instanceof ResultSet) {\n      rightData = joinData.data(dataOptions);\n    } else if (Array.isArray(joinData)) {\n      rightData = joinData;\n    } else {\n      throw new TypeError(\"joinData needs to be an array or result set\");\n    }\n    rightDataLength = rightData.length;\n\n    //construct a lookup table\n    for (let i = 0; i < rightDataLength; i++) {\n      key = rightKeyisFunction\n        ? (rightJoinKey as (obj: any) => string)(rightData[i])\n        : rightData[i][rightJoinKey as string];\n      joinMap[key] = rightData[i];\n    }\n\n    if (!mapFun) {\n      mapFun = (left: any, right: any) => ({\n        left,\n        right\n      });\n    }\n\n    //Run map function over each object in the ResultSet\n    for (let j = 0; j < leftDataLength; j++) {\n      key = leftKeyisFunction\n        ? (leftJoinKey as (obj: any) => string)(leftData[j])\n        : leftData[j][leftJoinKey as string];\n      result.push(mapFun(leftData[j], joinMap[key] || {}));\n    }\n\n    //return a new ResultSet with no filters\n    this._collection = new Collection(\"joinData\");\n    this._collection.insert(result);\n    this._filteredRows = [];\n    this._filterInitialized = false;\n\n    return this;\n  }\n\n  /**\n   * Applies a map function into a new collection for further chaining.\n   * @param {function} mapFun - javascript map function\n   * @param {object} [dataOptions=] - options to data() before input to your map function\n   * @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun\n   * @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object\n   * @param {string} dataOptions.forceCloneMethod - Allows overriding the default or collection specified cloning method\n   * @return {ResultSet}\n   */\n  public map<U extends object>(mapFun: (obj: Doc<T>, index: number, array: Doc<T>[]) => U,\n    dataOptions?: ResultSet.DataOptions): ResultSet<U> {\n    const data = this.data(dataOptions).map(mapFun);\n    //return return a new ResultSet with no filters\n    this._collection = new Collection(\"mappedData\");\n    this._collection.insert(data as any as T);\n    this._filteredRows = [];\n    this._filterInitialized = false;\n    return this as any as ResultSet<U>;\n  }\n}\n\nexport namespace ResultSet {\n  export interface DataOptions {\n    forceClones?: boolean;\n    forceCloneMethod?: CloneMethod;\n    removeMeta?: boolean;\n  }\n\n  export interface SimpleSortOptions {\n    desc?: boolean;\n    sortComparator?: string;\n  }\n\n  export type ContainsHelperType<R> =\n    R extends string ? string | string[] :\n    R extends any[] ? R[number] | R[number][] :\n    R extends object ? keyof R | (keyof R)[] : never;\n\n  export type LokiOps<R> = {\n    $eq?: R;\n  } | {\n    $ne?: R;\n  } | {\n    $gt?: R;\n  } | {\n    $gte?: R;\n  } | {\n    $lt?: R;\n  } | {\n    $lte?: R;\n  } | {\n    $between?: [R, R];\n  } | {\n    $in?: R[];\n  } | {\n    $nin?: R[];\n  } | {\n    $keyin?: object;\n  } | {\n    $nkeyin?: object;\n  } | {\n    $definedin?: object;\n  } | {\n    $undefinedin?: object;\n  } | {\n    $regex?: RegExp | string | [string, string] // string and [string, string] are better for serialization\n  } | {\n    $containsNone?: ContainsHelperType<R>;\n  } | {\n    $containsAny?: ContainsHelperType<R>;\n  } | {\n    $contains?: ContainsHelperType<R>;\n  } | {\n    $type?: string;\n  } | {\n    $finite?: boolean;\n  } | {\n    $size?: number;\n  } | {\n    $len?: number;\n  } | {\n    $where?: (val?: R) => boolean;\n  };\n\n  export type Query<T> =\n    { [P in keyof T]?: LokiOps<T[P]> | T[P] }\n    & { $and?: Query<T>[] }\n    & { $or?: Query<T>[] }\n    & { $fts?: FullTextSearchQuery };\n}\n"
  },
  {
    "path": "packages/loki/src/unique_index.ts",
    "content": "import { Dict } from \"../../common/types\";\n\nexport class UniqueIndex {\n  // The property field to index.\n  private _field: string;\n  // maps value to loki\n  private _lokiMap: Dict<number>;\n  // maps loki to value - turns this into birectional map enforcing 1-1\n  // while this is optional and doubles memory overhead, it will improve maintenance costs\n  private _valMap: Dict<any>;\n\n  /**\n   * Constructs an unique index object.\n   * @param {string} propertyField - the property field to index\n   */\n  constructor(propertyField: string) {\n    this._field = propertyField;\n    this._lokiMap = {};\n    this._valMap = {};\n  }\n\n  /**\n   * Sets a document's unique index.\n   * @param {number} id loki id to associate with value\n   * @param {*} value  value to associate with id\n   */\n  public set(id: number, value: any): void {\n    // unique index should not include null/undefined values\n    if (value !== null && value !== undefined) {\n      if (value in this._lokiMap) {\n        throw new Error(\"Duplicate key for property \" + this._field + \": \" + value);\n      }\n\n      if (id in this._valMap) {\n        throw new Error(\"Duplicate key for property $loki : \" + id);\n      }\n\n      this._lokiMap[value] = id;\n      this._valMap[id] = value;\n    }\n  }\n\n  /**\n   * Returns the $loki id of an unique value.\n   * @param {*} value the value to retrieve a loki id match for\n   */\n  public get(value: any): number {\n    return this._lokiMap[value];\n  }\n\n  /**\n   * Updates a document's unique index.\n   * @param {number} id (loki) id of document to update the value to\n   * @param {*} value value to associate with loki id\n   */\n  public update(id: number, value: any): void {\n    // if the value has not changed, do nothing\n    if (value === this._valMap[id]) {\n      return;\n    }\n\n    // the value must have changed, so check if new value already exists\n    if (value in this._lokiMap) {\n      throw new Error(\"Duplicate key for property \" + this._field + \": \" + value);\n    }\n    this.remove(id);\n    this.set(id, value);\n  }\n\n  /**\n   * Removes an unique index.\n   * @param {number} id (loki) id to remove from index\n   */\n  public remove(id: number): void {\n    if (!(id in this._valMap)) {\n      throw new Error(\"Key is not in unique index: \" + this._field);\n    }\n\n    let oldValue = this._valMap[id];\n\n    delete this._lokiMap[oldValue];\n    delete this._valMap[id];\n  }\n\n  /**\n   * Clears the unique index.\n   */\n  public clear(): void {\n    this._lokiMap = {};\n    this._valMap = {};\n  }\n}\n"
  },
  {
    "path": "packages/loki/webpack.config.js",
    "content": "/* global __dirname, module, require */\nconst path = require(\"path\");\nconst webpackConigCreator = require('../../config/webpack-config-creator.js');\n\nmodule.exports = webpackConigCreator({\n  entry: path.join(__dirname, \"src\", \"index.ts\"),\n  filename: \"lokidb.loki.js\",\n  library: \"@lokidb/loki\",\n});\n"
  },
  {
    "path": "packages/memory-storage/package.json",
    "content": "{\n  \"name\": \"@lokidb/memory-storage\",\n  \"description\": \"A persistence adapter which persists to memory.\",\n  \"author\": \"Various authors\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/LokiJS-Forge/LokiDB.git\"\n  },\n  \"main\": \"lokidb.memory-storage.js\",\n  \"types\": \"./types/memory-storage/src/index.d.ts\",\n  \"dependencies\": {\n    \"@lokidb/loki\": \"0\"\n  }\n}\n"
  },
  {
    "path": "packages/memory-storage/spec/generic/memory_storage.spec.ts",
    "content": "/* global describe, it, expect */\nimport { Loki } from \"../../../loki/src/loki\";\nimport { MemoryStorage } from \"../../src/memory_storage\";\n\ndescribe(\"testing memory storage\", function () {\n\n  interface Name {\n    name: string;\n  }\n\n  beforeAll(() => {\n    MemoryStorage.register();\n  });\n\n  afterAll(() => {\n    MemoryStorage.deregister();\n  });\n\n  it(\"LokiMemoryStorage\", function (done) {\n    const db = new Loki(\"myTestApp\");\n    const adapter = {adapter: new MemoryStorage()};\n    db.initializePersistence(adapter)\n      .then(() => {\n        db.addCollection<Name>(\"myColl\").insert({name: \"Hello World\"});\n        return db.saveDatabase();\n      })\n      .then(() => {\n        const db2 = new Loki(\"myTestApp\");\n        return db2.initializePersistence(adapter)\n          .then(() => {\n            return db2.loadDatabase();\n          }).then(() => {\n            expect(db2.getCollection<Name>(\"myColl\").find()[0].name).toEqual(\"Hello World\");\n          });\n      })\n      .then(() => {\n        const db2 = new Loki(\"myTestApp\");\n        return db2.initializePersistence(adapter)\n          .then(() => {\n            return db2.loadDatabase();\n          }).then(() => {\n            expect(db2.getCollection<Name>(\"myColl\").find()[0].name).toEqual(\"Hello World\");\n          });\n      })\n      .then(() => {\n        const db3 = new Loki(\"other\");\n        return db3.initializePersistence(adapter)\n          .then(() => {\n            return db3.loadDatabase();\n          }).then(() => {\n            expect(false).toEqual(true);\n          }, () => {\n            expect(true).toEqual(true);\n          });\n      })\n      .then(() => {\n        return db.deleteDatabase();\n      })\n      .then(() => {\n        return db.loadDatabase()\n          .then(() => {\n            expect(db.getCollection<Name>(\"myColl\").find()[0].name).toEqual(\"Hello World\");\n            expect(false).toEqual(true);\n            done();\n          }, () => {\n            expect(true).toEqual(true);\n            done();\n          });\n      });\n  });\n});\n"
  },
  {
    "path": "packages/memory-storage/src/index.ts",
    "content": "import { MemoryStorage } from \"./memory_storage\";\n\nexport {MemoryStorage};\nexport default MemoryStorage;\n"
  },
  {
    "path": "packages/memory-storage/src/memory_storage.ts",
    "content": "import { PLUGINS } from \"../../common/plugin\";\nimport { Dict, StorageAdapter } from \"../../common/types\";\n\n/**\n * An in-memory persistence adapter for an in-memory database.\n * This simple 'key/value' adapter is intended for unit testing and diagnostics.\n */\nexport class MemoryStorage implements StorageAdapter {\n\n  public hashStore: Dict<{\n    savecount: number;\n    lastsave: Date;\n    value: string;\n  }>;\n  public options: MemoryStorage.Options;\n\n  /**\n   * Registers the local storage as plugin.\n   */\n  static register(): void {\n    PLUGINS[\"MemoryStorage\"] = MemoryStorage;\n  }\n\n  /**\n   * Deregisters the local storage as plugin.\n   */\n  static deregister(): void {\n    delete PLUGINS[\"MemoryStorage\"];\n  }\n\n  /**\n   * @param {object} options - memory storage options\n   * @param {boolean} [options.asyncResponses=false] - whether callbacks are invoked asynchronously (default: false)\n   * @param {int} [options.asyncTimeout=50] - timeout in ms to queue callbacks (default: 50)\n   */\n  constructor(options?: MemoryStorage.Options) {\n    this.hashStore = {};\n    this.options = options || {};\n\n    if (this.options.asyncResponses === undefined) {\n      this.options.asyncResponses = false;\n    }\n\n    if (this.options.asyncTimeout === undefined) {\n      this.options.asyncTimeout = 50; // 50 ms default\n    }\n  }\n\n  /**\n   * Loads a serialized database from its in-memory store.\n   * (Loki persistence adapter interface function)\n   *\n   * @param {string} dbname - name of the database (filename/keyname)\n   * @returns {Promise} a Promise that resolves after the database was loaded\n   */\n  public loadDatabase(dbname: string): Promise<string> {\n    if (this.options.asyncResponses) {\n      return new Promise((resolve, reject) => {\n        setTimeout(() => {\n          if (this.hashStore[dbname] !== undefined) {\n            resolve(this.hashStore[dbname].value);\n          }\n          else {\n            reject(null);\n          }\n        }, this.options.asyncTimeout);\n      });\n    }\n    else {\n      if (this.hashStore[dbname] !== undefined) {\n        return Promise.resolve(this.hashStore[dbname].value);\n      }\n      else {\n        return Promise.reject(null);\n      }\n    }\n  }\n\n  /**\n   * Saves a serialized database to its in-memory store.\n   * (Loki persistence adapter interface function)\n   *\n   * @param {string} dbname - name of the database (filename/keyname)\n   * @param {string} dbstring - the database content\n   * @returns {Promise} a Promise that resolves after the database was persisted\n   */\n  public saveDatabase(dbname: string, dbstring: string): Promise<void> {\n    if (this.options.asyncResponses) {\n      return new Promise((resolve) => {\n        setTimeout(() => {\n          const saveCount = (this.hashStore[dbname] !== undefined ? this.hashStore[dbname].savecount : 0);\n\n          this.hashStore[dbname] = {\n            savecount: saveCount + 1,\n            lastsave: new Date(),\n            value: dbstring\n          };\n\n          resolve();\n        }, this.options.asyncTimeout);\n        return Promise.resolve();\n      });\n    } else {\n      const saveCount = (this.hashStore[dbname] !== undefined ? this.hashStore[dbname].savecount : 0);\n\n      this.hashStore[dbname] = {\n        savecount: saveCount + 1,\n        lastsave: new Date(),\n        value: dbstring\n      };\n\n      return Promise.resolve();\n    }\n  }\n\n  /**\n   * Deletes a database from its in-memory store.\n   *\n   * @param {string} dbname - name of the database (filename/keyname)\n   * @returns {Promise} a Promise that resolves after the database was deleted\n   */\n  public deleteDatabase(dbname: string): Promise<void> {\n    delete this.hashStore[dbname];\n    return Promise.resolve();\n  }\n}\n\nexport namespace MemoryStorage {\n  export interface Options {\n    asyncResponses?: boolean;\n    asyncTimeout?: number;\n  }\n}\n"
  },
  {
    "path": "packages/memory-storage/webpack.config.js",
    "content": "/* global __dirname, module, require */\nconst path = require(\"path\");\nconst webpackConigCreator = require('../../config/webpack-config-creator.js');\n\nmodule.exports = webpackConigCreator({\n  entry: path.join(__dirname, \"src\", \"index.ts\"),\n  filename: \"lokidb.memory-storage.js\",\n  library: \"@lokidb/memory-storage\",\n  externals: {\n    \"../../loki/src/loki\": \"@lokidb/loki\"\n  },\n});\n"
  },
  {
    "path": "packages/partitioning-adapter/package.json",
    "content": "{\n  \"name\": \"@lokidb/partitioning-adapter\",\n  \"description\": \"An adapter for adapters. Converts a non reference mode adapter into a reference mode adapter which can perform destructuring and partitioning.\",\n  \"author\": \"Various authors\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/LokiJS-Forge/LokiDB.git\"\n  },\n  \"main\": \"lokidb.partitioning-adapter.js\",\n  \"types\": \"./types/partitioning-adapter/src/index.d.ts\",\n  \"dependencies\": {\n    \"@lokidb/loki\": \"0\"\n  }\n}\n"
  },
  {
    "path": "packages/partitioning-adapter/spec/generic/partitioning.spec.ts",
    "content": "/* global describe, it, expect */\nimport { Loki } from \"../../../loki/src/loki\";\nimport { MemoryStorage } from \"../../../memory-storage/src/memory_storage\";\nimport { PartitioningAdapter } from \"../../src/partitioning_adapter\";\n\n\ninterface AB {\n  a: number;\n  b: number;\n}\n\n\ninterface User {\n  name: string;\n  owner: string;\n  maker: string;\n}\n\ndescribe(\"partitioning adapter\", () => {\n  let db2: Loki;\n\n  it(\"verify partioning adapter works\", (done) => {\n    const mem = new MemoryStorage();\n    const adapter = new PartitioningAdapter(mem);\n\n    const db = new Loki(\"sandbox.db\");\n\n    db.initializePersistence({adapter: adapter});\n\n    // Add a collection to the database\n    const items = db.addCollection<User>(\"items\");\n    items.insert({name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\"});\n    items.insert({name: \"gungnir\", owner: \"odin\", maker: \"elves\"});\n    items.insert({name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\"});\n    items.insert({name: \"draupnir\", owner: \"odin\", maker: \"elves\"});\n\n    const another = db.addCollection<AB>(\"another\");\n    const ai = another.insert({a: 1, b: 2});\n\n    db.saveDatabase().then(() => {\n      // should have partitioned the data\n      expect(Object.keys(mem.hashStore).length).toEqual(3);\n      expect(mem.hashStore.hasOwnProperty(\"sandbox.db\")).toEqual(true);\n      expect(mem.hashStore.hasOwnProperty(\"sandbox.db.0\")).toEqual(true);\n      expect(mem.hashStore.hasOwnProperty(\"sandbox.db.1\")).toEqual(true);\n      // all partitions should have been saved once each\n      expect(mem.hashStore[\"sandbox.db\"].savecount).toEqual(1);\n      expect(mem.hashStore[\"sandbox.db.0\"].savecount).toEqual(1);\n      expect(mem.hashStore[\"sandbox.db.1\"].savecount).toEqual(1);\n\n      // so let's go ahead and update one of our collections to make it dirty\n      ai.b = 3;\n      another.update(ai);\n\n      // and save again to ensure lastsave is different on for db container and that one collection\n      return db.saveDatabase();\n    }).then(() => {\n      // db container always gets saved since we currently have no 'dirty' flag on it to check\n      expect(mem.hashStore[\"sandbox.db\"].savecount).toEqual(2);\n      // we didn't change this\n      expect(mem.hashStore[\"sandbox.db.0\"].savecount).toEqual(1);\n      // we updated this collection so it should have been saved again\n      expect(mem.hashStore[\"sandbox.db.1\"].savecount).toEqual(2);\n\n      // ok now lets load from it\n      db2 = new Loki(\"sandbox.db\");\n\n      db2.initializePersistence({adapter: adapter});\n\n      return db2.loadDatabase();\n    }).then(() => {\n      expect(db2[\"_collections\"].length).toEqual(2);\n      expect(db2[\"_collections\"][0].count()).toEqual(4);\n      expect(db2[\"_collections\"][1].count()).toEqual(1);\n      expect(db2.getCollection<User>(\"items\").findOne({name: \"gungnir\"}).owner).toEqual(\"odin\");\n      expect(db2.getCollection<AB>(\"another\").findOne({a: 1}).b).toEqual(3);\n    }).then(done, done.fail);\n  });\n\n  it(\"verify partioning adapter with paging mode enabled works\", (done) => {\n    const mem = new MemoryStorage();\n\n    // we will use an exceptionally low page size (64bytes) to test with small dataset\n    // every object will serialize to over 64bytes so that is not a hard limit but when\n    // we exceed that we will stop adding to page (so for this test 1 doc per page)\n    const adapter = new PartitioningAdapter(mem, {paging: true, pageSize: 64});\n\n    const db = new Loki(\"sandbox.db\");\n\n    db.initializePersistence({adapter: adapter});\n\n    // Add a collection to the database\n    const items = db.addCollection<User>(\"items\");\n    items.insert({name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\"});\n    items.insert({name: \"gungnir\", owner: \"odin\", maker: \"elves\"});\n    const tyr = items.insert({name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\"});\n    items.insert({name: \"draupnir\", owner: \"odin\", maker: \"elves\"});\n\n    const another = db.addCollection<AB>(\"another\");\n    const ai = another.insert({a: 1, b: 2});\n\n    // for purposes of our memory storage it is pretty much synchronous\n    db.saveDatabase().then(() => {\n      // should have partitioned the data\n      expect(Object.keys(mem.hashStore).length).toEqual(6);\n      expect(mem.hashStore.hasOwnProperty(\"sandbox.db\")).toEqual(true);\n      expect(mem.hashStore.hasOwnProperty(\"sandbox.db.0.0\")).toEqual(true);\n      expect(mem.hashStore.hasOwnProperty(\"sandbox.db.0.1\")).toEqual(true);\n      expect(mem.hashStore.hasOwnProperty(\"sandbox.db.0.2\")).toEqual(true);\n      expect(mem.hashStore.hasOwnProperty(\"sandbox.db.0.3\")).toEqual(true);\n      expect(mem.hashStore.hasOwnProperty(\"sandbox.db.1.0\")).toEqual(true);\n      // all partitions should have been saved once each\n      expect(mem.hashStore[\"sandbox.db\"].savecount).toEqual(1);\n      expect(mem.hashStore[\"sandbox.db.0.0\"].savecount).toEqual(1);\n      expect(mem.hashStore[\"sandbox.db.0.1\"].savecount).toEqual(1);\n      expect(mem.hashStore[\"sandbox.db.0.2\"].savecount).toEqual(1);\n      expect(mem.hashStore[\"sandbox.db.0.3\"].savecount).toEqual(1);\n      expect(mem.hashStore[\"sandbox.db.1.0\"].savecount).toEqual(1);\n\n      // so let's go ahead and update one of our collections to make it dirty\n      ai.b = 3;\n      another.update(ai);\n\n      // and save again to ensure lastsave is different on for db container and that one collection\n      return db.saveDatabase();\n    }).then(() => {\n      // db container always gets saved since we currently have no 'dirty' flag on it to check\n      expect(mem.hashStore[\"sandbox.db\"].savecount).toEqual(2);\n      // we didn't change this\n      expect(mem.hashStore[\"sandbox.db.0.0\"].savecount).toEqual(1);\n      expect(mem.hashStore[\"sandbox.db.0.2\"].savecount).toEqual(1);\n      expect(mem.hashStore[\"sandbox.db.0.3\"].savecount).toEqual(1);\n      // we updated this collection so it should have been saved again\n      expect(mem.hashStore[\"sandbox.db.1.0\"].savecount).toEqual(2);\n\n      // now update a multi page items collection and verify both pages were saved\n      tyr.maker = \"elves\";\n      items.update(tyr);\n\n      return db.saveDatabase();\n    }).then(() => {\n      expect(mem.hashStore[\"sandbox.db\"].savecount).toEqual(3);\n      expect(mem.hashStore[\"sandbox.db.0.0\"].savecount).toEqual(2);\n      expect(mem.hashStore[\"sandbox.db.0.1\"].savecount).toEqual(2);\n      expect(mem.hashStore[\"sandbox.db.0.2\"].savecount).toEqual(2);\n      expect(mem.hashStore[\"sandbox.db.0.3\"].savecount).toEqual(2);\n      expect(mem.hashStore[\"sandbox.db.1.0\"].savecount).toEqual(2);\n\n      // ok now lets load from it\n      db2 = new Loki(\"sandbox.db\");\n      db2.initializePersistence({adapter: adapter});\n      return db2.loadDatabase();\n    }).then(() => {\n      expect(db2[\"_collections\"].length).toEqual(2);\n      expect(db2[\"_collections\"][0].count()).toEqual(4);\n      expect(db2[\"_collections\"][1].count()).toEqual(1);\n      expect(db2.getCollection<User>(\"items\").findOne({name: \"tyrfing\"}).maker).toEqual(\"elves\");\n      expect(db2.getCollection<AB>(\"another\").findOne({a: 1}).b).toEqual(3);\n\n      // verify empty collection saves with paging\n      db.addCollection(\"extracoll\");\n      return db.saveDatabase();\n    }).then(() => {\n      expect(mem.hashStore[\"sandbox.db\"].savecount).toEqual(4);\n      expect(mem.hashStore[\"sandbox.db.0.0\"].savecount).toEqual(2);\n      expect(mem.hashStore[\"sandbox.db.0.1\"].savecount).toEqual(2);\n      expect(mem.hashStore[\"sandbox.db.0.2\"].savecount).toEqual(2);\n      expect(mem.hashStore[\"sandbox.db.0.3\"].savecount).toEqual(2);\n      expect(mem.hashStore[\"sandbox.db.1.0\"].savecount).toEqual(2);\n      expect(mem.hashStore[\"sandbox.db.2.0\"].savecount).toEqual(1);\n\n      // now verify loading empty collection works with paging codepath\n      db2 = new Loki(\"sandbox.db\");\n      db2.initializePersistence({adapter: adapter});\n      return db2.loadDatabase();\n    }).then(() => {\n      expect(db2[\"_collections\"].length).toEqual(3);\n      expect(db2[\"_collections\"][0].count()).toEqual(4);\n      expect(db2[\"_collections\"][1].count()).toEqual(1);\n      expect(db2[\"_collections\"][2].count()).toEqual(0);\n    }).then(done, done.fail);\n  });\n\n  it(\"verify throttled async works as expected\", (done) => {\n    const mem = new MemoryStorage({asyncResponses: true, asyncTimeout: 50});\n    const adapter = new PartitioningAdapter(mem);\n    const throttled = true;\n    const db = new Loki(\"sandbox.db\");\n    db.initializePersistence({adapter: adapter, throttledSaves: throttled});\n\n    // Add a collection to the database\n    const items = db.addCollection<User>(\"items\");\n    items.insert({name: \"mjolnir\", owner: \"thor\", maker: \"dwarves\"});\n    items.insert({name: \"gungnir\", owner: \"odin\", maker: \"elves\"});\n    const tyr = items.insert({name: \"tyrfing\", owner: \"Svafrlami\", maker: \"dwarves\"});\n    items.insert({name: \"draupnir\", owner: \"odin\", maker: \"elves\"});\n\n    const another = db.addCollection<AB>(\"another\");\n    const ai = another.insert({a: 1, b: 2});\n\n    db.saveDatabase().then(() => {\n      // should have partitioned the data\n      expect(Object.keys(mem.hashStore).length).toEqual(3);\n      expect(mem.hashStore.hasOwnProperty(\"sandbox.db\")).toEqual(true);\n      expect(mem.hashStore.hasOwnProperty(\"sandbox.db.0\")).toEqual(true);\n      expect(mem.hashStore.hasOwnProperty(\"sandbox.db.1\")).toEqual(true);\n      // all partitions should have been saved once each\n      expect(mem.hashStore[\"sandbox.db\"].savecount).toEqual(1);\n      expect(mem.hashStore[\"sandbox.db.0\"].savecount).toEqual(1);\n      expect(mem.hashStore[\"sandbox.db.1\"].savecount).toEqual(1);\n\n      // so let's go ahead and update one of our collections to make it dirty\n      ai.b = 3;\n      another.update(ai);\n\n      // and save again to ensure lastsave is different on for db container and that one collection\n      db.saveDatabase().then(() => {\n        // db container always gets saved since we currently have no 'dirty' flag on it to check\n        expect(mem.hashStore[\"sandbox.db\"].savecount).toEqual(2);\n        // we didn't change this\n        expect(mem.hashStore[\"sandbox.db.0\"].savecount).toEqual(1);\n        // we updated this collection so it should have been saved again\n        expect(mem.hashStore[\"sandbox.db.1\"].savecount).toEqual(2);\n\n        // now update a multi page items collection and verify both pages were saved\n        tyr.maker = \"elves\";\n        items.update(tyr);\n        db.saveDatabase().then(() => {\n          expect(mem.hashStore[\"sandbox.db\"].savecount).toEqual(3);\n          expect(mem.hashStore[\"sandbox.db.0\"].savecount).toEqual(2);\n          expect(mem.hashStore[\"sandbox.db.1\"].savecount).toEqual(2);\n\n          // ok now lets load from it\n          let db2 = new Loki(\"sandbox.db\");\n          db2.initializePersistence({adapter: adapter, throttledSaves: throttled});\n          db2.loadDatabase().then(() => {\n            expect(db2[\"_collections\"].length).toEqual(2);\n            expect(db2[\"_collections\"][0].count()).toEqual(4);\n            expect(db2[\"_collections\"][1].count()).toEqual(1);\n            expect(db2.getCollection<User>(\"items\").findOne({name: \"tyrfing\"}).maker).toEqual(\"elves\");\n            expect(db2.getCollection<AB>(\"another\").findOne({a: 1}).b).toEqual(3);\n\n            // verify empty collection saves with paging\n            db.addCollection(\"extracoll\");\n            db.saveDatabase().then(() => {\n              expect(mem.hashStore[\"sandbox.db\"].savecount).toEqual(4);\n              expect(mem.hashStore[\"sandbox.db.0\"].savecount).toEqual(2);\n              expect(mem.hashStore[\"sandbox.db.1\"].savecount).toEqual(2);\n              expect(mem.hashStore[\"sandbox.db.2\"].savecount).toEqual(1);\n\n              // now verify loading empty collection works with paging codepath\n              db2 = new Loki(\"sandbox.db\");\n              db2.initializePersistence({adapter: adapter, throttledSaves: throttled});\n              db2.loadDatabase().then(() => {\n                expect(db2[\"_collections\"].length).toEqual(3);\n                expect(db2[\"_collections\"][0].count()).toEqual(4);\n                expect(db2[\"_collections\"][1].count()).toEqual(1);\n                expect(db2[\"_collections\"][2].count()).toEqual(0);\n\n                // since async calls are being used, use jasmine done() to indicate test finished\n                done();\n              });\n            });\n          });\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/partitioning-adapter/src/index.ts",
    "content": "import { PartitioningAdapter } from \"./partitioning_adapter\";\n\nexport {PartitioningAdapter};\nexport default PartitioningAdapter;\n"
  },
  {
    "path": "packages/partitioning-adapter/src/partitioning_adapter.ts",
    "content": "import { Loki } from \"../../loki/src/loki\";\nimport { StorageAdapter } from \"../../common/types\";\nimport { PLUGINS } from \"../../common/plugin\";\n\n/**\n * An adapter for adapters. Converts a non reference mode adapter into a reference mode adapter\n * which can perform destructuring and partitioning. Each collection will be stored in its own key/save and\n * only dirty collections will be saved. If you  turn on paging with default page size of 25megs and save\n * a 75 meg collection it should use up roughly 3 save slots (key/value pairs sent to inner adapter).\n * A dirty collection that spans three pages will save all three pages again\n * Paging mode was added mainly because Chrome has issues saving 'too large' of a string within a\n * single IndexedDB row. If a single document update causes the collection to be flagged as dirty, all\n * of that collection's pages will be written on next save.\n */\nexport class PartitioningAdapter implements StorageAdapter {\n\n  public mode: string;\n  private _adapter: StorageAdapter;\n  private _dbref: Loki;\n  private _dbname: string;\n  private _pageIterator: PartitioningAdapter.PageIterator;\n  private _paging: boolean;\n  private _pageSize: number;\n  private _delimiter: string;\n  private _dirtyPartitions: number[];\n\n  /**\n   * Registers the partitioning adapter as plugin.\n   */\n  static register(): void {\n    PLUGINS[\"PartitioningAdapter\"] = PartitioningAdapter;\n  }\n\n  /**\n   * Deregisters the partitioning storage as plugin.\n   */\n  static deregister(): void {\n    delete PLUGINS[\"PartitioningAdapter\"];\n  }\n\n  /**\n   * @param {object} adapter - reference to a 'non-reference' mode loki adapter instance.\n   * @param {boolean} paging - (default: false) set to true to enable paging collection data.\n   * @param {number} pageSize - (default : 25MB) you can use this to limit size of strings passed to inner adapter.\n   * @param {string} delimiter - allows you to override the default delimiter\n   */\n  constructor(adapter: StorageAdapter, {paging = false, pageSize = 25 * 1024 * 1024, delimiter = \"$<\\n\"} = {}) {\n    this.mode = \"reference\";\n    this._adapter = null;\n    this._dbref = null;\n    this._dbname = \"\";\n    this._pageIterator = {};\n\n    // verify user passed an appropriate adapter\n    if (adapter) {\n      if (adapter.mode === \"reference\") {\n        throw new Error(\"LokiPartitioningAdapter cannot be instantiated with a reference mode adapter.\");\n      } else {\n        this._adapter = adapter;\n      }\n    } else {\n      throw new Error(\"LokiPartitioningAdapter requires a (non-reference mode) adapter on construction.\");\n    }\n\n    this._paging = paging;\n    this._pageSize = pageSize;\n    this._delimiter = delimiter;\n  }\n\n  /**\n   * Loads a database which was partitioned into several key/value saves.\n   * (Loki persistence adapter interface function)\n   *\n   * @param {string} dbname - name of the database (filename/keyname)\n   * @returns {Promise} a Promise that resolves after the database was loaded\n   */\n  public loadDatabase(dbname: string): Promise<any> {\n    this._dbname = dbname;\n    this._dbref = new Loki(dbname);\n\n    // load the db container (without data)\n    return this._adapter.loadDatabase(dbname).then((result: string) => {\n      if (typeof result !== \"string\") {\n        throw new Error(\"LokiPartitioningAdapter received an unexpected response from inner adapter loadDatabase()\");\n      }\n\n      // I will want to use loki destructuring helper methods so i will inflate into typed instance\n      let db = JSON.parse(result);\n      this._dbref.loadJSONObject(db);\n      db = null;\n\n      if (this._dbref._collections.length === 0) {\n        return this._dbref;\n      }\n\n      this._pageIterator = {\n        collection: 0,\n        pageIndex: 0\n      };\n\n      return this._loadNextPartition(0).then(() => this._dbref);\n    });\n  }\n\n  /**\n   * Used to sequentially load each collection partition, one at a time.\n   *\n   * @param {int} partition - ordinal collection position to load next\n   * @returns {Promise} a Promise that resolves after the next partition is loaded\n   */\n  private _loadNextPartition(partition: number): Promise<void> {\n    if (this._paging === true) {\n      this._pageIterator.pageIndex = 0;\n      return this._loadNextPage();\n    }\n\n    const keyname = this._dbname + \".\" + partition;\n    return this._adapter.loadDatabase(keyname).then((result: string) => {\n      this._dbref._collections[partition]._data = this._dbref.deserializeCollection(result, {\n        delimited: true\n      });\n\n      if (++partition < this._dbref._collections.length) {\n        return this._loadNextPartition(partition);\n      }\n      return Promise.resolve();\n    });\n  }\n\n  /**\n   * Used to sequentially load the next page of collection partition, one at a time.\n   *\n   * @returns {Promise} a Promise that resolves after the next page is loaded\n   */\n  private _loadNextPage(): Promise<void> {\n    // calculate name for next saved page in sequence\n    const keyname = this._dbname + \".\" + this._pageIterator.collection + \".\" + this._pageIterator.pageIndex;\n\n    // load whatever page is next in sequence\n    return this._adapter.loadDatabase(keyname).then((result: string) => {\n      let data = result.split(this._delimiter);\n      result = \"\"; // free up memory now that we have split it into array\n      let dlen = data.length;\n\n      // detect if last page by presence of final empty string element and remove it if so\n      const isLastPage = (data[dlen - 1] === \"\");\n      if (isLastPage) {\n        data.pop();\n        dlen = data.length;\n        // empty collections are just a delimiter meaning two blank items\n        if (data[dlen - 1] === \"\" && dlen === 1) {\n          data.pop();\n          dlen = data.length;\n        }\n      }\n\n      // convert stringified array elements to object instances and push to collection data\n      for (let idx = 0; idx < dlen; idx++) {\n        this._dbref._collections[this._pageIterator.collection]._data.push(JSON.parse(data[idx]));\n        data[idx] = null;\n      }\n      data = [];\n\n      // if last page, we are done with this partition\n      if (isLastPage) {\n        // if there are more partitions, kick off next partition load\n        if (++this._pageIterator.collection < this._dbref._collections.length) {\n          return this._loadNextPartition(this._pageIterator.collection);\n        }\n      } else {\n        this._pageIterator.pageIndex++;\n        return this._loadNextPage();\n      }\n      return Promise.resolve();\n    });\n  }\n\n  /**\n   * Saves a database by partioning into separate key/value saves.\n   * (Loki 'reference mode' persistence adapter interface function)\n   *\n   * @param {string} dbname - name of the database (filename/keyname)\n   * @param {object} dbref - reference to database which we will partition and save.\n   * @returns {Promise} a Promise that resolves after the database was deleted\n   *\n   */\n  public exportDatabase(dbname: string, dbref: Loki): Promise<void> {\n    this._dbref = dbref;\n    this._dbname = dbname;\n\n    // queue up dirty partitions to be saved\n    this._dirtyPartitions = [-1];\n    for (let idx = 0; idx < dbref._collections.length; idx++) {\n      if (dbref._collections[idx]._dirty) {\n        this._dirtyPartitions.push(idx);\n      }\n    }\n\n    return this._saveNextPartition();\n  }\n\n  /**\n   * Helper method used internally to save each dirty collection, one at a time.\n   *\n   * @returns {Promise} a Promise that resolves after the next partition is saved\n   */\n  private _saveNextPartition(): Promise<void> {\n    const partition = this._dirtyPartitions.shift();\n    const keyname = this._dbname + ((partition === -1) ? \"\" : (\".\" + partition));\n\n    // if we are doing paging and this is collection partition\n    if (this._paging && partition !== -1) {\n      this._pageIterator = {\n        collection: partition,\n        docIndex: 0,\n        pageIndex: 0\n      };\n\n      // since saveNextPage recursively calls itself until done, our callback means this whole paged partition is finished\n      return this._saveNextPage().then(() => {\n        if (this._dirtyPartitions.length !== 0) {\n          return this._saveNextPartition();\n        }\n        return Promise.resolve();\n      });\n    }\n\n    // otherwise this is 'non-paged' partioning...\n    const result = this._dbref.serializeDestructured({\n      partitioned: true,\n      delimited: true,\n      partition\n    });\n\n    return this._adapter.saveDatabase(keyname, result as string).then(() => {\n      if (this._dirtyPartitions.length !== 0) {\n        return this._saveNextPartition();\n      }\n      return Promise.resolve();\n    });\n  }\n\n  /**\n   * Helper method used internally to generate and save the next page of the current (dirty) partition.\n   *\n   * @returns {Promise} a Promise that resolves after the next partition is saved\n   */\n  private _saveNextPage(): Promise<void> {\n    const coll = this._dbref._collections[this._pageIterator.collection];\n    const keyname = this._dbname + \".\" + this._pageIterator.collection + \".\" + this._pageIterator.pageIndex;\n    let pageLen = 0;\n    const cdlen = coll._data.length;\n    const delimlen = this._delimiter.length;\n    let serializedObject = \"\";\n    let pageBuilder = \"\";\n    let doneWithPartition = false;\n    let doneWithPage = false;\n\n    const pageSaveCallback = () => {\n      pageBuilder = \"\";\n\n      // update meta properties then continue process by invoking callback\n      if (!doneWithPartition) {\n        this._pageIterator.pageIndex++;\n        return this._saveNextPage();\n      }\n      return Promise.resolve();\n    };\n\n    if (coll._data.length === 0) {\n      doneWithPartition = true;\n    }\n\n    while (!doneWithPartition && !doneWithPage) {\n      if (!doneWithPartition) {\n        // serialize object\n        serializedObject = JSON.stringify(coll._data[this._pageIterator.docIndex]);\n        pageBuilder += serializedObject;\n        pageLen += serializedObject.length;\n\n        // if no more documents in collection to add, we are done with partition\n        if (++this._pageIterator.docIndex >= cdlen) doneWithPartition = true;\n      }\n      // if our current page is bigger than defined pageSize, we are done with page\n      if (pageLen >= this._pageSize) doneWithPage = true;\n\n      // if not done with current page, need delimiter before next item\n      // if done with partition we also want a delmiter to indicate 'end of pages' final empty row\n      if (!doneWithPage || doneWithPartition) {\n        pageBuilder += this._delimiter;\n        pageLen += delimlen;\n      }\n    }\n    // if we are done with page save it and pass off to next recursive call or callback\n    return this._adapter.saveDatabase(keyname, pageBuilder).then(pageSaveCallback);\n  }\n}\n\nnamespace PartitioningAdapter {\n  export interface PageIterator {\n    collection?: number;\n    docIndex?: number;\n    pageIndex?: number;\n  }\n}\n"
  },
  {
    "path": "packages/partitioning-adapter/webpack.config.js",
    "content": "/* global __dirname, module, require */\nconst path = require(\"path\");\nconst webpackConigCreator = require('../../config/webpack-config-creator.js');\n\nmodule.exports = webpackConigCreator({\n  entry: path.join(__dirname, \"src\", \"index.ts\"),\n  filename: \"lokidb.partitioning-adapter.js\",\n  library: \"@lokidb/partitioning-adapter\",\n  externals: {\n    \"../../loki/src/loki\": \"@lokidb/loki\"\n  },\n});\n"
  },
  {
    "path": "scripts/build.ts",
    "content": "import * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as process from \"process\";\nimport {PACKAGES, getBuildInformation, run, copy, makeDir, remove_dir, print} from \"./common\";\n\nconst BUILD_DIST = process.argv.includes(\"--dist\");\nconst BUILD_INFO = getBuildInformation(true);\n\nmain();\nprocess.exit(0);\n\nfunction main() {\n  if (BUILD_INFO.release && BUILD_DIST) {\n    print(\"+++ Release build +++\");\n    // Update npm package version.\n    run(\"npm\", [\"version\", BUILD_INFO.version, \"--no-git-tag-version\"]);\n  }\n\n  build();\n}\n\nfunction build() {\n  const ROOT_DIR = process.cwd();\n  const UGLIFYJS = path.join(ROOT_DIR, \"node_modules\", \"uglify-es\", \"bin\", \"uglifyjs\");\n\n  print(`====== BUILDING: Version ${BUILD_INFO.version}`);\n\n  const README = `${ROOT_DIR}/README.md`;\n\n  for (const PACKAGE of PACKAGES) {\n\n    const SRC_DIR = path.join(ROOT_DIR, \"packages\", PACKAGE);\n    const SRC_PACKAGE_JSON = path.join(SRC_DIR, \"package.json\");\n    const SRC_WEBPACK_CONFIG = path.join(SRC_DIR, \"webpack.config.js\");\n    const OUT_PACKAGES_DIR = BUILD_DIST ? path.join(ROOT_DIR, \"dist\", \"packages\") : path.join(ROOT_DIR, \"build\", \"packages\");\n    const OUT_DIR = path.join(OUT_PACKAGES_DIR, PACKAGE);\n    const OUT_DIR_FILENAME = path.join(OUT_DIR, `lokidb.${PACKAGE}.js`);\n    const OUT_DIR_FILENAME_MINIFIED = path.join(OUT_DIR, `lokidb.${PACKAGE}.min.js`);\n    const NPM_PACKAGES_DIR = BUILD_DIST ? path.join(ROOT_DIR, \"dist\", \"packages-dist\") : null;\n    const NPM_DIR = BUILD_DIST ? path.join(NPM_PACKAGES_DIR, PACKAGE) : null;\n    const NPM_PACKAGE_JSON = BUILD_DIST ? path.join(NPM_DIR, \"package.json\") : null;\n\n    print(`======      [${PACKAGE}]: PACKING    =====`);\n    remove_dir(OUT_DIR);\n\n    run(\"webpack-cli\", [\"--config=\" + SRC_WEBPACK_CONFIG, \"--output-path=\" + OUT_DIR]);\n\n    // Update script tag export of UMD to use default module export.\n    {\n      const bundle = fs.readFileSync(OUT_DIR_FILENAME).toString();\n\n      // Split on script export of UMD.\n      const script_start = bundle.search(/root\\[.+] = factory.+\\);/);\n      const script_end = script_start + bundle.slice(script_start).indexOf(\";\") + 1;\n\n      const umd_part = bundle.slice(0, script_start);\n      let script_part = bundle.slice(script_start, script_end);\n      const library_part = bundle.slice(script_end);\n\n      // Update script tag export of UMD to use default module export.\n      let library_name = script_part.match(/root\\[\"@lokidb\\/(.+?)\"/)[1];\n      // Transform library name to Loki<LibraryName>.\n      let simple_name = library_name.replace(/(?:-|^)([a-z])/ig, (_, letter) => {\n        return letter.toUpperCase();\n      });\n      if (!simple_name.startsWith(\"Loki\")) {\n        simple_name = \"Loki\" + simple_name;\n      }\n\n      // Add default export to script.\n      script_part = `{ ${script_part} root[\"${simple_name}\"] = root[\"@lokidb/${library_name}\"].default; }`;\n      fs.writeFileSync(OUT_DIR_FILENAME, umd_part + script_part + library_part);\n    }\n\n    if (BUILD_DIST) {\n      print(`======      [${PACKAGE}]: BUNDLING   =====`);\n      remove_dir(NPM_DIR);\n      makeDir(NPM_DIR);\n\n      // Copy files to dist and npm dist.\n      copy(OUT_DIR, NPM_PACKAGES_DIR, true);\n      copy(SRC_PACKAGE_JSON, NPM_DIR);\n      copy(README, NPM_DIR);\n    }\n\n    print(`======      [${PACKAGE}]: MINIFY     =====`);\n    run(\"node\", [UGLIFYJS, OUT_DIR_FILENAME, \"--output\", OUT_DIR_FILENAME_MINIFIED]);\n\n    if (BUILD_DIST) {\n      print(`======      [${PACKAGE}]: VERSIONING =====`);\n      const data = fs.readFileSync(NPM_PACKAGE_JSON).toString(\"utf8\");\n      let json = JSON.parse(data);\n      json.version = BUILD_INFO.version;\n      // Update version of other needed LokiDB packages\n      if (json.dependencies) {\n        for (let pack of Object.keys(json.dependencies)) {\n          if (pack.startsWith(\"@lokidb/\")) {\n            json.dependencies[pack] = BUILD_INFO.version;\n          }\n        }\n      }\n      if (json.optionalDependencies) {\n        for (let pack of Object.keys(json.optionalDependencies)) {\n          if (pack.startsWith(\"@lokidb/\")) {\n            json.optionalDependencies[pack] = BUILD_INFO.version;\n          }\n        }\n      }\n      fs.writeFileSync(NPM_PACKAGE_JSON, JSON.stringify(json, null, 2));\n    }\n  }\n}\n"
  },
  {
    "path": "scripts/common.ts",
    "content": "import {spawnSync} from \"child_process\";\n\nconst cash = require(\"cash\");\n\nexport const PACKAGES = [\n  \"loki\",\n  \"partitioning-adapter\",\n  \"local-storage\",\n  \"indexed-storage\",\n  \"fs-storage\",\n  \"memory-storage\",\n  \"full-text-search\",\n  \"full-text-search-language\",\n  \"full-text-search-language-de\",\n  \"full-text-search-language-en\",\n];\n\nexport function run(command: string, args: string[] = [], object: { shell?: boolean } = {}) {\n  if (object.shell === undefined) {\n    object.shell = true;\n  }\n  const child = spawnSync(command, args, object);\n  if (child.status !== 0) {\n    throw Error(\"Process failed: \" + command + \" \" + args.join(\" \") + \"\\n\"\n      + (child.error ? child.error.message : child.output));\n  }\n  return child.output;\n}\n\nexport function copy(src: string, dst: string, recursive = false) {\n  cash.cp(`${src} ${dst}`, {recursive: recursive});\n}\n\nexport function remove_dir(path: string) {\n  cash.rm(path, {recursive: true});\n}\n\nexport function makeDir(path: string) {\n  cash.mkdir(path, {parents: true});\n}\n\nexport function print(txt: string, lb: string = \"\\n\") {\n  process.stdout.write(txt + lb);\n}\n\nexport function printError(txt: string, lb: string = \"\\n\") {\n  process.stderr.write(txt + lb);\n}\n\nconst IS_PULL_REQUEST = process.env.TRAVIS_PULL_REQUEST !== \"false\";\nconst IS_MASTER_TARGET = process.env.TRAVIS_BRANCH === process.env.GIT_BRANCH;\nconst COMMIT_TAG = process.env.TRAVIS_TAG;\n\nexport type BuildInformation = {\n  release: boolean;\n  version: string;\n};\n\nexport function getBuildInformation(optional_fetch: boolean): BuildInformation {\n  try {\n    fetchBranchesAndTags();\n  } catch (e) {\n    if (!optional_fetch) {\n      throw e;\n    }\n  }\n\n  const buildInformation: BuildInformation = {\n    release: checkIfReleaseMode(),\n    version: require(\"../package.json\").version,\n  };\n\n  if (buildInformation.release) {\n    buildInformation.version = COMMIT_TAG.match(/Release_(.+)/)[1];\n  }\n\n  return buildInformation;\n}\n\nfunction fetchBranchesAndTags() {\n  run(\"git\", [\"config\", \"--replace-all\", \"remote.origin.fetch\", \"+refs/heads/*:refs/remotes/origin/*\"]);\n  run(\"git\", [\"fetch\"]);\n  run(\"git\", [\"fetch\", \"--tags\"]);\n}\n\nfunction checkIfReleaseMode() {\n  if (!IS_PULL_REQUEST && !IS_MASTER_TARGET && COMMIT_TAG.startsWith(\"Release\")) {\n    // Safe current commit.\n    const currentCommit = run(\"git\", [\"rev-parse\", \"HEAD\"])[1].toString().slice(0, -1);\n    // Check if masters head is the same as tag.\n    run(\"git\", [\"checkout\", \"master\"]);\n    const is_release = run(\"git\", [\"describe\", \"--tags\", \"--always\"])[1].toString() === COMMIT_TAG + \"\\n\";\n    // Go back to current commit.\n    run(\"git\", [\"checkout\", currentCommit]);\n    return is_release;\n  }\n  return false;\n}\n"
  },
  {
    "path": "scripts/deploy.ts",
    "content": "import * as child_process from \"child_process\";\nimport * as fs from \"fs\";\nimport * as process from \"process\";\nimport * as stream from \"stream\";\nimport {PACKAGES, getBuildInformation, print, printError, run} from \"./common\";\n\nconst RELEASE_TIMEOUT = 10 * 60 * 1000; // 10 minutes\n\nconst GH_TOKEN = process.env.GH_TOKEN;\nconst COMMIT_TAG = process.env.TRAVIS_TAG;\nconst TRAVIS_REPO_SLUG = process.env.TRAVIS_REPO_SLUG;\n\nconst BUILD_INFO = getBuildInformation(false);\nconst RELEASE_BRANCH = \"Releasing_\" + BUILD_INFO.version;\n\nconst CHANGELOG = {\n  file: \"CHANGELOG.md\",\n  header: \"\",\n  body: \"\",\n  changes: \"\",\n  get log() {\n    if (this.body) {\n      return this.header + \"\\n\\n\" + this.body + \"\\n\\n## Commit Summary\\n\" + this.changes + \"\\n\\n\\n\";\n    } else {\n      return this.header + \"\\n\\n\\n\" + this.changes + \"\\n\\n\\n\";\n    }\n  },\n  get log_without_head() {\n    if (this.body) {\n      return this.body + \"\\n\\n##Commit Summary\" + this.changes;\n    } else {\n      return this.changes;\n    }\n  },\n  get version_and_date() {\n    const version = this.header.split(\"\\n\")[1];\n    return version.substr(version.search(\" \") + 1);\n  }\n};\n\nmain(); \n\nfunction main() {\n  if (BUILD_INFO.release) {\n    updateChangelog()\n      .then(() => prepareReleaseBranch())\n      .then(() => delayRelease())\n      .then(() => {\n        publishToNPM();\n        mergeReleaseBranch();\n      })\n      .catch((e) => {\n        printError(e);\n        process.exit(1);\n      });\n  } else {\n    print(\"Nothing to deploy...\");\n  }\n}\n\nfunction loginToNPM() {\n  return new Promise((resolve, reject) => {\n    const username = process.env.NPM_USERNAME;\n    const password = process.env.NPM_PASSWORD;\n    const email = process.env.NPM_EMAIL;\n\n    if (!username || !password || !email || !email.includes(\"@\")) {\n      reject(Error(\"Login data not set probably.\"));\n    }\n\n    // Write to stdin to login.\n    const npmLogin = child_process.spawn(\"npm\", [\"login\"]);\n    npmLogin.stdout.on(\"data\", (data) => {\n      const msg = data.toString();\n      if (msg.startsWith(\"Username\")) {\n        npmLogin.stdin.write(username + \"\\n\");\n      } else if (msg.startsWith(\"Password\")) {\n        npmLogin.stdin.write(password + \"\\n\");\n      } else if (msg.startsWith(\"Email\")) {\n        npmLogin.stdin.write(email + \"\\n\");\n      }\n    });\n    npmLogin.stderr.on(\"data\", (data) => {\n      printError(data.toString());\n      npmLogin.stdout.destroy();\n      npmLogin.stderr.destroy();\n      npmLogin.stdin.end();\n    });\n    npmLogin.on(\"close\", (code) => {\n      if (code !== 0) {\n        reject(Error(\"NPM login failed.\"));\n      }\n      resolve();\n    });\n  });\n}\n\nfunction publishToNPM() {\n  print(`====== PUBLISHING: Version ${BUILD_INFO.version}`);\n\n  loginToNPM()\n    .then(() => {\n      for (const PACKAGE of PACKAGES) {\n        run(\"npm\", [\"publish\", `${process.cwd()}/dist/packages-dist/${PACKAGE}`, \"--access=public\"]);\n        print(`======      [${PACKAGE}]: PUBLISHED =====`);\n      }\n    });\n}\n\nfunction updateChangelog() {\n  print(\"====== Update changelog.\");\n  return generateChangelog()\n    .then(() => {\n      if (fs.existsSync(CHANGELOG.file)) {\n        const data = fs.readFileSync(CHANGELOG.file);\n        fs.writeFileSync(CHANGELOG.file, CHANGELOG.log + data);\n      } else {\n        fs.writeFileSync(CHANGELOG.file, CHANGELOG.log);\n      }\n    });\n}\n\nfunction generateChangelog() {\n  return new Promise((resolve, reject) => {\n    // Initiate the source\n    const changelog_buffer = new stream.PassThrough();\n\n    let changelog = \"\";\n    changelog_buffer.on(\"data\", (data) => {\n      changelog += data.toString();\n    });\n\n    changelog_buffer.on(\"error\", (error) => {\n      reject(error);\n    });\n\n    changelog_buffer.on(\"end\", () => {\n      const changelog_lines = changelog.split(\"\\n\");\n\n      CHANGELOG.header = changelog_lines.splice(0, 2).join(\"\\n\");\n      CHANGELOG.changes = changelog_lines.splice(2, changelog_lines.length - 6).join(\"\\n\");\n\n      // Get changelog body.\n      const tag_message = run(\"git\", [\"cat-file\", \"-p\", COMMIT_TAG])[1].toString().split(\"\\n\");\n      if (tag_message[0].startsWith(\"object\")) {\n        CHANGELOG.body = tag_message.slice(5).join(\"\\n\");\n      }\n\n      resolve();\n    });\n\n    // Generate changelog from commit messages.\n    require(\"conventional-changelog\")({\n      preset: \"angular\"\n    }).pipe(changelog_buffer);\n  });\n}\n\nfunction delayRelease() {\n  // Delay the release to cancel.\n  print(\"Delayed release for \" + (RELEASE_TIMEOUT / 60000) + \" minutes.\");\n  const current_time = new Date().getTime();\n  return new Promise(function (resolve) {\n    function echo() {\n      print(\".\", \"\");\n      if (current_time + RELEASE_TIMEOUT >= new Date().getTime()) {\n        setTimeout(echo, 60000);\n      } else {\n        print(\"\");\n        resolve();\n      }\n    }\n\n    echo();\n  });\n}\n\nfunction prepareReleaseBranch() {\n  print(\"====== Prepare release branch\");\n  run(\"git\", [\"checkout\", \"-b\", RELEASE_BRANCH]);\n  run(\"git\", [\"add\", \"-u\"]);\n  run(\"git\", [\"add\", \"-f\", \"dist/packages/*\"]);\n  run(\"git\", [\"commit\", \"-m\", `\"Release ${BUILD_INFO.version}\"`]);\n  run(\"git\", [\"remote\", \"set-url\", \"origin\", `https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git`]);\n  run(\"git\", [\"push\", \"--set-upstream\", \"origin\", RELEASE_BRANCH]);\n}\n\nfunction mergeReleaseBranch() {\n  print(\"====== Merge release branch\");\n  run(\"git\", [\"checkout\", \"master\"]);\n  run(\"git\", [\"merge\", RELEASE_BRANCH]);\n\n  run(\"git\", [\"push\", \"origin\", `:refs/tags/${COMMIT_TAG}`]);\n  run(\"git\", [\"tag\", BUILD_INFO.version]);\n\n  run(\"git\", [\"push\"]);\n  run(\"git\", [\"tag\", \"-d\", COMMIT_TAG]);\n  run(\"git\", [\"push\", \"--tags\"]);\n\n  // Remove release branch.\n  run(\"git\", [\"branch\", \"-d\", RELEASE_BRANCH]);\n  run(\"git\", [\"push\", \"origin\", \"--delete\", RELEASE_BRANCH]);\n\n  print(\"====== Create GitHub release\");\n  const release = {\n    \"tag_name\": BUILD_INFO.version,\n    \"target_commitish\": \"master\",\n    \"name\": CHANGELOG.version_and_date,\n    \"body\": CHANGELOG.log_without_head,\n    \"draft\": false,\n    \"prerelease\": false\n  };\n  run(\"curl\", [\"--request\", \"POST\", \"--data\", JSON.stringify(release),\n    `https://${GH_TOKEN}@api.github.com/repos/${TRAVIS_REPO_SLUG}/releases`]);\n\n  print(\"====== Update documentation\");\n  run(\"mkdocs\", [\"gh-deploy\"]);\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"compilerOptions\": {\n    \"outDir\": \"./.ts/\",\n    \"inlineSourceMap\": true,\n    \"sourceMap\": false,\n    \"declaration\": true,\n    \"module\": \"commonjs\",\n    \"strictPropertyInitialization\": true,\n    \"alwaysStrict\": true,\n    \"noImplicitAny\": true,\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"target\": \"es6\",\n    \"lib\": [\n      \"es2017\",\n      \"dom\"\n    ],\n    \"typeRoots\": [\n      \"node_modules/@types\"\n    ],\n    \"types\": [\n      \"jasmine\",\n      \"jasmine-expect\",\n      \"node\"\n    ]\n  },\n  \"include\": [\n    \"packages/*/src/**/*.ts\"\n  ],\n  \"typedocOptions\": {\n    \"mode\": \"file\",\n    \"out\": \"docs/api\",\n    \"exclude\": \"**/spec/**/*.ts\",\n    \"theme\": \"default\",\n    \"ignoreCompilerErrors\": true,\n    \"excludePrivate\": true,\n    \"excludeNotExported\": true,\n    \"target\": \"ES6\",\n    \"preserveConstEnums\": true,\n    \"stripInternal\": true,\n    \"suppressExcessPropertyErrors\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"module\": \"umd\"\n  }\n}\n"
  }
]