Index: frontend/node_modules/istanbul-lib-instrument/CHANGELOG.md
===================================================================
--- frontend/node_modules/istanbul-lib-instrument/CHANGELOG.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/istanbul-lib-instrument/CHANGELOG.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,631 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+
+## [5.2.1](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument-v5.2.0...istanbul-lib-instrument-v5.2.1) (2022-10-05)
+
+
+### Bug Fixes
+
+* handle error when inputSourceMap is not a plain object ([#662](https://github.com/istanbuljs/istanbuljs/issues/662)) ([3e3611f](https://github.com/istanbuljs/istanbuljs/commit/3e3611f0efffefd5f87e6cbccd840e9f33aaf43e))
+
+## [5.2.0](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument-v5.1.0...istanbul-lib-instrument-v5.2.0) (2022-02-21)
+
+
+### Features
+
+* exclude Empty Object and Arrays in Truthy Detection ([#666](https://github.com/istanbuljs/istanbuljs/issues/666)) ([e279684](https://github.com/istanbuljs/istanbuljs/commit/e279684e735f4b7dbe2b632cde2515f6862099de))
+
+## [5.1.0](https://www.github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument-v5.0.4...istanbul-lib-instrument-v5.1.0) (2021-10-27)
+
+
+### Features
+
+* option to evaluate logical truthiness, for applications such as fuzzing ([#629](https://www.github.com/istanbuljs/istanbuljs/issues/629)) ([a743b84](https://www.github.com/istanbuljs/istanbuljs/commit/a743b8442e977f0c77ffa282eed7ac84ca200d1f))
+
+### [5.0.4](https://www.github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument-v5.0.3...istanbul-lib-instrument-v5.0.4) (2021-10-16)
+
+
+### Bug Fixes
+
+* **magic-value:** make incrementing magic value a manual step ([#641](https://www.github.com/istanbuljs/istanbuljs/issues/641)) ([823010b](https://www.github.com/istanbuljs/istanbuljs/commit/823010b821cf81bd91377d75fc83f0875925db66))
+
+### [5.0.3](https://www.github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument-v5.0.2...istanbul-lib-instrument-v5.0.3) (2021-10-06)
+
+
+### Bug Fixes
+
+* coverage.branchMap else location. ([#633](https://www.github.com/istanbuljs/istanbuljs/issues/633)) ([eb4b4ec](https://www.github.com/istanbuljs/istanbuljs/commit/eb4b4ec8f4b858655a66b0033fcc662f44ef4cc9))
+
+### [5.0.2](https://www.github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument-v5.0.1...istanbul-lib-instrument-v5.0.2) (2021-09-13)
+
+
+### Bug Fixes
+
+* **build:** verfiy automated publication ([b232690](https://www.github.com/istanbuljs/istanbuljs/commit/b232690193f4b524332046c96dd1cdc6e881c6c7))
+
+### [5.0.1](https://www.github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument-v5.0.0...istanbul-lib-instrument-v5.0.1) (2021-09-13)
+
+
+### Bug Fixes
+
+* **build:** verfiy automated publication ([74c96bd](https://www.github.com/istanbuljs/istanbuljs/commit/74c96bdc4224a06e2e1166ebd9adf8faf28438b1))
+
+## [5.0.0](https://www.github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument-v4.0.3...istanbul-lib-instrument-v5.0.0) (2021-09-13)
+
+
+### ⚠ BREAKING CHANGES
+
+* istanbul-lib-instrument no longer uses babel
+
+### Code Refactoring
+
+* istanbul-lib-instrument no longer uses babel ([8d3badb](https://www.github.com/istanbuljs/istanbuljs/commit/8d3badb8f6c9a4bed9af8e19c3ac6459ebd7267b))
+
+## [4.0.3](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@4.0.2...istanbul-lib-instrument@4.0.3) (2020-05-09)
+
+
+### Bug Fixes
+
+* Prevent readInitialCoverage from reading babel config ([#562](https://github.com/istanbuljs/istanbuljs/issues/562)) ([49b4745](https://github.com/istanbuljs/istanbuljs/commit/49b474525c15e703642916011bd86f663aca0c3d))
+
+
+
+
+
+## [4.0.2](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@4.0.1...istanbul-lib-instrument@4.0.2) (2020-05-06)
+
+
+### Bug Fixes
+
+* Add ts-ignore to reassignment of generated function ([#557](https://github.com/istanbuljs/istanbuljs/issues/557)) ([817efb0](https://github.com/istanbuljs/istanbuljs/commit/817efb04fc161efae426b2231a0221606b09f559))
+* Use @babel/core for all babel imports. ([#555](https://github.com/istanbuljs/istanbuljs/issues/555)) ([a99a13e](https://github.com/istanbuljs/istanbuljs/commit/a99a13ee6931fc124a2a723c3f511cdbcb0aa81d))
+
+
+
+
+
+## [4.0.1](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@4.0.0...istanbul-lib-instrument@4.0.1) (2020-02-03)
+
+
+### Bug Fixes
+
+* Always call coverage initialization function ([#524](https://github.com/istanbuljs/istanbuljs/issues/524)) ([c6536c1](https://github.com/istanbuljs/istanbuljs/commit/c6536c14bf0663ca7e0493dd40ea132b05352594))
+
+
+
+
+
+# [4.0.0](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@4.0.0-alpha.3...istanbul-lib-instrument@4.0.0) (2019-12-20)
+
+**Note:** Version bump only for package istanbul-lib-instrument
+
+
+
+
+
+# [4.0.0-alpha.3](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@4.0.0-alpha.2...istanbul-lib-instrument@4.0.0-alpha.3) (2019-12-07)
+
+**Note:** Version bump only for package istanbul-lib-instrument
+
+
+
+
+
+# [4.0.0-alpha.2](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@4.0.0-alpha.1...istanbul-lib-instrument@4.0.0-alpha.2) (2019-11-01)
+
+
+### Bug Fixes
+
+* Produce properly merged source-maps when inputSourceMap is provided ([#487](https://github.com/istanbuljs/istanbuljs/issues/487)) ([8f8c88e](https://github.com/istanbuljs/istanbuljs/commit/8f8c88e3a2add4c08729e41e356aa7981dc69d4d))
+
+
+
+
+
+# [4.0.0-alpha.1](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@4.0.0-alpha.0...istanbul-lib-instrument@4.0.0-alpha.1) (2019-10-06)
+
+
+### Bug Fixes
+
+* Eliminate babel hoisting of the coverage variable ([#481](https://github.com/istanbuljs/istanbuljs/issues/481)) ([8dfbcba](https://github.com/istanbuljs/istanbuljs/commit/8dfbcba)), closes [#92](https://github.com/istanbuljs/istanbuljs/issues/92)
+* Honor ignore hints in chained if statements ([#469](https://github.com/istanbuljs/istanbuljs/issues/469)) ([a629770](https://github.com/istanbuljs/istanbuljs/commit/a629770)), closes [#468](https://github.com/istanbuljs/istanbuljs/issues/468)
+* Populate lastFileCoverage for already instrumented files ([#470](https://github.com/istanbuljs/istanbuljs/issues/470)) ([ea6d779](https://github.com/istanbuljs/istanbuljs/commit/ea6d779)), closes [istanbuljs/nyc#594](https://github.com/istanbuljs/nyc/issues/594)
+
+
+### Features
+
+* Use @istanbuljs/schema to pull defaults ([#485](https://github.com/istanbuljs/istanbuljs/issues/485)) ([87e27f3](https://github.com/istanbuljs/istanbuljs/commit/87e27f3)), closes [#460](https://github.com/istanbuljs/istanbuljs/issues/460)
+
+
+### BREAKING CHANGES
+
+* The defaults for `autoWrap`, `preserveComments`,
+`esModules` and `produceSourceMap` are now true.  This applies only to
+the stand-alone instrumenter, the visitor does not use these options.
+* The `flow` and `jsx` parser plugins are no longer
+enabled by default.  This applies only to the stand-alone instrumenter,
+the visitor does not use this option.
+* The `plugins` option of the stand-alone instrumenter
+has been renamed to `parserPlugins` to match nyc.
+
+
+
+
+
+# [4.0.0-alpha.0](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@3.3.0...istanbul-lib-instrument@4.0.0-alpha.0) (2019-06-19)
+
+
+### Features
+
+* Update dependencies, require Node.js 8 ([#401](https://github.com/istanbuljs/istanbuljs/issues/401)) ([bf3a539](https://github.com/istanbuljs/istanbuljs/commit/bf3a539))
+
+
+### BREAKING CHANGES
+
+* Node.js 8 is now required
+
+
+
+
+
+# [3.3.0](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@3.2.0...istanbul-lib-instrument@3.3.0) (2019-04-24)
+
+
+### Features
+
+* Enable classProperties and classPrivateProperties parsers and coverage. ([#379](https://github.com/istanbuljs/istanbuljs/issues/379)) ([c09dc38](https://github.com/istanbuljs/istanbuljs/commit/c09dc38))
+
+
+
+
+
+# [3.2.0](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@3.1.2...istanbul-lib-instrument@3.2.0) (2019-04-09)
+
+
+### Features
+
+* Add bigInt and importMeta to default parser plugins. ([#356](https://github.com/istanbuljs/istanbuljs/issues/356)) ([fb4d6ed](https://github.com/istanbuljs/istanbuljs/commit/fb4d6ed)), closes [#338](https://github.com/istanbuljs/istanbuljs/issues/338)
+
+
+
+
+
+## [3.1.2](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@3.1.1...istanbul-lib-instrument@3.1.2) (2019-04-03)
+
+
+### Bug Fixes
+
+* Be more friendly to ts-node. ([#352](https://github.com/istanbuljs/istanbuljs/issues/352)) ([40d15f5](https://github.com/istanbuljs/istanbuljs/commit/40d15f5)), closes [#336](https://github.com/istanbuljs/istanbuljs/issues/336)
+
+
+
+
+
+## [3.1.1](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@3.1.0...istanbul-lib-instrument@3.1.1) (2019-03-12)
+
+
+### Bug Fixes
+
+* Honor istanbul ignore next hints placed before export statement. ([#298](https://github.com/istanbuljs/istanbuljs/issues/298)) ([f24795d](https://github.com/istanbuljs/istanbuljs/commit/f24795d)), closes [#297](https://github.com/istanbuljs/istanbuljs/issues/297)
+
+
+
+
+
+# [3.1.0](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@3.0.1...istanbul-lib-instrument@3.1.0) (2019-01-26)
+
+
+### Features
+
+* dont skip for loop initialization instrumentation ([#188](https://github.com/istanbuljs/istanbuljs/issues/188)) ([2e0258e](https://github.com/istanbuljs/istanbuljs/commit/2e0258e))
+* New options coverageGlobalScope and coverageGlobalScopeFunc. ([#200](https://github.com/istanbuljs/istanbuljs/issues/200)) ([25509c7](https://github.com/istanbuljs/istanbuljs/commit/25509c7)), closes [#199](https://github.com/istanbuljs/istanbuljs/issues/199)
+
+
+
+
+
+<a name="3.0.1"></a>
+## [3.0.1](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@3.0.0...istanbul-lib-instrument@3.0.1) (2018-12-25)
+
+
+
+
+**Note:** Version bump only for package istanbul-lib-instrument
+
+<a name="3.0.0"></a>
+# [3.0.0](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@2.3.2...istanbul-lib-instrument@3.0.0) (2018-09-06)
+
+
+### Chores
+
+* Update test for babel 7. ([#218](https://github.com/istanbuljs/istanbuljs/issues/218)) ([9cf4d43](https://github.com/istanbuljs/istanbuljs/commit/9cf4d43)), closes [#205](https://github.com/istanbuljs/istanbuljs/issues/205)
+
+
+### Features
+
+* Add option plugins ([#205](https://github.com/istanbuljs/istanbuljs/issues/205)) ([312f81f](https://github.com/istanbuljs/istanbuljs/commit/312f81f))
+* Update babel to 7.0.0. ([#215](https://github.com/istanbuljs/istanbuljs/issues/215)) ([8a96613](https://github.com/istanbuljs/istanbuljs/commit/8a96613))
+
+
+### BREAKING CHANGES
+
+* was added which requires an option for the `decorators`
+plugin.  Add it to get tests working again, commit updated api.md.
+
+
+
+
+<a name="2.3.2"></a>
+## [2.3.2](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@2.3.1...istanbul-lib-instrument@2.3.2) (2018-07-24)
+
+
+
+
+**Note:** Version bump only for package istanbul-lib-instrument
+
+<a name="2.3.1"></a>
+## [2.3.1](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@2.3.0...istanbul-lib-instrument@2.3.1) (2018-07-07)
+
+
+### Bug Fixes
+
+* Don't ignore src/visitor.js for self test. ([#194](https://github.com/istanbuljs/istanbuljs/issues/194)) ([71b815d](https://github.com/istanbuljs/istanbuljs/commit/71b815d))
+
+
+
+
+<a name="2.3.0"></a>
+# [2.3.0](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@2.2.1...istanbul-lib-instrument@2.3.0) (2018-06-27)
+
+
+### Features
+
+* update pinned babel version to latest release. ([#189](https://github.com/istanbuljs/istanbuljs/issues/189)) ([ac8ec07](https://github.com/istanbuljs/istanbuljs/commit/ac8ec07))
+
+
+
+
+<a name="2.2.1"></a>
+## [2.2.1](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@2.2.0...istanbul-lib-instrument@2.2.1) (2018-06-26)
+
+
+### Bug Fixes
+
+* Instrument ObjectMethod's. ([#182](https://github.com/istanbuljs/istanbuljs/issues/182)) ([126f09d](https://github.com/istanbuljs/istanbuljs/commit/126f09d))
+* update default args test guard to work on supported versions. ([#185](https://github.com/istanbuljs/istanbuljs/issues/185)) ([955511a](https://github.com/istanbuljs/istanbuljs/commit/955511a))
+
+
+
+
+<a name="2.2.0"></a>
+# [2.2.0](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@2.0.2...istanbul-lib-instrument@2.2.0) (2018-06-06)
+
+
+### Features
+
+* add support for optional catch binding ([#175](https://github.com/istanbuljs/istanbuljs/issues/175)) ([088dd9f](https://github.com/istanbuljs/istanbuljs/commit/088dd9f))
+
+
+
+
+<a name="2.1.0"></a>
+# [2.1.0](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@2.0.2...istanbul-lib-instrument@2.1.0) (2018-05-31)
+
+
+### Features
+
+* add support for optional catch binding ([#175](https://github.com/istanbuljs/istanbuljs/issues/175)) ([088dd9f](https://github.com/istanbuljs/istanbuljs/commit/088dd9f))
+
+
+
+
+<a name="2.0.2"></a>
+## [2.0.2](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@2.0.1...istanbul-lib-instrument@2.0.2) (2018-05-31)
+
+
+
+
+**Note:** Version bump only for package istanbul-lib-instrument
+
+<a name="2.0.1"></a>
+## [2.0.1](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@2.0.0...istanbul-lib-instrument@2.0.1) (2018-05-31)
+
+
+### Bug Fixes
+
+* should import [@babel](https://github.com/babel)/template ([85a0d1a](https://github.com/istanbuljs/istanbuljs/commit/85a0d1a))
+
+
+
+
+<a name="2.0.0"></a>
+# [2.0.0](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@1.10.1...istanbul-lib-instrument@2.0.0) (2018-05-31)
+
+
+### Bug Fixes
+
+* parenthesize superClass on non-idetifier case ([#158](https://github.com/istanbuljs/istanbuljs/issues/158)) ([6202c88](https://github.com/istanbuljs/istanbuljs/commit/6202c88))
+
+
+### Chores
+
+* upgrade babel in instrumenter ([#174](https://github.com/istanbuljs/istanbuljs/issues/174)) ([ce23e91](https://github.com/istanbuljs/istanbuljs/commit/ce23e91))
+
+
+### BREAKING CHANGES
+
+* babel@7 drops Node@4 support
+
+
+
+
+<a name="1.10.1"></a>
+## [1.10.1](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@1.10.0...istanbul-lib-instrument@1.10.1) (2018-03-09)
+
+
+### Bug Fixes
+
+* default value for ignorelassMethods ([#151](https://github.com/istanbuljs/istanbuljs/issues/151)) ([5dd88e8](https://github.com/istanbuljs/istanbuljs/commit/5dd88e8))
+
+
+
+
+<a name="1.10.0"></a>
+# [1.10.0](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@1.9.2...istanbul-lib-instrument@1.10.0) (2018-03-04)
+
+
+### Features
+
+* allows an array of ignored method names to be provided ([#127](https://github.com/istanbuljs/istanbuljs/issues/127)) ([67918e2](https://github.com/istanbuljs/istanbuljs/commit/67918e2))
+
+
+
+
+<a name="1.9.2"></a>
+## [1.9.2](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@1.9.1...istanbul-lib-instrument@1.9.2) (2018-02-13)
+
+
+### Bug Fixes
+
+* compatibility with babel 7 ([#135](https://github.com/istanbuljs/istanbuljs/issues/135)) ([6cac849](https://github.com/istanbuljs/istanbuljs/commit/6cac849))
+* handle instrumentation when a function is called Function ([#131](https://github.com/istanbuljs/istanbuljs/issues/131)) ([b12a07e](https://github.com/istanbuljs/istanbuljs/commit/b12a07e))
+* proper passing of the preserveComments option to babel ([#122](https://github.com/istanbuljs/istanbuljs/issues/122)) ([470bb0e](https://github.com/istanbuljs/istanbuljs/commit/470bb0e))
+* update instrument, account for lack of arrow expression ([#119](https://github.com/istanbuljs/istanbuljs/issues/119)) ([#125](https://github.com/istanbuljs/istanbuljs/issues/125)) ([0968206](https://github.com/istanbuljs/istanbuljs/commit/0968206))
+
+
+
+
+<a name="1.9.1"></a>
+## [1.9.1](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@1.9.0...istanbul-lib-instrument@1.9.1) (2017-10-22)
+
+
+### Bug Fixes
+
+* address issue with class instrumentation ([#111](https://github.com/istanbuljs/istanbuljs/issues/111)) ([cbd1c14](https://github.com/istanbuljs/istanbuljs/commit/cbd1c14))
+
+
+
+
+<a name="1.9.0"></a>
+# [1.9.0](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@1.8.0...istanbul-lib-instrument@1.9.0) (2017-10-21)
+
+
+### Bug Fixes
+
+* support conditional expression for superClass ([#106](https://github.com/istanbuljs/istanbuljs/issues/106)) ([aae256f](https://github.com/istanbuljs/istanbuljs/commit/aae256f))
+
+
+### Features
+
+* add support for ignoring entire files ([#108](https://github.com/istanbuljs/istanbuljs/issues/108)) ([f12da65](https://github.com/istanbuljs/istanbuljs/commit/f12da65))
+
+
+
+
+<a name="1.8.0"></a>
+# [1.8.0](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@1.7.5...istanbul-lib-instrument@1.8.0) (2017-09-05)
+
+
+### Features
+
+* add support for object-spread syntax ([#82](https://github.com/istanbuljs/istanbuljs/issues/82)) ([28d5566](https://github.com/istanbuljs/istanbuljs/commit/28d5566))
+
+
+
+
+<a name="1.7.5"></a>
+## [1.7.5](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@1.7.4...istanbul-lib-instrument@1.7.5) (2017-08-23)
+
+
+### Bug Fixes
+
+* name of function is now preserved or named exports ([#79](https://github.com/istanbuljs/istanbuljs/issues/79)) ([2ce8974](https://github.com/istanbuljs/istanbuljs/commit/2ce8974))
+
+
+
+
+<a name="1.7.4"></a>
+## [1.7.4](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@1.7.3...istanbul-lib-instrument@1.7.4) (2017-07-16)
+
+
+### Bug Fixes
+
+* update increment operator to appropriate expression type ([#74](https://github.com/istanbuljs/istanbuljs/issues/74)) ([dc69e66](https://github.com/istanbuljs/istanbuljs/commit/dc69e66))
+
+
+
+
+<a name="1.7.3"></a>
+## [1.7.3](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@1.7.2...istanbul-lib-instrument@1.7.3) (2017-06-25)
+
+
+
+
+<a name="1.7.2"></a>
+## [1.7.2](https://github.com/istanbuljs/istanbuljs/compare/istanbul-lib-instrument@1.7.1...istanbul-lib-instrument@1.7.2) (2017-05-27)
+
+
+### Bug Fixes
+
+* hoist statement counter for class variables, so that name is preserved ([#60](https://github.com/istanbuljs/istanbuljs/issues/60)) ([120d221](https://github.com/istanbuljs/istanbuljs/commit/120d221))
+
+
+
+
+<a name="1.7.1"></a>
+## [1.7.1](https://github.com/istanbuljs/istanbul-lib-instrument/compare/istanbul-lib-instrument@1.7.0...istanbul-lib-instrument@1.7.1) (2017-04-29)
+
+
+### Bug Fixes
+
+* don't instrument a file if it has already been instrumented ([#38](https://github.com/istanbuljs/istanbuljs/issues/38)) ([9c38e4e](https://github.com/istanbuljs/istanbul-lib-instrument/commit/9c38e4e))
+
+
+
+
+<a name="1.7.0"></a>
+# [1.7.0](https://github.com/istanbuljs/istanbul-lib-instrument/compare/istanbul-lib-instrument@1.6.2...istanbul-lib-instrument@1.7.0) (2017-03-27)
+
+
+### Features
+
+* use extended babylon support; adding features such as jsx ([#22](https://github.com/istanbuljs/istanbuljs/issues/22)) ([11c2438](https://github.com/istanbuljs/istanbul-lib-instrument/commit/11c2438))
+
+<a name="1.6.2"></a>
+## [1.6.2](https://github.com/istanbuljs/istanbul-lib-instrument/compare/istanbul-lib-instrument@1.6.1...istanbul-lib-instrument@1.6.2) (2017-03-22)
+
+
+### Bug Fixes
+
+* loc is sometimes not defined, so loc.start fails see [#99](https://github.com/istanbuljs/istanbuljs/issues/99) ([#18](https://github.com/istanbuljs/istanbuljs/issues/18)) ([df85ba6](https://github.com/istanbuljs/istanbul-lib-instrument/commit/df85ba6))
+
+<a name="1.6.1"></a>
+## [1.6.1](https://github.com/istanbuljs/istanbul-lib-instrument/compare/istanbul-lib-instrument@1.6.0...istanbul-lib-instrument@1.6.1) (2017-03-21)
+
+<a name="1.6.0"></a>
+# [1.6.0](https://github.com/istanbuljs/istanbul-lib-instrument/compare/istanbul-lib-instrument@1.4.2...istanbul-lib-instrument@1.6.0) (2017-03-21)
+
+
+### Features
+
+* adds line number property back to coverage.json ([b03b927](https://github.com/istanbuljs/istanbul-lib-instrument/commit/b03b927))
+
+<a name="1.4.2"></a>
+## [1.4.2](https://github.com/istanbuljs/istanbul-lib-instrument/compare/v1.4.1...v1.4.2) (2017-01-04)
+
+
+### Bug Fixes
+
+* only hoist counter for a smaller subset of function declarations ([9f8931e](https://github.com/istanbuljs/istanbul-lib-instrument/commit/9f8931e))
+
+
+
+<a name="1.4.1"></a>
+## [1.4.1](https://github.com/istanbuljs/istanbul-lib-instrument/compare/v1.4.0...v1.4.1) (2017-01-04)
+
+
+### Bug Fixes
+
+* address regression discussed in https://github.com/istanbuljs/babel-plugin-istanbul/issues/78 ([#40](https://github.com/istanbuljs/istanbul-lib-instrument/issues/40)) ([7f458a3](https://github.com/istanbuljs/istanbul-lib-instrument/commit/7f458a3))
+
+
+
+<a name="1.4.0"></a>
+# [1.4.0](https://github.com/istanbuljs/istanbul-lib-instrument/compare/v1.3.1...v1.4.0) (2017-01-02)
+
+
+### Features
+
+* preserve inferred function names ([#38](https://github.com/istanbuljs/istanbul-lib-instrument/issues/38)) ([312666e](https://github.com/istanbuljs/istanbul-lib-instrument/commit/312666e))
+
+
+
+<a name="1.3.1"></a>
+## [1.3.1](https://github.com/istanbuljs/istanbul-lib-instrument/compare/v1.3.0...v1.3.1) (2016-12-27)
+
+
+### Bug Fixes
+
+* function declaration assignment now retains function name ([#33](https://github.com/istanbuljs/istanbul-lib-instrument/issues/33)) ([2d781da](https://github.com/istanbuljs/istanbul-lib-instrument/commit/2d781da))
+
+
+
+<a name="1.3.0"></a>
+# [1.3.0](https://github.com/istanbuljs/istanbul-lib-instrument/compare/v1.2.0...v1.3.0) (2016-11-10)
+
+
+### Features
+
+* allow an input source-map to be passed to instrumentSync()  ([#23](https://github.com/istanbuljs/istanbul-lib-instrument/issues/23)) ([b08e4f5](https://github.com/istanbuljs/istanbul-lib-instrument/commit/b08e4f5))
+
+
+
+<a name="1.2.0"></a>
+# [1.2.0](https://github.com/istanbuljs/istanbul-lib-instrument/compare/v1.1.4...v1.2.0) (2016-10-25)
+
+
+### Features
+
+* implement function to extract empty coverage data from an instrumented file ([#28](https://github.com/istanbuljs/istanbul-lib-instrument/issues/28)) ([06d0ef6](https://github.com/istanbuljs/istanbul-lib-instrument/commit/06d0ef6))
+
+
+
+<a name="1.1.4"></a>
+## [1.1.4](https://github.com/istanbuljs/istanbul-lib-instrument/compare/v1.1.3...v1.1.4) (2016-10-17)
+
+
+### Bug Fixes
+
+* hoist coverage variable to very top of file ([#26](https://github.com/istanbuljs/istanbul-lib-instrument/issues/26)) ([0225e8c](https://github.com/istanbuljs/istanbul-lib-instrument/commit/0225e8c))
+
+
+
+<a name="1.1.3"></a>
+## [1.1.3](https://github.com/istanbuljs/istanbul-lib-instrument/compare/v1.1.2...v1.1.3) (2016-09-13)
+
+
+### Performance Improvements
+
+* simplify coverage variable naming https://github.com/istanbuljs/istanbul-lib-instrument/pull/24 ([7252aae](https://github.com/istanbuljs/istanbul-lib-instrument/commit/7252aae))
+
+
+
+<a name="1.1.2"></a>
+## [1.1.2](https://github.com/istanbuljs/istanbul-lib-instrument/compare/v1.1.1...v1.1.2) (2016-09-08)
+
+
+### Performance Improvements
+
+* use zero-based numeric indices for much faster instrumented code ([#22](https://github.com/istanbuljs/istanbul-lib-instrument/issues/22)) ([5b401f5](https://github.com/istanbuljs/istanbul-lib-instrument/commit/5b401f5))
+
+
+
+<a name="1.1.1"></a>
+## [1.1.1](https://github.com/istanbuljs/istanbul-lib-instrument/compare/v1.1.0...v1.1.1) (2016-08-30)
+
+
+### Bug Fixes
+
+* upgrade istanbul-lib-coverage ([eb9b1f6](https://github.com/istanbuljs/istanbul-lib-instrument/commit/eb9b1f6))
+
+
+
+<a name="1.1.0"></a>
+# [1.1.0](https://github.com/istanbuljs/istanbul-lib-instrument/compare/v1.1.0-alpha.4...v1.1.0) (2016-08-11)
+
+
+### Bug Fixes
+
+* guard against invalid loc ([#16](https://github.com/istanbuljs/istanbul-lib-instrument/issues/16)) ([23ebfc3](https://github.com/istanbuljs/istanbul-lib-instrument/commit/23ebfc3))
+
+
+
+<a name="1.1.0-alpha.4"></a>
+# [1.1.0-alpha.4](https://github.com/istanbuljs/istanbul-lib-instrument/compare/v1.0.0-alpha.5...v1.1.0-alpha.4) (2016-07-20)
+
+
+### Bug Fixes
+
+* require more performant babel-generator ([#15](https://github.com/istanbuljs/istanbul-lib-instrument/issues/15)) ([21b2563](https://github.com/istanbuljs/istanbul-lib-instrument/commit/21b2563))
Index: frontend/node_modules/istanbul-lib-instrument/LICENSE
===================================================================
--- frontend/node_modules/istanbul-lib-instrument/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/istanbul-lib-instrument/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,24 @@
+Copyright 2012-2015 Yahoo! Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the Yahoo! Inc. nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL YAHOO! INC. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Index: frontend/node_modules/istanbul-lib-instrument/README.md
===================================================================
--- frontend/node_modules/istanbul-lib-instrument/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/istanbul-lib-instrument/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,22 @@
+## istanbul-lib-instrument
+
+[![Build Status](https://travis-ci.org/istanbuljs/istanbul-lib-instrument.svg?branch=master)](https://travis-ci.org/istanbuljs/istanbul-lib-instrument)
+
+Istanbul instrumenter library.
+
+Version 1.1.x now implements instrumentation using `Babel`. The implementation is inspired
+by prior art by @dtinth as demonstrated in the `__coverage__` babel plugin.
+
+It provides 2 "modes" of instrumentation.
+
+-   The old API that is mostly unchanged (except for incompatibilities noted) and
+    performs the instrumentation using babel as a library.
+
+-   A `programVisitor` function for the Babel AST that can be used by a Babel plugin
+    to emit instrumentation for ES6 code directly without any source map
+    processing. This is the preferred path for babel users. The Babel plugin is
+    called `babel-plugin-istanbul`.
+
+Incompatibilities and changes to instrumentation behavior can be found in
+[v0-changes.md](v0-changes.md).
+
Index: frontend/node_modules/istanbul-lib-instrument/node_modules/.bin/semver
===================================================================
--- frontend/node_modules/istanbul-lib-instrument/node_modules/.bin/semver	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/istanbul-lib-instrument/node_modules/.bin/semver	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,16 @@
+#!/bin/sh
+basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
+
+case `uname` in
+    *CYGWIN*|*MINGW*|*MSYS*)
+        if command -v cygpath > /dev/null 2>&1; then
+            basedir=`cygpath -w "$basedir"`
+        fi
+    ;;
+esac
+
+if [ -x "$basedir/node" ]; then
+  exec "$basedir/node"  "$basedir/../semver/bin/semver.js" "$@"
+else 
+  exec node  "$basedir/../semver/bin/semver.js" "$@"
+fi
Index: frontend/node_modules/istanbul-lib-instrument/node_modules/.bin/semver.cmd
===================================================================
--- frontend/node_modules/istanbul-lib-instrument/node_modules/.bin/semver.cmd	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/istanbul-lib-instrument/node_modules/.bin/semver.cmd	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,17 @@
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+  SET "_prog=%dp0%\node.exe"
+) ELSE (
+  SET "_prog=node"
+  SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%"  "%dp0%\..\semver\bin\semver.js" %*
Index: frontend/node_modules/istanbul-lib-instrument/node_modules/.bin/semver.ps1
===================================================================
--- frontend/node_modules/istanbul-lib-instrument/node_modules/.bin/semver.ps1	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/istanbul-lib-instrument/node_modules/.bin/semver.ps1	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,28 @@
+#!/usr/bin/env pwsh
+$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
+
+$exe=""
+if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
+  # Fix case when both the Windows and Linux builds of Node
+  # are installed in the same directory
+  $exe=".exe"
+}
+$ret=0
+if (Test-Path "$basedir/node$exe") {
+  # Support pipeline input
+  if ($MyInvocation.ExpectingInput) {
+    $input | & "$basedir/node$exe"  "$basedir/../semver/bin/semver.js" $args
+  } else {
+    & "$basedir/node$exe"  "$basedir/../semver/bin/semver.js" $args
+  }
+  $ret=$LASTEXITCODE
+} else {
+  # Support pipeline input
+  if ($MyInvocation.ExpectingInput) {
+    $input | & "node$exe"  "$basedir/../semver/bin/semver.js" $args
+  } else {
+    & "node$exe"  "$basedir/../semver/bin/semver.js" $args
+  }
+  $ret=$LASTEXITCODE
+}
+exit $ret
Index: frontend/node_modules/istanbul-lib-instrument/node_modules/semver/LICENSE
===================================================================
--- frontend/node_modules/istanbul-lib-instrument/node_modules/semver/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/istanbul-lib-instrument/node_modules/semver/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,15 @@
+The ISC License
+
+Copyright (c) Isaac Z. Schlueter and Contributors
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Index: frontend/node_modules/istanbul-lib-instrument/node_modules/semver/README.md
===================================================================
--- frontend/node_modules/istanbul-lib-instrument/node_modules/semver/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/istanbul-lib-instrument/node_modules/semver/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,443 @@
+semver(1) -- The semantic versioner for npm
+===========================================
+
+## Install
+
+```bash
+npm install semver
+````
+
+## Usage
+
+As a node module:
+
+```js
+const semver = require('semver')
+
+semver.valid('1.2.3') // '1.2.3'
+semver.valid('a.b.c') // null
+semver.clean('  =v1.2.3   ') // '1.2.3'
+semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') // true
+semver.gt('1.2.3', '9.8.7') // false
+semver.lt('1.2.3', '9.8.7') // true
+semver.minVersion('>=1.0.0') // '1.0.0'
+semver.valid(semver.coerce('v2')) // '2.0.0'
+semver.valid(semver.coerce('42.6.7.9.3-alpha')) // '42.6.7'
+```
+
+As a command-line utility:
+
+```
+$ semver -h
+
+A JavaScript implementation of the https://semver.org/ specification
+Copyright Isaac Z. Schlueter
+
+Usage: semver [options] <version> [<version> [...]]
+Prints valid versions sorted by SemVer precedence
+
+Options:
+-r --range <range>
+        Print versions that match the specified range.
+
+-i --increment [<level>]
+        Increment a version by the specified level.  Level can
+        be one of: major, minor, patch, premajor, preminor,
+        prepatch, or prerelease.  Default level is 'patch'.
+        Only one version may be specified.
+
+--preid <identifier>
+        Identifier to be used to prefix premajor, preminor,
+        prepatch or prerelease version increments.
+
+-l --loose
+        Interpret versions and ranges loosely
+
+-p --include-prerelease
+        Always include prerelease versions in range matching
+
+-c --coerce
+        Coerce a string into SemVer if possible
+        (does not imply --loose)
+
+--rtl
+        Coerce version strings right to left
+
+--ltr
+        Coerce version strings left to right (default)
+
+Program exits successfully if any valid version satisfies
+all supplied ranges, and prints all satisfying versions.
+
+If no satisfying versions are found, then exits failure.
+
+Versions are printed in ascending order, so supplying
+multiple versions to the utility will just sort them.
+```
+
+## Versions
+
+A "version" is described by the `v2.0.0` specification found at
+<https://semver.org/>.
+
+A leading `"="` or `"v"` character is stripped off and ignored.
+
+## Ranges
+
+A `version range` is a set of `comparators` which specify versions
+that satisfy the range.
+
+A `comparator` is composed of an `operator` and a `version`.  The set
+of primitive `operators` is:
+
+* `<` Less than
+* `<=` Less than or equal to
+* `>` Greater than
+* `>=` Greater than or equal to
+* `=` Equal.  If no operator is specified, then equality is assumed,
+  so this operator is optional, but MAY be included.
+
+For example, the comparator `>=1.2.7` would match the versions
+`1.2.7`, `1.2.8`, `2.5.3`, and `1.3.9`, but not the versions `1.2.6`
+or `1.1.0`.
+
+Comparators can be joined by whitespace to form a `comparator set`,
+which is satisfied by the **intersection** of all of the comparators
+it includes.
+
+A range is composed of one or more comparator sets, joined by `||`.  A
+version matches a range if and only if every comparator in at least
+one of the `||`-separated comparator sets is satisfied by the version.
+
+For example, the range `>=1.2.7 <1.3.0` would match the versions
+`1.2.7`, `1.2.8`, and `1.2.99`, but not the versions `1.2.6`, `1.3.0`,
+or `1.1.0`.
+
+The range `1.2.7 || >=1.2.9 <2.0.0` would match the versions `1.2.7`,
+`1.2.9`, and `1.4.6`, but not the versions `1.2.8` or `2.0.0`.
+
+### Prerelease Tags
+
+If a version has a prerelease tag (for example, `1.2.3-alpha.3`) then
+it will only be allowed to satisfy comparator sets if at least one
+comparator with the same `[major, minor, patch]` tuple also has a
+prerelease tag.
+
+For example, the range `>1.2.3-alpha.3` would be allowed to match the
+version `1.2.3-alpha.7`, but it would *not* be satisfied by
+`3.4.5-alpha.9`, even though `3.4.5-alpha.9` is technically "greater
+than" `1.2.3-alpha.3` according to the SemVer sort rules.  The version
+range only accepts prerelease tags on the `1.2.3` version.  The
+version `3.4.5` *would* satisfy the range, because it does not have a
+prerelease flag, and `3.4.5` is greater than `1.2.3-alpha.7`.
+
+The purpose for this behavior is twofold.  First, prerelease versions
+frequently are updated very quickly, and contain many breaking changes
+that are (by the author's design) not yet fit for public consumption.
+Therefore, by default, they are excluded from range matching
+semantics.
+
+Second, a user who has opted into using a prerelease version has
+clearly indicated the intent to use *that specific* set of
+alpha/beta/rc versions.  By including a prerelease tag in the range,
+the user is indicating that they are aware of the risk.  However, it
+is still not appropriate to assume that they have opted into taking a
+similar risk on the *next* set of prerelease versions.
+
+Note that this behavior can be suppressed (treating all prerelease
+versions as if they were normal versions, for the purpose of range
+matching) by setting the `includePrerelease` flag on the options
+object to any
+[functions](https://github.com/npm/node-semver#functions) that do
+range matching.
+
+#### Prerelease Identifiers
+
+The method `.inc` takes an additional `identifier` string argument that
+will append the value of the string as a prerelease identifier:
+
+```javascript
+semver.inc('1.2.3', 'prerelease', 'beta')
+// '1.2.4-beta.0'
+```
+
+command-line example:
+
+```bash
+$ semver 1.2.3 -i prerelease --preid beta
+1.2.4-beta.0
+```
+
+Which then can be used to increment further:
+
+```bash
+$ semver 1.2.4-beta.0 -i prerelease
+1.2.4-beta.1
+```
+
+### Advanced Range Syntax
+
+Advanced range syntax desugars to primitive comparators in
+deterministic ways.
+
+Advanced ranges may be combined in the same way as primitive
+comparators using white space or `||`.
+
+#### Hyphen Ranges `X.Y.Z - A.B.C`
+
+Specifies an inclusive set.
+
+* `1.2.3 - 2.3.4` := `>=1.2.3 <=2.3.4`
+
+If a partial version is provided as the first version in the inclusive
+range, then the missing pieces are replaced with zeroes.
+
+* `1.2 - 2.3.4` := `>=1.2.0 <=2.3.4`
+
+If a partial version is provided as the second version in the
+inclusive range, then all versions that start with the supplied parts
+of the tuple are accepted, but nothing that would be greater than the
+provided tuple parts.
+
+* `1.2.3 - 2.3` := `>=1.2.3 <2.4.0`
+* `1.2.3 - 2` := `>=1.2.3 <3.0.0`
+
+#### X-Ranges `1.2.x` `1.X` `1.2.*` `*`
+
+Any of `X`, `x`, or `*` may be used to "stand in" for one of the
+numeric values in the `[major, minor, patch]` tuple.
+
+* `*` := `>=0.0.0` (Any version satisfies)
+* `1.x` := `>=1.0.0 <2.0.0` (Matching major version)
+* `1.2.x` := `>=1.2.0 <1.3.0` (Matching major and minor versions)
+
+A partial version range is treated as an X-Range, so the special
+character is in fact optional.
+
+* `""` (empty string) := `*` := `>=0.0.0`
+* `1` := `1.x.x` := `>=1.0.0 <2.0.0`
+* `1.2` := `1.2.x` := `>=1.2.0 <1.3.0`
+
+#### Tilde Ranges `~1.2.3` `~1.2` `~1`
+
+Allows patch-level changes if a minor version is specified on the
+comparator.  Allows minor-level changes if not.
+
+* `~1.2.3` := `>=1.2.3 <1.(2+1).0` := `>=1.2.3 <1.3.0`
+* `~1.2` := `>=1.2.0 <1.(2+1).0` := `>=1.2.0 <1.3.0` (Same as `1.2.x`)
+* `~1` := `>=1.0.0 <(1+1).0.0` := `>=1.0.0 <2.0.0` (Same as `1.x`)
+* `~0.2.3` := `>=0.2.3 <0.(2+1).0` := `>=0.2.3 <0.3.0`
+* `~0.2` := `>=0.2.0 <0.(2+1).0` := `>=0.2.0 <0.3.0` (Same as `0.2.x`)
+* `~0` := `>=0.0.0 <(0+1).0.0` := `>=0.0.0 <1.0.0` (Same as `0.x`)
+* `~1.2.3-beta.2` := `>=1.2.3-beta.2 <1.3.0` Note that prereleases in
+  the `1.2.3` version will be allowed, if they are greater than or
+  equal to `beta.2`.  So, `1.2.3-beta.4` would be allowed, but
+  `1.2.4-beta.2` would not, because it is a prerelease of a
+  different `[major, minor, patch]` tuple.
+
+#### Caret Ranges `^1.2.3` `^0.2.5` `^0.0.4`
+
+Allows changes that do not modify the left-most non-zero element in the
+`[major, minor, patch]` tuple.  In other words, this allows patch and
+minor updates for versions `1.0.0` and above, patch updates for
+versions `0.X >=0.1.0`, and *no* updates for versions `0.0.X`.
+
+Many authors treat a `0.x` version as if the `x` were the major
+"breaking-change" indicator.
+
+Caret ranges are ideal when an author may make breaking changes
+between `0.2.4` and `0.3.0` releases, which is a common practice.
+However, it presumes that there will *not* be breaking changes between
+`0.2.4` and `0.2.5`.  It allows for changes that are presumed to be
+additive (but non-breaking), according to commonly observed practices.
+
+* `^1.2.3` := `>=1.2.3 <2.0.0`
+* `^0.2.3` := `>=0.2.3 <0.3.0`
+* `^0.0.3` := `>=0.0.3 <0.0.4`
+* `^1.2.3-beta.2` := `>=1.2.3-beta.2 <2.0.0` Note that prereleases in
+  the `1.2.3` version will be allowed, if they are greater than or
+  equal to `beta.2`.  So, `1.2.3-beta.4` would be allowed, but
+  `1.2.4-beta.2` would not, because it is a prerelease of a
+  different `[major, minor, patch]` tuple.
+* `^0.0.3-beta` := `>=0.0.3-beta <0.0.4`  Note that prereleases in the
+  `0.0.3` version *only* will be allowed, if they are greater than or
+  equal to `beta`.  So, `0.0.3-pr.2` would be allowed.
+
+When parsing caret ranges, a missing `patch` value desugars to the
+number `0`, but will allow flexibility within that value, even if the
+major and minor versions are both `0`.
+
+* `^1.2.x` := `>=1.2.0 <2.0.0`
+* `^0.0.x` := `>=0.0.0 <0.1.0`
+* `^0.0` := `>=0.0.0 <0.1.0`
+
+A missing `minor` and `patch` values will desugar to zero, but also
+allow flexibility within those values, even if the major version is
+zero.
+
+* `^1.x` := `>=1.0.0 <2.0.0`
+* `^0.x` := `>=0.0.0 <1.0.0`
+
+### Range Grammar
+
+Putting all this together, here is a Backus-Naur grammar for ranges,
+for the benefit of parser authors:
+
+```bnf
+range-set  ::= range ( logical-or range ) *
+logical-or ::= ( ' ' ) * '||' ( ' ' ) *
+range      ::= hyphen | simple ( ' ' simple ) * | ''
+hyphen     ::= partial ' - ' partial
+simple     ::= primitive | partial | tilde | caret
+primitive  ::= ( '<' | '>' | '>=' | '<=' | '=' ) partial
+partial    ::= xr ( '.' xr ( '.' xr qualifier ? )? )?
+xr         ::= 'x' | 'X' | '*' | nr
+nr         ::= '0' | ['1'-'9'] ( ['0'-'9'] ) *
+tilde      ::= '~' partial
+caret      ::= '^' partial
+qualifier  ::= ( '-' pre )? ( '+' build )?
+pre        ::= parts
+build      ::= parts
+parts      ::= part ( '.' part ) *
+part       ::= nr | [-0-9A-Za-z]+
+```
+
+## Functions
+
+All methods and classes take a final `options` object argument.  All
+options in this object are `false` by default.  The options supported
+are:
+
+- `loose`  Be more forgiving about not-quite-valid semver strings.
+  (Any resulting output will always be 100% strict compliant, of
+  course.)  For backwards compatibility reasons, if the `options`
+  argument is a boolean value instead of an object, it is interpreted
+  to be the `loose` param.
+- `includePrerelease`  Set to suppress the [default
+  behavior](https://github.com/npm/node-semver#prerelease-tags) of
+  excluding prerelease tagged versions from ranges unless they are
+  explicitly opted into.
+
+Strict-mode Comparators and Ranges will be strict about the SemVer
+strings that they parse.
+
+* `valid(v)`: Return the parsed version, or null if it's not valid.
+* `inc(v, release)`: Return the version incremented by the release
+  type (`major`,   `premajor`, `minor`, `preminor`, `patch`,
+  `prepatch`, or `prerelease`), or null if it's not valid
+  * `premajor` in one call will bump the version up to the next major
+    version and down to a prerelease of that major version.
+    `preminor`, and `prepatch` work the same way.
+  * If called from a non-prerelease version, the `prerelease` will work the
+    same as `prepatch`. It increments the patch version, then makes a
+    prerelease. If the input version is already a prerelease it simply
+    increments it.
+* `prerelease(v)`: Returns an array of prerelease components, or null
+  if none exist. Example: `prerelease('1.2.3-alpha.1') -> ['alpha', 1]`
+* `major(v)`: Return the major version number.
+* `minor(v)`: Return the minor version number.
+* `patch(v)`: Return the patch version number.
+* `intersects(r1, r2, loose)`: Return true if the two supplied ranges
+  or comparators intersect.
+* `parse(v)`: Attempt to parse a string as a semantic version, returning either
+  a `SemVer` object or `null`.
+
+### Comparison
+
+* `gt(v1, v2)`: `v1 > v2`
+* `gte(v1, v2)`: `v1 >= v2`
+* `lt(v1, v2)`: `v1 < v2`
+* `lte(v1, v2)`: `v1 <= v2`
+* `eq(v1, v2)`: `v1 == v2` This is true if they're logically equivalent,
+  even if they're not the exact same string.  You already know how to
+  compare strings.
+* `neq(v1, v2)`: `v1 != v2` The opposite of `eq`.
+* `cmp(v1, comparator, v2)`: Pass in a comparison string, and it'll call
+  the corresponding function above.  `"==="` and `"!=="` do simple
+  string comparison, but are included for completeness.  Throws if an
+  invalid comparison string is provided.
+* `compare(v1, v2)`: Return `0` if `v1 == v2`, or `1` if `v1` is greater, or `-1` if
+  `v2` is greater.  Sorts in ascending order if passed to `Array.sort()`.
+* `rcompare(v1, v2)`: The reverse of compare.  Sorts an array of versions
+  in descending order when passed to `Array.sort()`.
+* `compareBuild(v1, v2)`: The same as `compare` but considers `build` when two versions
+  are equal.  Sorts in ascending order if passed to `Array.sort()`.
+  `v2` is greater.  Sorts in ascending order if passed to `Array.sort()`.
+* `diff(v1, v2)`: Returns difference between two versions by the release type
+  (`major`, `premajor`, `minor`, `preminor`, `patch`, `prepatch`, or `prerelease`),
+  or null if the versions are the same.
+
+### Comparators
+
+* `intersects(comparator)`: Return true if the comparators intersect
+
+### Ranges
+
+* `validRange(range)`: Return the valid range or null if it's not valid
+* `satisfies(version, range)`: Return true if the version satisfies the
+  range.
+* `maxSatisfying(versions, range)`: Return the highest version in the list
+  that satisfies the range, or `null` if none of them do.
+* `minSatisfying(versions, range)`: Return the lowest version in the list
+  that satisfies the range, or `null` if none of them do.
+* `minVersion(range)`: Return the lowest version that can possibly match
+  the given range.
+* `gtr(version, range)`: Return `true` if version is greater than all the
+  versions possible in the range.
+* `ltr(version, range)`: Return `true` if version is less than all the
+  versions possible in the range.
+* `outside(version, range, hilo)`: Return true if the version is outside
+  the bounds of the range in either the high or low direction.  The
+  `hilo` argument must be either the string `'>'` or `'<'`.  (This is
+  the function called by `gtr` and `ltr`.)
+* `intersects(range)`: Return true if any of the ranges comparators intersect
+
+Note that, since ranges may be non-contiguous, a version might not be
+greater than a range, less than a range, *or* satisfy a range!  For
+example, the range `1.2 <1.2.9 || >2.0.0` would have a hole from `1.2.9`
+until `2.0.0`, so the version `1.2.10` would not be greater than the
+range (because `2.0.1` satisfies, which is higher), nor less than the
+range (since `1.2.8` satisfies, which is lower), and it also does not
+satisfy the range.
+
+If you want to know if a version satisfies or does not satisfy a
+range, use the `satisfies(version, range)` function.
+
+### Coercion
+
+* `coerce(version, options)`: Coerces a string to semver if possible
+
+This aims to provide a very forgiving translation of a non-semver string to
+semver. It looks for the first digit in a string, and consumes all
+remaining characters which satisfy at least a partial semver (e.g., `1`,
+`1.2`, `1.2.3`) up to the max permitted length (256 characters).  Longer
+versions are simply truncated (`4.6.3.9.2-alpha2` becomes `4.6.3`).  All
+surrounding text is simply ignored (`v3.4 replaces v3.3.1` becomes
+`3.4.0`).  Only text which lacks digits will fail coercion (`version one`
+is not valid).  The maximum  length for any semver component considered for
+coercion is 16 characters; longer components will be ignored
+(`10000000000000000.4.7.4` becomes `4.7.4`).  The maximum value for any
+semver component is `Integer.MAX_SAFE_INTEGER || (2**53 - 1)`; higher value
+components are invalid (`9999999999999999.4.7.4` is likely invalid).
+
+If the `options.rtl` flag is set, then `coerce` will return the right-most
+coercible tuple that does not share an ending index with a longer coercible
+tuple.  For example, `1.2.3.4` will return `2.3.4` in rtl mode, not
+`4.0.0`.  `1.2.3/4` will return `4.0.0`, because the `4` is not a part of
+any other overlapping SemVer tuple.
+
+### Clean
+
+* `clean(version)`: Clean a string to be a valid semver if possible
+
+This will return a cleaned and trimmed semver version. If the provided version is not valid a null will be returned. This does not work for ranges. 
+
+ex.
+* `s.clean(' = v 2.1.5foo')`: `null`
+* `s.clean(' = v 2.1.5foo', { loose: true })`: `'2.1.5-foo'`
+* `s.clean(' = v 2.1.5-foo')`: `null`
+* `s.clean(' = v 2.1.5-foo', { loose: true })`: `'2.1.5-foo'`
+* `s.clean('=v2.1.5')`: `'2.1.5'`
+* `s.clean('  =v2.1.5')`: `2.1.5`
+* `s.clean('      2.1.5   ')`: `'2.1.5'`
+* `s.clean('~1.0.0')`: `null`
Index: frontend/node_modules/istanbul-lib-instrument/node_modules/semver/bin/semver.js
===================================================================
--- frontend/node_modules/istanbul-lib-instrument/node_modules/semver/bin/semver.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/istanbul-lib-instrument/node_modules/semver/bin/semver.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,174 @@
+#!/usr/bin/env node
+// Standalone semver comparison program.
+// Exits successfully and prints matching version(s) if
+// any supplied version is valid and passes all tests.
+
+var argv = process.argv.slice(2)
+
+var versions = []
+
+var range = []
+
+var inc = null
+
+var version = require('../package.json').version
+
+var loose = false
+
+var includePrerelease = false
+
+var coerce = false
+
+var rtl = false
+
+var identifier
+
+var semver = require('../semver')
+
+var reverse = false
+
+var options = {}
+
+main()
+
+function main () {
+  if (!argv.length) return help()
+  while (argv.length) {
+    var a = argv.shift()
+    var indexOfEqualSign = a.indexOf('=')
+    if (indexOfEqualSign !== -1) {
+      a = a.slice(0, indexOfEqualSign)
+      argv.unshift(a.slice(indexOfEqualSign + 1))
+    }
+    switch (a) {
+      case '-rv': case '-rev': case '--rev': case '--reverse':
+        reverse = true
+        break
+      case '-l': case '--loose':
+        loose = true
+        break
+      case '-p': case '--include-prerelease':
+        includePrerelease = true
+        break
+      case '-v': case '--version':
+        versions.push(argv.shift())
+        break
+      case '-i': case '--inc': case '--increment':
+        switch (argv[0]) {
+          case 'major': case 'minor': case 'patch': case 'prerelease':
+          case 'premajor': case 'preminor': case 'prepatch':
+            inc = argv.shift()
+            break
+          default:
+            inc = 'patch'
+            break
+        }
+        break
+      case '--preid':
+        identifier = argv.shift()
+        break
+      case '-r': case '--range':
+        range.push(argv.shift())
+        break
+      case '-c': case '--coerce':
+        coerce = true
+        break
+      case '--rtl':
+        rtl = true
+        break
+      case '--ltr':
+        rtl = false
+        break
+      case '-h': case '--help': case '-?':
+        return help()
+      default:
+        versions.push(a)
+        break
+    }
+  }
+
+  var options = { loose: loose, includePrerelease: includePrerelease, rtl: rtl }
+
+  versions = versions.map(function (v) {
+    return coerce ? (semver.coerce(v, options) || { version: v }).version : v
+  }).filter(function (v) {
+    return semver.valid(v)
+  })
+  if (!versions.length) return fail()
+  if (inc && (versions.length !== 1 || range.length)) { return failInc() }
+
+  for (var i = 0, l = range.length; i < l; i++) {
+    versions = versions.filter(function (v) {
+      return semver.satisfies(v, range[i], options)
+    })
+    if (!versions.length) return fail()
+  }
+  return success(versions)
+}
+
+function failInc () {
+  console.error('--inc can only be used on a single version with no range')
+  fail()
+}
+
+function fail () { process.exit(1) }
+
+function success () {
+  var compare = reverse ? 'rcompare' : 'compare'
+  versions.sort(function (a, b) {
+    return semver[compare](a, b, options)
+  }).map(function (v) {
+    return semver.clean(v, options)
+  }).map(function (v) {
+    return inc ? semver.inc(v, inc, options, identifier) : v
+  }).forEach(function (v, i, _) { console.log(v) })
+}
+
+function help () {
+  console.log(['SemVer ' + version,
+    '',
+    'A JavaScript implementation of the https://semver.org/ specification',
+    'Copyright Isaac Z. Schlueter',
+    '',
+    'Usage: semver [options] <version> [<version> [...]]',
+    'Prints valid versions sorted by SemVer precedence',
+    '',
+    'Options:',
+    '-r --range <range>',
+    '        Print versions that match the specified range.',
+    '',
+    '-i --increment [<level>]',
+    '        Increment a version by the specified level.  Level can',
+    '        be one of: major, minor, patch, premajor, preminor,',
+    "        prepatch, or prerelease.  Default level is 'patch'.",
+    '        Only one version may be specified.',
+    '',
+    '--preid <identifier>',
+    '        Identifier to be used to prefix premajor, preminor,',
+    '        prepatch or prerelease version increments.',
+    '',
+    '-l --loose',
+    '        Interpret versions and ranges loosely',
+    '',
+    '-p --include-prerelease',
+    '        Always include prerelease versions in range matching',
+    '',
+    '-c --coerce',
+    '        Coerce a string into SemVer if possible',
+    '        (does not imply --loose)',
+    '',
+    '--rtl',
+    '        Coerce version strings right to left',
+    '',
+    '--ltr',
+    '        Coerce version strings left to right (default)',
+    '',
+    'Program exits successfully if any valid version satisfies',
+    'all supplied ranges, and prints all satisfying versions.',
+    '',
+    'If no satisfying versions are found, then exits failure.',
+    '',
+    'Versions are printed in ascending order, so supplying',
+    'multiple versions to the utility will just sort them.'
+  ].join('\n'))
+}
Index: frontend/node_modules/istanbul-lib-instrument/node_modules/semver/package.json
===================================================================
--- frontend/node_modules/istanbul-lib-instrument/node_modules/semver/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/istanbul-lib-instrument/node_modules/semver/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,38 @@
+{
+  "name": "semver",
+  "version": "6.3.1",
+  "description": "The semantic version parser used by npm.",
+  "main": "semver.js",
+  "scripts": {
+    "test": "tap test/ --100 --timeout=30",
+    "lint": "echo linting disabled",
+    "postlint": "template-oss-check",
+    "template-oss-apply": "template-oss-apply --force",
+    "lintfix": "npm run lint -- --fix",
+    "snap": "tap test/ --100 --timeout=30",
+    "posttest": "npm run lint"
+  },
+  "devDependencies": {
+    "@npmcli/template-oss": "4.17.0",
+    "tap": "^12.7.0"
+  },
+  "license": "ISC",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/npm/node-semver.git"
+  },
+  "bin": {
+    "semver": "./bin/semver.js"
+  },
+  "files": [
+    "bin",
+    "range.bnf",
+    "semver.js"
+  ],
+  "author": "GitHub Inc.",
+  "templateOSS": {
+    "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
+    "content": "./scripts/template-oss",
+    "version": "4.17.0"
+  }
+}
Index: frontend/node_modules/istanbul-lib-instrument/node_modules/semver/range.bnf
===================================================================
--- frontend/node_modules/istanbul-lib-instrument/node_modules/semver/range.bnf	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/istanbul-lib-instrument/node_modules/semver/range.bnf	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,16 @@
+range-set  ::= range ( logical-or range ) *
+logical-or ::= ( ' ' ) * '||' ( ' ' ) *
+range      ::= hyphen | simple ( ' ' simple ) * | ''
+hyphen     ::= partial ' - ' partial
+simple     ::= primitive | partial | tilde | caret
+primitive  ::= ( '<' | '>' | '>=' | '<=' | '=' ) partial
+partial    ::= xr ( '.' xr ( '.' xr qualifier ? )? )?
+xr         ::= 'x' | 'X' | '*' | nr
+nr         ::= '0' | [1-9] ( [0-9] ) *
+tilde      ::= '~' partial
+caret      ::= '^' partial
+qualifier  ::= ( '-' pre )? ( '+' build )?
+pre        ::= parts
+build      ::= parts
+parts      ::= part ( '.' part ) *
+part       ::= nr | [-0-9A-Za-z]+
Index: frontend/node_modules/istanbul-lib-instrument/node_modules/semver/semver.js
===================================================================
--- frontend/node_modules/istanbul-lib-instrument/node_modules/semver/semver.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/istanbul-lib-instrument/node_modules/semver/semver.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,1643 @@
+exports = module.exports = SemVer
+
+var debug
+/* istanbul ignore next */
+if (typeof process === 'object' &&
+    process.env &&
+    process.env.NODE_DEBUG &&
+    /\bsemver\b/i.test(process.env.NODE_DEBUG)) {
+  debug = function () {
+    var args = Array.prototype.slice.call(arguments, 0)
+    args.unshift('SEMVER')
+    console.log.apply(console, args)
+  }
+} else {
+  debug = function () {}
+}
+
+// Note: this is the semver.org version of the spec that it implements
+// Not necessarily the package version of this code.
+exports.SEMVER_SPEC_VERSION = '2.0.0'
+
+var MAX_LENGTH = 256
+var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER ||
+  /* istanbul ignore next */ 9007199254740991
+
+// Max safe segment length for coercion.
+var MAX_SAFE_COMPONENT_LENGTH = 16
+
+var MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6
+
+// The actual regexps go on exports.re
+var re = exports.re = []
+var safeRe = exports.safeRe = []
+var src = exports.src = []
+var t = exports.tokens = {}
+var R = 0
+
+function tok (n) {
+  t[n] = R++
+}
+
+var LETTERDASHNUMBER = '[a-zA-Z0-9-]'
+
+// Replace some greedy regex tokens to prevent regex dos issues. These regex are
+// used internally via the safeRe object since all inputs in this library get
+// normalized first to trim and collapse all extra whitespace. The original
+// regexes are exported for userland consumption and lower level usage. A
+// future breaking change could export the safer regex only with a note that
+// all input should have extra whitespace removed.
+var safeRegexReplacements = [
+  ['\\s', 1],
+  ['\\d', MAX_LENGTH],
+  [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH],
+]
+
+function makeSafeRe (value) {
+  for (var i = 0; i < safeRegexReplacements.length; i++) {
+    var token = safeRegexReplacements[i][0]
+    var max = safeRegexReplacements[i][1]
+    value = value
+      .split(token + '*').join(token + '{0,' + max + '}')
+      .split(token + '+').join(token + '{1,' + max + '}')
+  }
+  return value
+}
+
+// The following Regular Expressions can be used for tokenizing,
+// validating, and parsing SemVer version strings.
+
+// ## Numeric Identifier
+// A single `0`, or a non-zero digit followed by zero or more digits.
+
+tok('NUMERICIDENTIFIER')
+src[t.NUMERICIDENTIFIER] = '0|[1-9]\\d*'
+tok('NUMERICIDENTIFIERLOOSE')
+src[t.NUMERICIDENTIFIERLOOSE] = '\\d+'
+
+// ## Non-numeric Identifier
+// Zero or more digits, followed by a letter or hyphen, and then zero or
+// more letters, digits, or hyphens.
+
+tok('NONNUMERICIDENTIFIER')
+src[t.NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-]' + LETTERDASHNUMBER + '*'
+
+// ## Main Version
+// Three dot-separated numeric identifiers.
+
+tok('MAINVERSION')
+src[t.MAINVERSION] = '(' + src[t.NUMERICIDENTIFIER] + ')\\.' +
+                   '(' + src[t.NUMERICIDENTIFIER] + ')\\.' +
+                   '(' + src[t.NUMERICIDENTIFIER] + ')'
+
+tok('MAINVERSIONLOOSE')
+src[t.MAINVERSIONLOOSE] = '(' + src[t.NUMERICIDENTIFIERLOOSE] + ')\\.' +
+                        '(' + src[t.NUMERICIDENTIFIERLOOSE] + ')\\.' +
+                        '(' + src[t.NUMERICIDENTIFIERLOOSE] + ')'
+
+// ## Pre-release Version Identifier
+// A numeric identifier, or a non-numeric identifier.
+
+tok('PRERELEASEIDENTIFIER')
+src[t.PRERELEASEIDENTIFIER] = '(?:' + src[t.NUMERICIDENTIFIER] +
+                            '|' + src[t.NONNUMERICIDENTIFIER] + ')'
+
+tok('PRERELEASEIDENTIFIERLOOSE')
+src[t.PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[t.NUMERICIDENTIFIERLOOSE] +
+                                 '|' + src[t.NONNUMERICIDENTIFIER] + ')'
+
+// ## Pre-release Version
+// Hyphen, followed by one or more dot-separated pre-release version
+// identifiers.
+
+tok('PRERELEASE')
+src[t.PRERELEASE] = '(?:-(' + src[t.PRERELEASEIDENTIFIER] +
+                  '(?:\\.' + src[t.PRERELEASEIDENTIFIER] + ')*))'
+
+tok('PRERELEASELOOSE')
+src[t.PRERELEASELOOSE] = '(?:-?(' + src[t.PRERELEASEIDENTIFIERLOOSE] +
+                       '(?:\\.' + src[t.PRERELEASEIDENTIFIERLOOSE] + ')*))'
+
+// ## Build Metadata Identifier
+// Any combination of digits, letters, or hyphens.
+
+tok('BUILDIDENTIFIER')
+src[t.BUILDIDENTIFIER] = LETTERDASHNUMBER + '+'
+
+// ## Build Metadata
+// Plus sign, followed by one or more period-separated build metadata
+// identifiers.
+
+tok('BUILD')
+src[t.BUILD] = '(?:\\+(' + src[t.BUILDIDENTIFIER] +
+             '(?:\\.' + src[t.BUILDIDENTIFIER] + ')*))'
+
+// ## Full Version String
+// A main version, followed optionally by a pre-release version and
+// build metadata.
+
+// Note that the only major, minor, patch, and pre-release sections of
+// the version string are capturing groups.  The build metadata is not a
+// capturing group, because it should not ever be used in version
+// comparison.
+
+tok('FULL')
+tok('FULLPLAIN')
+src[t.FULLPLAIN] = 'v?' + src[t.MAINVERSION] +
+                  src[t.PRERELEASE] + '?' +
+                  src[t.BUILD] + '?'
+
+src[t.FULL] = '^' + src[t.FULLPLAIN] + '$'
+
+// like full, but allows v1.2.3 and =1.2.3, which people do sometimes.
+// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty
+// common in the npm registry.
+tok('LOOSEPLAIN')
+src[t.LOOSEPLAIN] = '[v=\\s]*' + src[t.MAINVERSIONLOOSE] +
+                  src[t.PRERELEASELOOSE] + '?' +
+                  src[t.BUILD] + '?'
+
+tok('LOOSE')
+src[t.LOOSE] = '^' + src[t.LOOSEPLAIN] + '$'
+
+tok('GTLT')
+src[t.GTLT] = '((?:<|>)?=?)'
+
+// Something like "2.*" or "1.2.x".
+// Note that "x.x" is a valid xRange identifer, meaning "any version"
+// Only the first item is strictly required.
+tok('XRANGEIDENTIFIERLOOSE')
+src[t.XRANGEIDENTIFIERLOOSE] = src[t.NUMERICIDENTIFIERLOOSE] + '|x|X|\\*'
+tok('XRANGEIDENTIFIER')
+src[t.XRANGEIDENTIFIER] = src[t.NUMERICIDENTIFIER] + '|x|X|\\*'
+
+tok('XRANGEPLAIN')
+src[t.XRANGEPLAIN] = '[v=\\s]*(' + src[t.XRANGEIDENTIFIER] + ')' +
+                   '(?:\\.(' + src[t.XRANGEIDENTIFIER] + ')' +
+                   '(?:\\.(' + src[t.XRANGEIDENTIFIER] + ')' +
+                   '(?:' + src[t.PRERELEASE] + ')?' +
+                   src[t.BUILD] + '?' +
+                   ')?)?'
+
+tok('XRANGEPLAINLOOSE')
+src[t.XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[t.XRANGEIDENTIFIERLOOSE] + ')' +
+                        '(?:\\.(' + src[t.XRANGEIDENTIFIERLOOSE] + ')' +
+                        '(?:\\.(' + src[t.XRANGEIDENTIFIERLOOSE] + ')' +
+                        '(?:' + src[t.PRERELEASELOOSE] + ')?' +
+                        src[t.BUILD] + '?' +
+                        ')?)?'
+
+tok('XRANGE')
+src[t.XRANGE] = '^' + src[t.GTLT] + '\\s*' + src[t.XRANGEPLAIN] + '$'
+tok('XRANGELOOSE')
+src[t.XRANGELOOSE] = '^' + src[t.GTLT] + '\\s*' + src[t.XRANGEPLAINLOOSE] + '$'
+
+// Coercion.
+// Extract anything that could conceivably be a part of a valid semver
+tok('COERCE')
+src[t.COERCE] = '(^|[^\\d])' +
+              '(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '})' +
+              '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' +
+              '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' +
+              '(?:$|[^\\d])'
+tok('COERCERTL')
+re[t.COERCERTL] = new RegExp(src[t.COERCE], 'g')
+safeRe[t.COERCERTL] = new RegExp(makeSafeRe(src[t.COERCE]), 'g')
+
+// Tilde ranges.
+// Meaning is "reasonably at or greater than"
+tok('LONETILDE')
+src[t.LONETILDE] = '(?:~>?)'
+
+tok('TILDETRIM')
+src[t.TILDETRIM] = '(\\s*)' + src[t.LONETILDE] + '\\s+'
+re[t.TILDETRIM] = new RegExp(src[t.TILDETRIM], 'g')
+safeRe[t.TILDETRIM] = new RegExp(makeSafeRe(src[t.TILDETRIM]), 'g')
+var tildeTrimReplace = '$1~'
+
+tok('TILDE')
+src[t.TILDE] = '^' + src[t.LONETILDE] + src[t.XRANGEPLAIN] + '$'
+tok('TILDELOOSE')
+src[t.TILDELOOSE] = '^' + src[t.LONETILDE] + src[t.XRANGEPLAINLOOSE] + '$'
+
+// Caret ranges.
+// Meaning is "at least and backwards compatible with"
+tok('LONECARET')
+src[t.LONECARET] = '(?:\\^)'
+
+tok('CARETTRIM')
+src[t.CARETTRIM] = '(\\s*)' + src[t.LONECARET] + '\\s+'
+re[t.CARETTRIM] = new RegExp(src[t.CARETTRIM], 'g')
+safeRe[t.CARETTRIM] = new RegExp(makeSafeRe(src[t.CARETTRIM]), 'g')
+var caretTrimReplace = '$1^'
+
+tok('CARET')
+src[t.CARET] = '^' + src[t.LONECARET] + src[t.XRANGEPLAIN] + '$'
+tok('CARETLOOSE')
+src[t.CARETLOOSE] = '^' + src[t.LONECARET] + src[t.XRANGEPLAINLOOSE] + '$'
+
+// A simple gt/lt/eq thing, or just "" to indicate "any version"
+tok('COMPARATORLOOSE')
+src[t.COMPARATORLOOSE] = '^' + src[t.GTLT] + '\\s*(' + src[t.LOOSEPLAIN] + ')$|^$'
+tok('COMPARATOR')
+src[t.COMPARATOR] = '^' + src[t.GTLT] + '\\s*(' + src[t.FULLPLAIN] + ')$|^$'
+
+// An expression to strip any whitespace between the gtlt and the thing
+// it modifies, so that `> 1.2.3` ==> `>1.2.3`
+tok('COMPARATORTRIM')
+src[t.COMPARATORTRIM] = '(\\s*)' + src[t.GTLT] +
+                      '\\s*(' + src[t.LOOSEPLAIN] + '|' + src[t.XRANGEPLAIN] + ')'
+
+// this one has to use the /g flag
+re[t.COMPARATORTRIM] = new RegExp(src[t.COMPARATORTRIM], 'g')
+safeRe[t.COMPARATORTRIM] = new RegExp(makeSafeRe(src[t.COMPARATORTRIM]), 'g')
+var comparatorTrimReplace = '$1$2$3'
+
+// Something like `1.2.3 - 1.2.4`
+// Note that these all use the loose form, because they'll be
+// checked against either the strict or loose comparator form
+// later.
+tok('HYPHENRANGE')
+src[t.HYPHENRANGE] = '^\\s*(' + src[t.XRANGEPLAIN] + ')' +
+                   '\\s+-\\s+' +
+                   '(' + src[t.XRANGEPLAIN] + ')' +
+                   '\\s*$'
+
+tok('HYPHENRANGELOOSE')
+src[t.HYPHENRANGELOOSE] = '^\\s*(' + src[t.XRANGEPLAINLOOSE] + ')' +
+                        '\\s+-\\s+' +
+                        '(' + src[t.XRANGEPLAINLOOSE] + ')' +
+                        '\\s*$'
+
+// Star ranges basically just allow anything at all.
+tok('STAR')
+src[t.STAR] = '(<|>)?=?\\s*\\*'
+
+// Compile to actual regexp objects.
+// All are flag-free, unless they were created above with a flag.
+for (var i = 0; i < R; i++) {
+  debug(i, src[i])
+  if (!re[i]) {
+    re[i] = new RegExp(src[i])
+
+    // Replace all greedy whitespace to prevent regex dos issues. These regex are
+    // used internally via the safeRe object since all inputs in this library get
+    // normalized first to trim and collapse all extra whitespace. The original
+    // regexes are exported for userland consumption and lower level usage. A
+    // future breaking change could export the safer regex only with a note that
+    // all input should have extra whitespace removed.
+    safeRe[i] = new RegExp(makeSafeRe(src[i]))
+  }
+}
+
+exports.parse = parse
+function parse (version, options) {
+  if (!options || typeof options !== 'object') {
+    options = {
+      loose: !!options,
+      includePrerelease: false
+    }
+  }
+
+  if (version instanceof SemVer) {
+    return version
+  }
+
+  if (typeof version !== 'string') {
+    return null
+  }
+
+  if (version.length > MAX_LENGTH) {
+    return null
+  }
+
+  var r = options.loose ? safeRe[t.LOOSE] : safeRe[t.FULL]
+  if (!r.test(version)) {
+    return null
+  }
+
+  try {
+    return new SemVer(version, options)
+  } catch (er) {
+    return null
+  }
+}
+
+exports.valid = valid
+function valid (version, options) {
+  var v = parse(version, options)
+  return v ? v.version : null
+}
+
+exports.clean = clean
+function clean (version, options) {
+  var s = parse(version.trim().replace(/^[=v]+/, ''), options)
+  return s ? s.version : null
+}
+
+exports.SemVer = SemVer
+
+function SemVer (version, options) {
+  if (!options || typeof options !== 'object') {
+    options = {
+      loose: !!options,
+      includePrerelease: false
+    }
+  }
+  if (version instanceof SemVer) {
+    if (version.loose === options.loose) {
+      return version
+    } else {
+      version = version.version
+    }
+  } else if (typeof version !== 'string') {
+    throw new TypeError('Invalid Version: ' + version)
+  }
+
+  if (version.length > MAX_LENGTH) {
+    throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters')
+  }
+
+  if (!(this instanceof SemVer)) {
+    return new SemVer(version, options)
+  }
+
+  debug('SemVer', version, options)
+  this.options = options
+  this.loose = !!options.loose
+
+  var m = version.trim().match(options.loose ? safeRe[t.LOOSE] : safeRe[t.FULL])
+
+  if (!m) {
+    throw new TypeError('Invalid Version: ' + version)
+  }
+
+  this.raw = version
+
+  // these are actually numbers
+  this.major = +m[1]
+  this.minor = +m[2]
+  this.patch = +m[3]
+
+  if (this.major > MAX_SAFE_INTEGER || this.major < 0) {
+    throw new TypeError('Invalid major version')
+  }
+
+  if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) {
+    throw new TypeError('Invalid minor version')
+  }
+
+  if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) {
+    throw new TypeError('Invalid patch version')
+  }
+
+  // numberify any prerelease numeric ids
+  if (!m[4]) {
+    this.prerelease = []
+  } else {
+    this.prerelease = m[4].split('.').map(function (id) {
+      if (/^[0-9]+$/.test(id)) {
+        var num = +id
+        if (num >= 0 && num < MAX_SAFE_INTEGER) {
+          return num
+        }
+      }
+      return id
+    })
+  }
+
+  this.build = m[5] ? m[5].split('.') : []
+  this.format()
+}
+
+SemVer.prototype.format = function () {
+  this.version = this.major + '.' + this.minor + '.' + this.patch
+  if (this.prerelease.length) {
+    this.version += '-' + this.prerelease.join('.')
+  }
+  return this.version
+}
+
+SemVer.prototype.toString = function () {
+  return this.version
+}
+
+SemVer.prototype.compare = function (other) {
+  debug('SemVer.compare', this.version, this.options, other)
+  if (!(other instanceof SemVer)) {
+    other = new SemVer(other, this.options)
+  }
+
+  return this.compareMain(other) || this.comparePre(other)
+}
+
+SemVer.prototype.compareMain = function (other) {
+  if (!(other instanceof SemVer)) {
+    other = new SemVer(other, this.options)
+  }
+
+  return compareIdentifiers(this.major, other.major) ||
+         compareIdentifiers(this.minor, other.minor) ||
+         compareIdentifiers(this.patch, other.patch)
+}
+
+SemVer.prototype.comparePre = function (other) {
+  if (!(other instanceof SemVer)) {
+    other = new SemVer(other, this.options)
+  }
+
+  // NOT having a prerelease is > having one
+  if (this.prerelease.length && !other.prerelease.length) {
+    return -1
+  } else if (!this.prerelease.length && other.prerelease.length) {
+    return 1
+  } else if (!this.prerelease.length && !other.prerelease.length) {
+    return 0
+  }
+
+  var i = 0
+  do {
+    var a = this.prerelease[i]
+    var b = other.prerelease[i]
+    debug('prerelease compare', i, a, b)
+    if (a === undefined && b === undefined) {
+      return 0
+    } else if (b === undefined) {
+      return 1
+    } else if (a === undefined) {
+      return -1
+    } else if (a === b) {
+      continue
+    } else {
+      return compareIdentifiers(a, b)
+    }
+  } while (++i)
+}
+
+SemVer.prototype.compareBuild = function (other) {
+  if (!(other instanceof SemVer)) {
+    other = new SemVer(other, this.options)
+  }
+
+  var i = 0
+  do {
+    var a = this.build[i]
+    var b = other.build[i]
+    debug('prerelease compare', i, a, b)
+    if (a === undefined && b === undefined) {
+      return 0
+    } else if (b === undefined) {
+      return 1
+    } else if (a === undefined) {
+      return -1
+    } else if (a === b) {
+      continue
+    } else {
+      return compareIdentifiers(a, b)
+    }
+  } while (++i)
+}
+
+// preminor will bump the version up to the next minor release, and immediately
+// down to pre-release. premajor and prepatch work the same way.
+SemVer.prototype.inc = function (release, identifier) {
+  switch (release) {
+    case 'premajor':
+      this.prerelease.length = 0
+      this.patch = 0
+      this.minor = 0
+      this.major++
+      this.inc('pre', identifier)
+      break
+    case 'preminor':
+      this.prerelease.length = 0
+      this.patch = 0
+      this.minor++
+      this.inc('pre', identifier)
+      break
+    case 'prepatch':
+      // If this is already a prerelease, it will bump to the next version
+      // drop any prereleases that might already exist, since they are not
+      // relevant at this point.
+      this.prerelease.length = 0
+      this.inc('patch', identifier)
+      this.inc('pre', identifier)
+      break
+    // If the input is a non-prerelease version, this acts the same as
+    // prepatch.
+    case 'prerelease':
+      if (this.prerelease.length === 0) {
+        this.inc('patch', identifier)
+      }
+      this.inc('pre', identifier)
+      break
+
+    case 'major':
+      // If this is a pre-major version, bump up to the same major version.
+      // Otherwise increment major.
+      // 1.0.0-5 bumps to 1.0.0
+      // 1.1.0 bumps to 2.0.0
+      if (this.minor !== 0 ||
+          this.patch !== 0 ||
+          this.prerelease.length === 0) {
+        this.major++
+      }
+      this.minor = 0
+      this.patch = 0
+      this.prerelease = []
+      break
+    case 'minor':
+      // If this is a pre-minor version, bump up to the same minor version.
+      // Otherwise increment minor.
+      // 1.2.0-5 bumps to 1.2.0
+      // 1.2.1 bumps to 1.3.0
+      if (this.patch !== 0 || this.prerelease.length === 0) {
+        this.minor++
+      }
+      this.patch = 0
+      this.prerelease = []
+      break
+    case 'patch':
+      // If this is not a pre-release version, it will increment the patch.
+      // If it is a pre-release it will bump up to the same patch version.
+      // 1.2.0-5 patches to 1.2.0
+      // 1.2.0 patches to 1.2.1
+      if (this.prerelease.length === 0) {
+        this.patch++
+      }
+      this.prerelease = []
+      break
+    // This probably shouldn't be used publicly.
+    // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction.
+    case 'pre':
+      if (this.prerelease.length === 0) {
+        this.prerelease = [0]
+      } else {
+        var i = this.prerelease.length
+        while (--i >= 0) {
+          if (typeof this.prerelease[i] === 'number') {
+            this.prerelease[i]++
+            i = -2
+          }
+        }
+        if (i === -1) {
+          // didn't increment anything
+          this.prerelease.push(0)
+        }
+      }
+      if (identifier) {
+        // 1.2.0-beta.1 bumps to 1.2.0-beta.2,
+        // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0
+        if (this.prerelease[0] === identifier) {
+          if (isNaN(this.prerelease[1])) {
+            this.prerelease = [identifier, 0]
+          }
+        } else {
+          this.prerelease = [identifier, 0]
+        }
+      }
+      break
+
+    default:
+      throw new Error('invalid increment argument: ' + release)
+  }
+  this.format()
+  this.raw = this.version
+  return this
+}
+
+exports.inc = inc
+function inc (version, release, loose, identifier) {
+  if (typeof (loose) === 'string') {
+    identifier = loose
+    loose = undefined
+  }
+
+  try {
+    return new SemVer(version, loose).inc(release, identifier).version
+  } catch (er) {
+    return null
+  }
+}
+
+exports.diff = diff
+function diff (version1, version2) {
+  if (eq(version1, version2)) {
+    return null
+  } else {
+    var v1 = parse(version1)
+    var v2 = parse(version2)
+    var prefix = ''
+    if (v1.prerelease.length || v2.prerelease.length) {
+      prefix = 'pre'
+      var defaultResult = 'prerelease'
+    }
+    for (var key in v1) {
+      if (key === 'major' || key === 'minor' || key === 'patch') {
+        if (v1[key] !== v2[key]) {
+          return prefix + key
+        }
+      }
+    }
+    return defaultResult // may be undefined
+  }
+}
+
+exports.compareIdentifiers = compareIdentifiers
+
+var numeric = /^[0-9]+$/
+function compareIdentifiers (a, b) {
+  var anum = numeric.test(a)
+  var bnum = numeric.test(b)
+
+  if (anum && bnum) {
+    a = +a
+    b = +b
+  }
+
+  return a === b ? 0
+    : (anum && !bnum) ? -1
+    : (bnum && !anum) ? 1
+    : a < b ? -1
+    : 1
+}
+
+exports.rcompareIdentifiers = rcompareIdentifiers
+function rcompareIdentifiers (a, b) {
+  return compareIdentifiers(b, a)
+}
+
+exports.major = major
+function major (a, loose) {
+  return new SemVer(a, loose).major
+}
+
+exports.minor = minor
+function minor (a, loose) {
+  return new SemVer(a, loose).minor
+}
+
+exports.patch = patch
+function patch (a, loose) {
+  return new SemVer(a, loose).patch
+}
+
+exports.compare = compare
+function compare (a, b, loose) {
+  return new SemVer(a, loose).compare(new SemVer(b, loose))
+}
+
+exports.compareLoose = compareLoose
+function compareLoose (a, b) {
+  return compare(a, b, true)
+}
+
+exports.compareBuild = compareBuild
+function compareBuild (a, b, loose) {
+  var versionA = new SemVer(a, loose)
+  var versionB = new SemVer(b, loose)
+  return versionA.compare(versionB) || versionA.compareBuild(versionB)
+}
+
+exports.rcompare = rcompare
+function rcompare (a, b, loose) {
+  return compare(b, a, loose)
+}
+
+exports.sort = sort
+function sort (list, loose) {
+  return list.sort(function (a, b) {
+    return exports.compareBuild(a, b, loose)
+  })
+}
+
+exports.rsort = rsort
+function rsort (list, loose) {
+  return list.sort(function (a, b) {
+    return exports.compareBuild(b, a, loose)
+  })
+}
+
+exports.gt = gt
+function gt (a, b, loose) {
+  return compare(a, b, loose) > 0
+}
+
+exports.lt = lt
+function lt (a, b, loose) {
+  return compare(a, b, loose) < 0
+}
+
+exports.eq = eq
+function eq (a, b, loose) {
+  return compare(a, b, loose) === 0
+}
+
+exports.neq = neq
+function neq (a, b, loose) {
+  return compare(a, b, loose) !== 0
+}
+
+exports.gte = gte
+function gte (a, b, loose) {
+  return compare(a, b, loose) >= 0
+}
+
+exports.lte = lte
+function lte (a, b, loose) {
+  return compare(a, b, loose) <= 0
+}
+
+exports.cmp = cmp
+function cmp (a, op, b, loose) {
+  switch (op) {
+    case '===':
+      if (typeof a === 'object')
+        a = a.version
+      if (typeof b === 'object')
+        b = b.version
+      return a === b
+
+    case '!==':
+      if (typeof a === 'object')
+        a = a.version
+      if (typeof b === 'object')
+        b = b.version
+      return a !== b
+
+    case '':
+    case '=':
+    case '==':
+      return eq(a, b, loose)
+
+    case '!=':
+      return neq(a, b, loose)
+
+    case '>':
+      return gt(a, b, loose)
+
+    case '>=':
+      return gte(a, b, loose)
+
+    case '<':
+      return lt(a, b, loose)
+
+    case '<=':
+      return lte(a, b, loose)
+
+    default:
+      throw new TypeError('Invalid operator: ' + op)
+  }
+}
+
+exports.Comparator = Comparator
+function Comparator (comp, options) {
+  if (!options || typeof options !== 'object') {
+    options = {
+      loose: !!options,
+      includePrerelease: false
+    }
+  }
+
+  if (comp instanceof Comparator) {
+    if (comp.loose === !!options.loose) {
+      return comp
+    } else {
+      comp = comp.value
+    }
+  }
+
+  if (!(this instanceof Comparator)) {
+    return new Comparator(comp, options)
+  }
+
+  comp = comp.trim().split(/\s+/).join(' ')
+  debug('comparator', comp, options)
+  this.options = options
+  this.loose = !!options.loose
+  this.parse(comp)
+
+  if (this.semver === ANY) {
+    this.value = ''
+  } else {
+    this.value = this.operator + this.semver.version
+  }
+
+  debug('comp', this)
+}
+
+var ANY = {}
+Comparator.prototype.parse = function (comp) {
+  var r = this.options.loose ? safeRe[t.COMPARATORLOOSE] : safeRe[t.COMPARATOR]
+  var m = comp.match(r)
+
+  if (!m) {
+    throw new TypeError('Invalid comparator: ' + comp)
+  }
+
+  this.operator = m[1] !== undefined ? m[1] : ''
+  if (this.operator === '=') {
+    this.operator = ''
+  }
+
+  // if it literally is just '>' or '' then allow anything.
+  if (!m[2]) {
+    this.semver = ANY
+  } else {
+    this.semver = new SemVer(m[2], this.options.loose)
+  }
+}
+
+Comparator.prototype.toString = function () {
+  return this.value
+}
+
+Comparator.prototype.test = function (version) {
+  debug('Comparator.test', version, this.options.loose)
+
+  if (this.semver === ANY || version === ANY) {
+    return true
+  }
+
+  if (typeof version === 'string') {
+    try {
+      version = new SemVer(version, this.options)
+    } catch (er) {
+      return false
+    }
+  }
+
+  return cmp(version, this.operator, this.semver, this.options)
+}
+
+Comparator.prototype.intersects = function (comp, options) {
+  if (!(comp instanceof Comparator)) {
+    throw new TypeError('a Comparator is required')
+  }
+
+  if (!options || typeof options !== 'object') {
+    options = {
+      loose: !!options,
+      includePrerelease: false
+    }
+  }
+
+  var rangeTmp
+
+  if (this.operator === '') {
+    if (this.value === '') {
+      return true
+    }
+    rangeTmp = new Range(comp.value, options)
+    return satisfies(this.value, rangeTmp, options)
+  } else if (comp.operator === '') {
+    if (comp.value === '') {
+      return true
+    }
+    rangeTmp = new Range(this.value, options)
+    return satisfies(comp.semver, rangeTmp, options)
+  }
+
+  var sameDirectionIncreasing =
+    (this.operator === '>=' || this.operator === '>') &&
+    (comp.operator === '>=' || comp.operator === '>')
+  var sameDirectionDecreasing =
+    (this.operator === '<=' || this.operator === '<') &&
+    (comp.operator === '<=' || comp.operator === '<')
+  var sameSemVer = this.semver.version === comp.semver.version
+  var differentDirectionsInclusive =
+    (this.operator === '>=' || this.operator === '<=') &&
+    (comp.operator === '>=' || comp.operator === '<=')
+  var oppositeDirectionsLessThan =
+    cmp(this.semver, '<', comp.semver, options) &&
+    ((this.operator === '>=' || this.operator === '>') &&
+    (comp.operator === '<=' || comp.operator === '<'))
+  var oppositeDirectionsGreaterThan =
+    cmp(this.semver, '>', comp.semver, options) &&
+    ((this.operator === '<=' || this.operator === '<') &&
+    (comp.operator === '>=' || comp.operator === '>'))
+
+  return sameDirectionIncreasing || sameDirectionDecreasing ||
+    (sameSemVer && differentDirectionsInclusive) ||
+    oppositeDirectionsLessThan || oppositeDirectionsGreaterThan
+}
+
+exports.Range = Range
+function Range (range, options) {
+  if (!options || typeof options !== 'object') {
+    options = {
+      loose: !!options,
+      includePrerelease: false
+    }
+  }
+
+  if (range instanceof Range) {
+    if (range.loose === !!options.loose &&
+        range.includePrerelease === !!options.includePrerelease) {
+      return range
+    } else {
+      return new Range(range.raw, options)
+    }
+  }
+
+  if (range instanceof Comparator) {
+    return new Range(range.value, options)
+  }
+
+  if (!(this instanceof Range)) {
+    return new Range(range, options)
+  }
+
+  this.options = options
+  this.loose = !!options.loose
+  this.includePrerelease = !!options.includePrerelease
+
+  // First reduce all whitespace as much as possible so we do not have to rely
+  // on potentially slow regexes like \s*. This is then stored and used for
+  // future error messages as well.
+  this.raw = range
+    .trim()
+    .split(/\s+/)
+    .join(' ')
+
+  // First, split based on boolean or ||
+  this.set = this.raw.split('||').map(function (range) {
+    return this.parseRange(range.trim())
+  }, this).filter(function (c) {
+    // throw out any that are not relevant for whatever reason
+    return c.length
+  })
+
+  if (!this.set.length) {
+    throw new TypeError('Invalid SemVer Range: ' + this.raw)
+  }
+
+  this.format()
+}
+
+Range.prototype.format = function () {
+  this.range = this.set.map(function (comps) {
+    return comps.join(' ').trim()
+  }).join('||').trim()
+  return this.range
+}
+
+Range.prototype.toString = function () {
+  return this.range
+}
+
+Range.prototype.parseRange = function (range) {
+  var loose = this.options.loose
+  // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
+  var hr = loose ? safeRe[t.HYPHENRANGELOOSE] : safeRe[t.HYPHENRANGE]
+  range = range.replace(hr, hyphenReplace)
+  debug('hyphen replace', range)
+  // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
+  range = range.replace(safeRe[t.COMPARATORTRIM], comparatorTrimReplace)
+  debug('comparator trim', range, safeRe[t.COMPARATORTRIM])
+
+  // `~ 1.2.3` => `~1.2.3`
+  range = range.replace(safeRe[t.TILDETRIM], tildeTrimReplace)
+
+  // `^ 1.2.3` => `^1.2.3`
+  range = range.replace(safeRe[t.CARETTRIM], caretTrimReplace)
+
+  // normalize spaces
+  range = range.split(/\s+/).join(' ')
+
+  // At this point, the range is completely trimmed and
+  // ready to be split into comparators.
+
+  var compRe = loose ? safeRe[t.COMPARATORLOOSE] : safeRe[t.COMPARATOR]
+  var set = range.split(' ').map(function (comp) {
+    return parseComparator(comp, this.options)
+  }, this).join(' ').split(/\s+/)
+  if (this.options.loose) {
+    // in loose mode, throw out any that are not valid comparators
+    set = set.filter(function (comp) {
+      return !!comp.match(compRe)
+    })
+  }
+  set = set.map(function (comp) {
+    return new Comparator(comp, this.options)
+  }, this)
+
+  return set
+}
+
+Range.prototype.intersects = function (range, options) {
+  if (!(range instanceof Range)) {
+    throw new TypeError('a Range is required')
+  }
+
+  return this.set.some(function (thisComparators) {
+    return (
+      isSatisfiable(thisComparators, options) &&
+      range.set.some(function (rangeComparators) {
+        return (
+          isSatisfiable(rangeComparators, options) &&
+          thisComparators.every(function (thisComparator) {
+            return rangeComparators.every(function (rangeComparator) {
+              return thisComparator.intersects(rangeComparator, options)
+            })
+          })
+        )
+      })
+    )
+  })
+}
+
+// take a set of comparators and determine whether there
+// exists a version which can satisfy it
+function isSatisfiable (comparators, options) {
+  var result = true
+  var remainingComparators = comparators.slice()
+  var testComparator = remainingComparators.pop()
+
+  while (result && remainingComparators.length) {
+    result = remainingComparators.every(function (otherComparator) {
+      return testComparator.intersects(otherComparator, options)
+    })
+
+    testComparator = remainingComparators.pop()
+  }
+
+  return result
+}
+
+// Mostly just for testing and legacy API reasons
+exports.toComparators = toComparators
+function toComparators (range, options) {
+  return new Range(range, options).set.map(function (comp) {
+    return comp.map(function (c) {
+      return c.value
+    }).join(' ').trim().split(' ')
+  })
+}
+
+// comprised of xranges, tildes, stars, and gtlt's at this point.
+// already replaced the hyphen ranges
+// turn into a set of JUST comparators.
+function parseComparator (comp, options) {
+  debug('comp', comp, options)
+  comp = replaceCarets(comp, options)
+  debug('caret', comp)
+  comp = replaceTildes(comp, options)
+  debug('tildes', comp)
+  comp = replaceXRanges(comp, options)
+  debug('xrange', comp)
+  comp = replaceStars(comp, options)
+  debug('stars', comp)
+  return comp
+}
+
+function isX (id) {
+  return !id || id.toLowerCase() === 'x' || id === '*'
+}
+
+// ~, ~> --> * (any, kinda silly)
+// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0
+// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0
+// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0
+// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0
+// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0
+function replaceTildes (comp, options) {
+  return comp.trim().split(/\s+/).map(function (comp) {
+    return replaceTilde(comp, options)
+  }).join(' ')
+}
+
+function replaceTilde (comp, options) {
+  var r = options.loose ? safeRe[t.TILDELOOSE] : safeRe[t.TILDE]
+  return comp.replace(r, function (_, M, m, p, pr) {
+    debug('tilde', comp, _, M, m, p, pr)
+    var ret
+
+    if (isX(M)) {
+      ret = ''
+    } else if (isX(m)) {
+      ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'
+    } else if (isX(p)) {
+      // ~1.2 == >=1.2.0 <1.3.0
+      ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'
+    } else if (pr) {
+      debug('replaceTilde pr', pr)
+      ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
+            ' <' + M + '.' + (+m + 1) + '.0'
+    } else {
+      // ~1.2.3 == >=1.2.3 <1.3.0
+      ret = '>=' + M + '.' + m + '.' + p +
+            ' <' + M + '.' + (+m + 1) + '.0'
+    }
+
+    debug('tilde return', ret)
+    return ret
+  })
+}
+
+// ^ --> * (any, kinda silly)
+// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0
+// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0
+// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0
+// ^1.2.3 --> >=1.2.3 <2.0.0
+// ^1.2.0 --> >=1.2.0 <2.0.0
+function replaceCarets (comp, options) {
+  return comp.trim().split(/\s+/).map(function (comp) {
+    return replaceCaret(comp, options)
+  }).join(' ')
+}
+
+function replaceCaret (comp, options) {
+  debug('caret', comp, options)
+  var r = options.loose ? safeRe[t.CARETLOOSE] : safeRe[t.CARET]
+  return comp.replace(r, function (_, M, m, p, pr) {
+    debug('caret', comp, _, M, m, p, pr)
+    var ret
+
+    if (isX(M)) {
+      ret = ''
+    } else if (isX(m)) {
+      ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'
+    } else if (isX(p)) {
+      if (M === '0') {
+        ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'
+      } else {
+        ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0'
+      }
+    } else if (pr) {
+      debug('replaceCaret pr', pr)
+      if (M === '0') {
+        if (m === '0') {
+          ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
+                ' <' + M + '.' + m + '.' + (+p + 1)
+        } else {
+          ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
+                ' <' + M + '.' + (+m + 1) + '.0'
+        }
+      } else {
+        ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
+              ' <' + (+M + 1) + '.0.0'
+      }
+    } else {
+      debug('no pr')
+      if (M === '0') {
+        if (m === '0') {
+          ret = '>=' + M + '.' + m + '.' + p +
+                ' <' + M + '.' + m + '.' + (+p + 1)
+        } else {
+          ret = '>=' + M + '.' + m + '.' + p +
+                ' <' + M + '.' + (+m + 1) + '.0'
+        }
+      } else {
+        ret = '>=' + M + '.' + m + '.' + p +
+              ' <' + (+M + 1) + '.0.0'
+      }
+    }
+
+    debug('caret return', ret)
+    return ret
+  })
+}
+
+function replaceXRanges (comp, options) {
+  debug('replaceXRanges', comp, options)
+  return comp.split(/\s+/).map(function (comp) {
+    return replaceXRange(comp, options)
+  }).join(' ')
+}
+
+function replaceXRange (comp, options) {
+  comp = comp.trim()
+  var r = options.loose ? safeRe[t.XRANGELOOSE] : safeRe[t.XRANGE]
+  return comp.replace(r, function (ret, gtlt, M, m, p, pr) {
+    debug('xRange', comp, ret, gtlt, M, m, p, pr)
+    var xM = isX(M)
+    var xm = xM || isX(m)
+    var xp = xm || isX(p)
+    var anyX = xp
+
+    if (gtlt === '=' && anyX) {
+      gtlt = ''
+    }
+
+    // if we're including prereleases in the match, then we need
+    // to fix this to -0, the lowest possible prerelease value
+    pr = options.includePrerelease ? '-0' : ''
+
+    if (xM) {
+      if (gtlt === '>' || gtlt === '<') {
+        // nothing is allowed
+        ret = '<0.0.0-0'
+      } else {
+        // nothing is forbidden
+        ret = '*'
+      }
+    } else if (gtlt && anyX) {
+      // we know patch is an x, because we have any x at all.
+      // replace X with 0
+      if (xm) {
+        m = 0
+      }
+      p = 0
+
+      if (gtlt === '>') {
+        // >1 => >=2.0.0
+        // >1.2 => >=1.3.0
+        // >1.2.3 => >= 1.2.4
+        gtlt = '>='
+        if (xm) {
+          M = +M + 1
+          m = 0
+          p = 0
+        } else {
+          m = +m + 1
+          p = 0
+        }
+      } else if (gtlt === '<=') {
+        // <=0.7.x is actually <0.8.0, since any 0.7.x should
+        // pass.  Similarly, <=7.x is actually <8.0.0, etc.
+        gtlt = '<'
+        if (xm) {
+          M = +M + 1
+        } else {
+          m = +m + 1
+        }
+      }
+
+      ret = gtlt + M + '.' + m + '.' + p + pr
+    } else if (xm) {
+      ret = '>=' + M + '.0.0' + pr + ' <' + (+M + 1) + '.0.0' + pr
+    } else if (xp) {
+      ret = '>=' + M + '.' + m + '.0' + pr +
+        ' <' + M + '.' + (+m + 1) + '.0' + pr
+    }
+
+    debug('xRange return', ret)
+
+    return ret
+  })
+}
+
+// Because * is AND-ed with everything else in the comparator,
+// and '' means "any version", just remove the *s entirely.
+function replaceStars (comp, options) {
+  debug('replaceStars', comp, options)
+  // Looseness is ignored here.  star is always as loose as it gets!
+  return comp.trim().replace(safeRe[t.STAR], '')
+}
+
+// This function is passed to string.replace(re[t.HYPHENRANGE])
+// M, m, patch, prerelease, build
+// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5
+// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do
+// 1.2 - 3.4 => >=1.2.0 <3.5.0
+function hyphenReplace ($0,
+  from, fM, fm, fp, fpr, fb,
+  to, tM, tm, tp, tpr, tb) {
+  if (isX(fM)) {
+    from = ''
+  } else if (isX(fm)) {
+    from = '>=' + fM + '.0.0'
+  } else if (isX(fp)) {
+    from = '>=' + fM + '.' + fm + '.0'
+  } else {
+    from = '>=' + from
+  }
+
+  if (isX(tM)) {
+    to = ''
+  } else if (isX(tm)) {
+    to = '<' + (+tM + 1) + '.0.0'
+  } else if (isX(tp)) {
+    to = '<' + tM + '.' + (+tm + 1) + '.0'
+  } else if (tpr) {
+    to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr
+  } else {
+    to = '<=' + to
+  }
+
+  return (from + ' ' + to).trim()
+}
+
+// if ANY of the sets match ALL of its comparators, then pass
+Range.prototype.test = function (version) {
+  if (!version) {
+    return false
+  }
+
+  if (typeof version === 'string') {
+    try {
+      version = new SemVer(version, this.options)
+    } catch (er) {
+      return false
+    }
+  }
+
+  for (var i = 0; i < this.set.length; i++) {
+    if (testSet(this.set[i], version, this.options)) {
+      return true
+    }
+  }
+  return false
+}
+
+function testSet (set, version, options) {
+  for (var i = 0; i < set.length; i++) {
+    if (!set[i].test(version)) {
+      return false
+    }
+  }
+
+  if (version.prerelease.length && !options.includePrerelease) {
+    // Find the set of versions that are allowed to have prereleases
+    // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0
+    // That should allow `1.2.3-pr.2` to pass.
+    // However, `1.2.4-alpha.notready` should NOT be allowed,
+    // even though it's within the range set by the comparators.
+    for (i = 0; i < set.length; i++) {
+      debug(set[i].semver)
+      if (set[i].semver === ANY) {
+        continue
+      }
+
+      if (set[i].semver.prerelease.length > 0) {
+        var allowed = set[i].semver
+        if (allowed.major === version.major &&
+            allowed.minor === version.minor &&
+            allowed.patch === version.patch) {
+          return true
+        }
+      }
+    }
+
+    // Version has a -pre, but it's not one of the ones we like.
+    return false
+  }
+
+  return true
+}
+
+exports.satisfies = satisfies
+function satisfies (version, range, options) {
+  try {
+    range = new Range(range, options)
+  } catch (er) {
+    return false
+  }
+  return range.test(version)
+}
+
+exports.maxSatisfying = maxSatisfying
+function maxSatisfying (versions, range, options) {
+  var max = null
+  var maxSV = null
+  try {
+    var rangeObj = new Range(range, options)
+  } catch (er) {
+    return null
+  }
+  versions.forEach(function (v) {
+    if (rangeObj.test(v)) {
+      // satisfies(v, range, options)
+      if (!max || maxSV.compare(v) === -1) {
+        // compare(max, v, true)
+        max = v
+        maxSV = new SemVer(max, options)
+      }
+    }
+  })
+  return max
+}
+
+exports.minSatisfying = minSatisfying
+function minSatisfying (versions, range, options) {
+  var min = null
+  var minSV = null
+  try {
+    var rangeObj = new Range(range, options)
+  } catch (er) {
+    return null
+  }
+  versions.forEach(function (v) {
+    if (rangeObj.test(v)) {
+      // satisfies(v, range, options)
+      if (!min || minSV.compare(v) === 1) {
+        // compare(min, v, true)
+        min = v
+        minSV = new SemVer(min, options)
+      }
+    }
+  })
+  return min
+}
+
+exports.minVersion = minVersion
+function minVersion (range, loose) {
+  range = new Range(range, loose)
+
+  var minver = new SemVer('0.0.0')
+  if (range.test(minver)) {
+    return minver
+  }
+
+  minver = new SemVer('0.0.0-0')
+  if (range.test(minver)) {
+    return minver
+  }
+
+  minver = null
+  for (var i = 0; i < range.set.length; ++i) {
+    var comparators = range.set[i]
+
+    comparators.forEach(function (comparator) {
+      // Clone to avoid manipulating the comparator's semver object.
+      var compver = new SemVer(comparator.semver.version)
+      switch (comparator.operator) {
+        case '>':
+          if (compver.prerelease.length === 0) {
+            compver.patch++
+          } else {
+            compver.prerelease.push(0)
+          }
+          compver.raw = compver.format()
+          /* fallthrough */
+        case '':
+        case '>=':
+          if (!minver || gt(minver, compver)) {
+            minver = compver
+          }
+          break
+        case '<':
+        case '<=':
+          /* Ignore maximum versions */
+          break
+        /* istanbul ignore next */
+        default:
+          throw new Error('Unexpected operation: ' + comparator.operator)
+      }
+    })
+  }
+
+  if (minver && range.test(minver)) {
+    return minver
+  }
+
+  return null
+}
+
+exports.validRange = validRange
+function validRange (range, options) {
+  try {
+    // Return '*' instead of '' so that truthiness works.
+    // This will throw if it's invalid anyway
+    return new Range(range, options).range || '*'
+  } catch (er) {
+    return null
+  }
+}
+
+// Determine if version is less than all the versions possible in the range
+exports.ltr = ltr
+function ltr (version, range, options) {
+  return outside(version, range, '<', options)
+}
+
+// Determine if version is greater than all the versions possible in the range.
+exports.gtr = gtr
+function gtr (version, range, options) {
+  return outside(version, range, '>', options)
+}
+
+exports.outside = outside
+function outside (version, range, hilo, options) {
+  version = new SemVer(version, options)
+  range = new Range(range, options)
+
+  var gtfn, ltefn, ltfn, comp, ecomp
+  switch (hilo) {
+    case '>':
+      gtfn = gt
+      ltefn = lte
+      ltfn = lt
+      comp = '>'
+      ecomp = '>='
+      break
+    case '<':
+      gtfn = lt
+      ltefn = gte
+      ltfn = gt
+      comp = '<'
+      ecomp = '<='
+      break
+    default:
+      throw new TypeError('Must provide a hilo val of "<" or ">"')
+  }
+
+  // If it satisifes the range it is not outside
+  if (satisfies(version, range, options)) {
+    return false
+  }
+
+  // From now on, variable terms are as if we're in "gtr" mode.
+  // but note that everything is flipped for the "ltr" function.
+
+  for (var i = 0; i < range.set.length; ++i) {
+    var comparators = range.set[i]
+
+    var high = null
+    var low = null
+
+    comparators.forEach(function (comparator) {
+      if (comparator.semver === ANY) {
+        comparator = new Comparator('>=0.0.0')
+      }
+      high = high || comparator
+      low = low || comparator
+      if (gtfn(comparator.semver, high.semver, options)) {
+        high = comparator
+      } else if (ltfn(comparator.semver, low.semver, options)) {
+        low = comparator
+      }
+    })
+
+    // If the edge version comparator has a operator then our version
+    // isn't outside it
+    if (high.operator === comp || high.operator === ecomp) {
+      return false
+    }
+
+    // If the lowest version comparator has an operator and our version
+    // is less than it then it isn't higher than the range
+    if ((!low.operator || low.operator === comp) &&
+        ltefn(version, low.semver)) {
+      return false
+    } else if (low.operator === ecomp && ltfn(version, low.semver)) {
+      return false
+    }
+  }
+  return true
+}
+
+exports.prerelease = prerelease
+function prerelease (version, options) {
+  var parsed = parse(version, options)
+  return (parsed && parsed.prerelease.length) ? parsed.prerelease : null
+}
+
+exports.intersects = intersects
+function intersects (r1, r2, options) {
+  r1 = new Range(r1, options)
+  r2 = new Range(r2, options)
+  return r1.intersects(r2)
+}
+
+exports.coerce = coerce
+function coerce (version, options) {
+  if (version instanceof SemVer) {
+    return version
+  }
+
+  if (typeof version === 'number') {
+    version = String(version)
+  }
+
+  if (typeof version !== 'string') {
+    return null
+  }
+
+  options = options || {}
+
+  var match = null
+  if (!options.rtl) {
+    match = version.match(safeRe[t.COERCE])
+  } else {
+    // Find the right-most coercible string that does not share
+    // a terminus with a more left-ward coercible string.
+    // Eg, '1.2.3.4' wants to coerce '2.3.4', not '3.4' or '4'
+    //
+    // Walk through the string checking with a /g regexp
+    // Manually set the index so as to pick up overlapping matches.
+    // Stop when we get a match that ends at the string end, since no
+    // coercible string can be more right-ward without the same terminus.
+    var next
+    while ((next = safeRe[t.COERCERTL].exec(version)) &&
+      (!match || match.index + match[0].length !== version.length)
+    ) {
+      if (!match ||
+          next.index + next[0].length !== match.index + match[0].length) {
+        match = next
+      }
+      safeRe[t.COERCERTL].lastIndex = next.index + next[1].length + next[2].length
+    }
+    // leave it in a clean state
+    safeRe[t.COERCERTL].lastIndex = -1
+  }
+
+  if (match === null) {
+    return null
+  }
+
+  return parse(match[2] +
+    '.' + (match[3] || '0') +
+    '.' + (match[4] || '0'), options)
+}
Index: frontend/node_modules/istanbul-lib-instrument/package.json
===================================================================
--- frontend/node_modules/istanbul-lib-instrument/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/istanbul-lib-instrument/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,50 @@
+{
+  "name": "istanbul-lib-instrument",
+  "version": "5.2.1",
+  "description": "Core istanbul API for JS code coverage",
+  "author": "Krishnan Anantheswaran <kananthmail-github@yahoo.com>",
+  "main": "src/index.js",
+  "files": [
+    "src"
+  ],
+  "scripts": {
+    "test": "nyc mocha"
+  },
+  "dependencies": {
+    "@babel/core": "^7.12.3",
+    "@babel/parser": "^7.14.7",
+    "@istanbuljs/schema": "^0.1.2",
+    "istanbul-lib-coverage": "^3.2.0",
+    "semver": "^6.3.0"
+  },
+  "devDependencies": {
+    "@babel/cli": "^7.7.5",
+    "chai": "^4.2.0",
+    "clone": "^2.1.2",
+    "debug": "^4.1.1",
+    "documentation": "^12.1.4",
+    "js-yaml": "^3.13.1",
+    "mocha": "^6.2.3",
+    "nopt": "^4.0.1",
+    "nyc": "^15.1.0"
+  },
+  "license": "BSD-3-Clause",
+  "bugs": {
+    "url": "https://github.com/istanbuljs/istanbuljs/issues"
+  },
+  "homepage": "https://istanbul.js.org/",
+  "repository": {
+    "type": "git",
+    "url": "git+ssh://git@github.com/istanbuljs/istanbuljs.git",
+    "directory": "packages/istanbul-lib-instrument"
+  },
+  "keywords": [
+    "coverage",
+    "istanbul",
+    "js",
+    "instrumentation"
+  ],
+  "engines": {
+    "node": ">=8"
+  }
+}
Index: frontend/node_modules/istanbul-lib-instrument/src/constants.js
===================================================================
--- frontend/node_modules/istanbul-lib-instrument/src/constants.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/istanbul-lib-instrument/src/constants.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,14 @@
+const { createHash } = require('crypto');
+const { name } = require('../package.json');
+// TODO: increment this version if there are schema changes
+// that are not backwards compatible:
+const VERSION = '4';
+
+const SHA = 'sha1';
+module.exports = {
+    SHA,
+    MAGIC_KEY: '_coverageSchema',
+    MAGIC_VALUE: createHash(SHA)
+        .update(name + '@' + VERSION)
+        .digest('hex')
+};
Index: frontend/node_modules/istanbul-lib-instrument/src/index.js
===================================================================
--- frontend/node_modules/istanbul-lib-instrument/src/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/istanbul-lib-instrument/src/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,21 @@
+const { defaults } = require('@istanbuljs/schema');
+const Instrumenter = require('./instrumenter');
+const programVisitor = require('./visitor');
+const readInitialCoverage = require('./read-coverage');
+
+/**
+ * createInstrumenter creates a new instrumenter with the
+ * supplied options.
+ * @param {Object} opts - instrumenter options. See the documentation
+ * for the Instrumenter class.
+ */
+function createInstrumenter(opts) {
+    return new Instrumenter(opts);
+}
+
+module.exports = {
+    createInstrumenter,
+    programVisitor,
+    readInitialCoverage,
+    defaultOpts: defaults.instrumenter
+};
Index: frontend/node_modules/istanbul-lib-instrument/src/instrumenter.js
===================================================================
--- frontend/node_modules/istanbul-lib-instrument/src/instrumenter.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/istanbul-lib-instrument/src/instrumenter.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,162 @@
+/*
+ Copyright 2012-2015, Yahoo Inc.
+ Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
+ */
+const { transformSync } = require('@babel/core');
+const { defaults } = require('@istanbuljs/schema');
+const programVisitor = require('./visitor');
+const readInitialCoverage = require('./read-coverage');
+
+/**
+ * Instrumenter is the public API for the instrument library.
+ * It is typically used for ES5 code. For ES6 code that you
+ * are already running under `babel` use the coverage plugin
+ * instead.
+ * @param {Object} opts optional.
+ * @param {string} [opts.coverageVariable=__coverage__] name of global coverage variable.
+ * @param {boolean} [opts.reportLogic=false] report boolean value of logical expressions.
+ * @param {boolean} [opts.preserveComments=false] preserve comments in output.
+ * @param {boolean} [opts.compact=true] generate compact code.
+ * @param {boolean} [opts.esModules=false] set to true to instrument ES6 modules.
+ * @param {boolean} [opts.autoWrap=false] set to true to allow `return` statements outside of functions.
+ * @param {boolean} [opts.produceSourceMap=false] set to true to produce a source map for the instrumented code.
+ * @param {Array} [opts.ignoreClassMethods=[]] set to array of class method names to ignore for coverage.
+ * @param {Function} [opts.sourceMapUrlCallback=null] a callback function that is called when a source map URL
+ *     is found in the original code. This function is called with the source file name and the source map URL.
+ * @param {boolean} [opts.debug=false] - turn debugging on.
+ * @param {array} [opts.parserPlugins] - set babel parser plugins, see @istanbuljs/schema for defaults.
+ * @param {string} [opts.coverageGlobalScope=this] the global coverage variable scope.
+ * @param {boolean} [opts.coverageGlobalScopeFunc=true] use an evaluated function to find coverageGlobalScope.
+ */
+class Instrumenter {
+    constructor(opts = {}) {
+        this.opts = {
+            ...defaults.instrumenter,
+            ...opts
+        };
+        this.fileCoverage = null;
+        this.sourceMap = null;
+    }
+    /**
+     * instrument the supplied code and track coverage against the supplied
+     * filename. It throws if invalid code is passed to it. ES5 and ES6 syntax
+     * is supported. To instrument ES6 modules, make sure that you set the
+     * `esModules` property to `true` when creating the instrumenter.
+     *
+     * @param {string} code - the code to instrument
+     * @param {string} filename - the filename against which to track coverage.
+     * @param {object} [inputSourceMap] - the source map that maps the not instrumented code back to it's original form.
+     * Is assigned to the coverage object and therefore, is available in the json output and can be used to remap the
+     * coverage to the untranspiled source.
+     * @returns {string} the instrumented code.
+     */
+    instrumentSync(code, filename, inputSourceMap) {
+        if (typeof code !== 'string') {
+            throw new Error('Code must be a string');
+        }
+        filename = filename || String(new Date().getTime()) + '.js';
+        const { opts } = this;
+        let output = {};
+        const babelOpts = {
+            configFile: false,
+            babelrc: false,
+            ast: true,
+            filename: filename || String(new Date().getTime()) + '.js',
+            inputSourceMap,
+            sourceMaps: opts.produceSourceMap,
+            compact: opts.compact,
+            comments: opts.preserveComments,
+            parserOpts: {
+                allowReturnOutsideFunction: opts.autoWrap,
+                sourceType: opts.esModules ? 'module' : 'script',
+                plugins: opts.parserPlugins
+            },
+            plugins: [
+                [
+                    ({ types }) => {
+                        const ee = programVisitor(types, filename, {
+                            coverageVariable: opts.coverageVariable,
+                            reportLogic: opts.reportLogic,
+                            coverageGlobalScope: opts.coverageGlobalScope,
+                            coverageGlobalScopeFunc:
+                                opts.coverageGlobalScopeFunc,
+                            ignoreClassMethods: opts.ignoreClassMethods,
+                            inputSourceMap
+                        });
+
+                        return {
+                            visitor: {
+                                Program: {
+                                    enter: ee.enter,
+                                    exit(path) {
+                                        output = ee.exit(path);
+                                    }
+                                }
+                            }
+                        };
+                    }
+                ]
+            ]
+        };
+
+        const codeMap = transformSync(code, babelOpts);
+
+        if (!output || !output.fileCoverage) {
+            const initialCoverage =
+                readInitialCoverage(codeMap.ast) ||
+                /* istanbul ignore next: paranoid check */ {};
+            this.fileCoverage = initialCoverage.coverageData;
+            this.sourceMap = inputSourceMap;
+            return code;
+        }
+
+        this.fileCoverage = output.fileCoverage;
+        this.sourceMap = codeMap.map;
+        const cb = this.opts.sourceMapUrlCallback;
+        if (cb && output.sourceMappingURL) {
+            cb(filename, output.sourceMappingURL);
+        }
+
+        return codeMap.code;
+    }
+    /**
+     * callback-style instrument method that calls back with an error
+     * as opposed to throwing one. Note that in the current implementation,
+     * the callback will be called in the same process tick and is not asynchronous.
+     *
+     * @param {string} code - the code to instrument
+     * @param {string} filename - the filename against which to track coverage.
+     * @param {Function} callback - the callback
+     * @param {Object} inputSourceMap - the source map that maps the not instrumented code back to it's original form.
+     * Is assigned to the coverage object and therefore, is available in the json output and can be used to remap the
+     * coverage to the untranspiled source.
+     */
+    instrument(code, filename, callback, inputSourceMap) {
+        if (!callback && typeof filename === 'function') {
+            callback = filename;
+            filename = null;
+        }
+        try {
+            const out = this.instrumentSync(code, filename, inputSourceMap);
+            callback(null, out);
+        } catch (ex) {
+            callback(ex);
+        }
+    }
+    /**
+     * returns the file coverage object for the last file instrumented.
+     * @returns {Object} the file coverage object.
+     */
+    lastFileCoverage() {
+        return this.fileCoverage;
+    }
+    /**
+     * returns the source map produced for the last file instrumented.
+     * @returns {null|Object} the source map object.
+     */
+    lastSourceMap() {
+        return this.sourceMap;
+    }
+}
+
+module.exports = Instrumenter;
Index: frontend/node_modules/istanbul-lib-instrument/src/read-coverage.js
===================================================================
--- frontend/node_modules/istanbul-lib-instrument/src/read-coverage.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/istanbul-lib-instrument/src/read-coverage.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,77 @@
+const { parseSync, traverse } = require('@babel/core');
+const { defaults } = require('@istanbuljs/schema');
+const { MAGIC_KEY, MAGIC_VALUE } = require('./constants');
+
+function getAst(code) {
+    if (typeof code === 'object' && typeof code.type === 'string') {
+        // Assume code is already a babel ast.
+        return code;
+    }
+
+    if (typeof code !== 'string') {
+        throw new Error('Code must be a string');
+    }
+
+    // Parse as leniently as possible
+    return parseSync(code, {
+        babelrc: false,
+        configFile: false,
+        parserOpts: {
+            allowAwaitOutsideFunction: true,
+            allowImportExportEverywhere: true,
+            allowReturnOutsideFunction: true,
+            allowSuperOutsideMethod: true,
+            sourceType: 'script',
+            plugins: defaults.instrumenter.parserPlugins
+        }
+    });
+}
+
+module.exports = function readInitialCoverage(code) {
+    const ast = getAst(code);
+
+    let covScope;
+    traverse(ast, {
+        ObjectProperty(path) {
+            const { node } = path;
+            if (
+                !node.computed &&
+                path.get('key').isIdentifier() &&
+                node.key.name === MAGIC_KEY
+            ) {
+                const magicValue = path.get('value').evaluate();
+                if (!magicValue.confident || magicValue.value !== MAGIC_VALUE) {
+                    return;
+                }
+                covScope =
+                    path.scope.getFunctionParent() ||
+                    path.scope.getProgramParent();
+                path.stop();
+            }
+        }
+    });
+
+    if (!covScope) {
+        return null;
+    }
+
+    const result = {};
+
+    for (const key of ['path', 'hash', 'gcv', 'coverageData']) {
+        const binding = covScope.getOwnBinding(key);
+        if (!binding) {
+            return null;
+        }
+        const valuePath = binding.path.get('init');
+        const value = valuePath.evaluate();
+        if (!value.confident) {
+            return null;
+        }
+        result[key] = value.value;
+    }
+
+    delete result.coverageData[MAGIC_KEY];
+    delete result.coverageData.hash;
+
+    return result;
+};
Index: frontend/node_modules/istanbul-lib-instrument/src/source-coverage.js
===================================================================
--- frontend/node_modules/istanbul-lib-instrument/src/source-coverage.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/istanbul-lib-instrument/src/source-coverage.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,135 @@
+const { classes } = require('istanbul-lib-coverage');
+
+function cloneLocation(loc) {
+    return {
+        start: {
+            line: loc && loc.start.line,
+            column: loc && loc.start.column
+        },
+        end: {
+            line: loc && loc.end.line,
+            column: loc && loc.end.column
+        }
+    };
+}
+/**
+ * SourceCoverage provides mutation methods to manipulate the structure of
+ * a file coverage object. Used by the instrumenter to create a full coverage
+ * object for a file incrementally.
+ *
+ * @private
+ * @param pathOrObj {String|Object} - see the argument for {@link FileCoverage}
+ * @extends FileCoverage
+ * @constructor
+ */
+class SourceCoverage extends classes.FileCoverage {
+    constructor(pathOrObj) {
+        super(pathOrObj);
+        this.meta = {
+            last: {
+                s: 0,
+                f: 0,
+                b: 0
+            }
+        };
+    }
+
+    newStatement(loc) {
+        const s = this.meta.last.s;
+        this.data.statementMap[s] = cloneLocation(loc);
+        this.data.s[s] = 0;
+        this.meta.last.s += 1;
+        return s;
+    }
+
+    newFunction(name, decl, loc) {
+        const f = this.meta.last.f;
+        name = name || '(anonymous_' + f + ')';
+        this.data.fnMap[f] = {
+            name,
+            decl: cloneLocation(decl),
+            loc: cloneLocation(loc),
+            // DEPRECATED: some legacy reports require this info.
+            line: loc && loc.start.line
+        };
+        this.data.f[f] = 0;
+        this.meta.last.f += 1;
+        return f;
+    }
+
+    newBranch(type, loc, isReportLogic = false) {
+        const b = this.meta.last.b;
+        this.data.b[b] = [];
+        this.data.branchMap[b] = {
+            loc: cloneLocation(loc),
+            type,
+            locations: [],
+            // DEPRECATED: some legacy reports require this info.
+            line: loc && loc.start.line
+        };
+        this.meta.last.b += 1;
+        this.maybeNewBranchTrue(type, b, isReportLogic);
+        return b;
+    }
+
+    maybeNewBranchTrue(type, name, isReportLogic) {
+        if (!isReportLogic) {
+            return;
+        }
+        if (type !== 'binary-expr') {
+            return;
+        }
+        this.data.bT = this.data.bT || {};
+        this.data.bT[name] = [];
+    }
+
+    addBranchPath(name, location) {
+        const bMeta = this.data.branchMap[name];
+        const counts = this.data.b[name];
+
+        /* istanbul ignore if: paranoid check */
+        if (!bMeta) {
+            throw new Error('Invalid branch ' + name);
+        }
+        bMeta.locations.push(cloneLocation(location));
+        counts.push(0);
+        this.maybeAddBranchTrue(name);
+        return counts.length - 1;
+    }
+
+    maybeAddBranchTrue(name) {
+        if (!this.data.bT) {
+            return;
+        }
+        const countsTrue = this.data.bT[name];
+        if (!countsTrue) {
+            return;
+        }
+        countsTrue.push(0);
+    }
+
+    /**
+     * Assigns an input source map to the coverage that can be used
+     * to remap the coverage output to the original source
+     * @param sourceMap {object} the source map
+     */
+    inputSourceMap(sourceMap) {
+        this.data.inputSourceMap = sourceMap;
+    }
+
+    freeze() {
+        // prune empty branches
+        const map = this.data.branchMap;
+        const branches = this.data.b;
+        const branchesT = this.data.bT || {};
+        Object.keys(map).forEach(b => {
+            if (map[b].locations.length === 0) {
+                delete map[b];
+                delete branches[b];
+                delete branchesT[b];
+            }
+        });
+    }
+}
+
+module.exports = { SourceCoverage };
Index: frontend/node_modules/istanbul-lib-instrument/src/visitor.js
===================================================================
--- frontend/node_modules/istanbul-lib-instrument/src/visitor.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/istanbul-lib-instrument/src/visitor.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,843 @@
+const { createHash } = require('crypto');
+const { template } = require('@babel/core');
+const { defaults } = require('@istanbuljs/schema');
+const { SourceCoverage } = require('./source-coverage');
+const { SHA, MAGIC_KEY, MAGIC_VALUE } = require('./constants');
+
+// pattern for istanbul to ignore a section
+const COMMENT_RE = /^\s*istanbul\s+ignore\s+(if|else|next)(?=\W|$)/;
+// pattern for istanbul to ignore the whole file
+const COMMENT_FILE_RE = /^\s*istanbul\s+ignore\s+(file)(?=\W|$)/;
+// source map URL pattern
+const SOURCE_MAP_RE = /[#@]\s*sourceMappingURL=(.*)\s*$/m;
+
+// generate a variable name from hashing the supplied file path
+function genVar(filename) {
+    const hash = createHash(SHA);
+    hash.update(filename);
+    return 'cov_' + parseInt(hash.digest('hex').substr(0, 12), 16).toString(36);
+}
+
+// VisitState holds the state of the visitor, provides helper functions
+// and is the `this` for the individual coverage visitors.
+class VisitState {
+    constructor(
+        types,
+        sourceFilePath,
+        inputSourceMap,
+        ignoreClassMethods = [],
+        reportLogic = false
+    ) {
+        this.varName = genVar(sourceFilePath);
+        this.attrs = {};
+        this.nextIgnore = null;
+        this.cov = new SourceCoverage(sourceFilePath);
+
+        if (typeof inputSourceMap !== 'undefined') {
+            this.cov.inputSourceMap(inputSourceMap);
+        }
+        this.ignoreClassMethods = ignoreClassMethods;
+        this.types = types;
+        this.sourceMappingURL = null;
+        this.reportLogic = reportLogic;
+    }
+
+    // should we ignore the node? Yes, if specifically ignoring
+    // or if the node is generated.
+    shouldIgnore(path) {
+        return this.nextIgnore || !path.node.loc;
+    }
+
+    // extract the ignore comment hint (next|if|else) or null
+    hintFor(node) {
+        let hint = null;
+        if (node.leadingComments) {
+            node.leadingComments.forEach(c => {
+                const v = (
+                    c.value || /* istanbul ignore next: paranoid check */ ''
+                ).trim();
+                const groups = v.match(COMMENT_RE);
+                if (groups) {
+                    hint = groups[1];
+                }
+            });
+        }
+        return hint;
+    }
+
+    // extract a source map URL from comments and keep track of it
+    maybeAssignSourceMapURL(node) {
+        const extractURL = comments => {
+            if (!comments) {
+                return;
+            }
+            comments.forEach(c => {
+                const v = (
+                    c.value || /* istanbul ignore next: paranoid check */ ''
+                ).trim();
+                const groups = v.match(SOURCE_MAP_RE);
+                if (groups) {
+                    this.sourceMappingURL = groups[1];
+                }
+            });
+        };
+        extractURL(node.leadingComments);
+        extractURL(node.trailingComments);
+    }
+
+    // for these expressions the statement counter needs to be hoisted, so
+    // function name inference can be preserved
+    counterNeedsHoisting(path) {
+        return (
+            path.isFunctionExpression() ||
+            path.isArrowFunctionExpression() ||
+            path.isClassExpression()
+        );
+    }
+
+    // all the generic stuff that needs to be done on enter for every node
+    onEnter(path) {
+        const n = path.node;
+
+        this.maybeAssignSourceMapURL(n);
+
+        // if already ignoring, nothing more to do
+        if (this.nextIgnore !== null) {
+            return;
+        }
+        // check hint to see if ignore should be turned on
+        const hint = this.hintFor(n);
+        if (hint === 'next') {
+            this.nextIgnore = n;
+            return;
+        }
+        // else check custom node attribute set by a prior visitor
+        if (this.getAttr(path.node, 'skip-all') !== null) {
+            this.nextIgnore = n;
+        }
+
+        // else check for ignored class methods
+        if (
+            path.isFunctionExpression() &&
+            this.ignoreClassMethods.some(
+                name => path.node.id && name === path.node.id.name
+            )
+        ) {
+            this.nextIgnore = n;
+            return;
+        }
+        if (
+            path.isClassMethod() &&
+            this.ignoreClassMethods.some(name => name === path.node.key.name)
+        ) {
+            this.nextIgnore = n;
+            return;
+        }
+    }
+
+    // all the generic stuff on exit of a node,
+    // including reseting ignores and custom node attrs
+    onExit(path) {
+        // restore ignore status, if needed
+        if (path.node === this.nextIgnore) {
+            this.nextIgnore = null;
+        }
+        // nuke all attributes for the node
+        delete path.node.__cov__;
+    }
+
+    // set a node attribute for the supplied node
+    setAttr(node, name, value) {
+        node.__cov__ = node.__cov__ || {};
+        node.__cov__[name] = value;
+    }
+
+    // retrieve a node attribute for the supplied node or null
+    getAttr(node, name) {
+        const c = node.__cov__;
+        if (!c) {
+            return null;
+        }
+        return c[name];
+    }
+
+    //
+    increase(type, id, index) {
+        const T = this.types;
+        const wrap =
+            index !== null
+                ? // If `index` present, turn `x` into `x[index]`.
+                  x => T.memberExpression(x, T.numericLiteral(index), true)
+                : x => x;
+        return T.updateExpression(
+            '++',
+            wrap(
+                T.memberExpression(
+                    T.memberExpression(
+                        T.callExpression(T.identifier(this.varName), []),
+                        T.identifier(type)
+                    ),
+                    T.numericLiteral(id),
+                    true
+                )
+            )
+        );
+    }
+
+    // Reads the logic expression conditions and conditionally increments truthy counter.
+    increaseTrue(type, id, index, node) {
+        const T = this.types;
+        const tempName = `${this.varName}_temp`;
+
+        return T.sequenceExpression([
+            T.assignmentExpression(
+                '=',
+                T.memberExpression(
+                    T.callExpression(T.identifier(this.varName), []),
+                    T.identifier(tempName)
+                ),
+                node // Only evaluates once.
+            ),
+            T.parenthesizedExpression(
+                T.conditionalExpression(
+                    this.validateTrueNonTrivial(T, tempName),
+                    this.increase(type, id, index),
+                    T.nullLiteral()
+                )
+            ),
+            T.memberExpression(
+                T.callExpression(T.identifier(this.varName), []),
+                T.identifier(tempName)
+            )
+        ]);
+    }
+
+    validateTrueNonTrivial(T, tempName) {
+        return T.logicalExpression(
+            '&&',
+            T.memberExpression(
+                T.callExpression(T.identifier(this.varName), []),
+                T.identifier(tempName)
+            ),
+            T.logicalExpression(
+                '&&',
+                T.parenthesizedExpression(
+                    T.logicalExpression(
+                        '||',
+                        T.unaryExpression(
+                            '!',
+                            T.callExpression(
+                                T.memberExpression(
+                                    T.identifier('Array'),
+                                    T.identifier('isArray')
+                                ),
+                                [
+                                    T.memberExpression(
+                                        T.callExpression(
+                                            T.identifier(this.varName),
+                                            []
+                                        ),
+                                        T.identifier(tempName)
+                                    )
+                                ]
+                            )
+                        ),
+                        T.memberExpression(
+                            T.memberExpression(
+                                T.callExpression(
+                                    T.identifier(this.varName),
+                                    []
+                                ),
+                                T.identifier(tempName)
+                            ),
+                            T.identifier('length')
+                        )
+                    )
+                ),
+                T.parenthesizedExpression(
+                    T.logicalExpression(
+                        '||',
+                        T.binaryExpression(
+                            '!==',
+                            T.callExpression(
+                                T.memberExpression(
+                                    T.identifier('Object'),
+                                    T.identifier('getPrototypeOf')
+                                ),
+                                [
+                                    T.memberExpression(
+                                        T.callExpression(
+                                            T.identifier(this.varName),
+                                            []
+                                        ),
+                                        T.identifier(tempName)
+                                    )
+                                ]
+                            ),
+                            T.memberExpression(
+                                T.identifier('Object'),
+                                T.identifier('prototype')
+                            )
+                        ),
+                        T.memberExpression(
+                            T.callExpression(
+                                T.memberExpression(
+                                    T.identifier('Object'),
+                                    T.identifier('values')
+                                ),
+                                [
+                                    T.memberExpression(
+                                        T.callExpression(
+                                            T.identifier(this.varName),
+                                            []
+                                        ),
+                                        T.identifier(tempName)
+                                    )
+                                ]
+                            ),
+                            T.identifier('length')
+                        )
+                    )
+                )
+            )
+        );
+    }
+
+    insertCounter(path, increment) {
+        const T = this.types;
+        if (path.isBlockStatement()) {
+            path.node.body.unshift(T.expressionStatement(increment));
+        } else if (path.isStatement()) {
+            path.insertBefore(T.expressionStatement(increment));
+        } else if (
+            this.counterNeedsHoisting(path) &&
+            T.isVariableDeclarator(path.parentPath)
+        ) {
+            // make an attempt to hoist the statement counter, so that
+            // function names are maintained.
+            const parent = path.parentPath.parentPath;
+            if (parent && T.isExportNamedDeclaration(parent.parentPath)) {
+                parent.parentPath.insertBefore(
+                    T.expressionStatement(increment)
+                );
+            } else if (
+                parent &&
+                (T.isProgram(parent.parentPath) ||
+                    T.isBlockStatement(parent.parentPath))
+            ) {
+                parent.insertBefore(T.expressionStatement(increment));
+            } else {
+                path.replaceWith(T.sequenceExpression([increment, path.node]));
+            }
+        } /* istanbul ignore else: not expected */ else if (
+            path.isExpression()
+        ) {
+            path.replaceWith(T.sequenceExpression([increment, path.node]));
+        } else {
+            console.error(
+                'Unable to insert counter for node type:',
+                path.node.type
+            );
+        }
+    }
+
+    insertStatementCounter(path) {
+        /* istanbul ignore if: paranoid check */
+        if (!(path.node && path.node.loc)) {
+            return;
+        }
+        const index = this.cov.newStatement(path.node.loc);
+        const increment = this.increase('s', index, null);
+        this.insertCounter(path, increment);
+    }
+
+    insertFunctionCounter(path) {
+        const T = this.types;
+        /* istanbul ignore if: paranoid check */
+        if (!(path.node && path.node.loc)) {
+            return;
+        }
+        const n = path.node;
+
+        let dloc = null;
+        // get location for declaration
+        switch (n.type) {
+            case 'FunctionDeclaration':
+            case 'FunctionExpression':
+                /* istanbul ignore else: paranoid check */
+                if (n.id) {
+                    dloc = n.id.loc;
+                }
+                break;
+        }
+        if (!dloc) {
+            dloc = {
+                start: n.loc.start,
+                end: { line: n.loc.start.line, column: n.loc.start.column + 1 }
+            };
+        }
+
+        const name = path.node.id ? path.node.id.name : path.node.name;
+        const index = this.cov.newFunction(name, dloc, path.node.body.loc);
+        const increment = this.increase('f', index, null);
+        const body = path.get('body');
+        /* istanbul ignore else: not expected */
+        if (body.isBlockStatement()) {
+            body.node.body.unshift(T.expressionStatement(increment));
+        } else {
+            console.error(
+                'Unable to process function body node type:',
+                path.node.type
+            );
+        }
+    }
+
+    getBranchIncrement(branchName, loc) {
+        const index = this.cov.addBranchPath(branchName, loc);
+        return this.increase('b', branchName, index);
+    }
+
+    getBranchLogicIncrement(path, branchName, loc) {
+        const index = this.cov.addBranchPath(branchName, loc);
+        return [
+            this.increase('b', branchName, index),
+            this.increaseTrue('bT', branchName, index, path.node)
+        ];
+    }
+
+    insertBranchCounter(path, branchName, loc) {
+        const increment = this.getBranchIncrement(
+            branchName,
+            loc || path.node.loc
+        );
+        this.insertCounter(path, increment);
+    }
+
+    findLeaves(node, accumulator, parent, property) {
+        if (!node) {
+            return;
+        }
+        if (node.type === 'LogicalExpression') {
+            const hint = this.hintFor(node);
+            if (hint !== 'next') {
+                this.findLeaves(node.left, accumulator, node, 'left');
+                this.findLeaves(node.right, accumulator, node, 'right');
+            }
+        } else {
+            accumulator.push({
+                node,
+                parent,
+                property
+            });
+        }
+    }
+}
+
+// generic function that takes a set of visitor methods and
+// returns a visitor object with `enter` and `exit` properties,
+// such that:
+//
+// * standard entry processing is done
+// * the supplied visitors are called only when ignore is not in effect
+//   This relieves them from worrying about ignore states and generated nodes.
+// * standard exit processing is done
+//
+function entries(...enter) {
+    // the enter function
+    const wrappedEntry = function(path, node) {
+        this.onEnter(path);
+        if (this.shouldIgnore(path)) {
+            return;
+        }
+        enter.forEach(e => {
+            e.call(this, path, node);
+        });
+    };
+    const exit = function(path, node) {
+        this.onExit(path, node);
+    };
+    return {
+        enter: wrappedEntry,
+        exit
+    };
+}
+
+function coverStatement(path) {
+    this.insertStatementCounter(path);
+}
+
+/* istanbul ignore next: no node.js support */
+function coverAssignmentPattern(path) {
+    const n = path.node;
+    const b = this.cov.newBranch('default-arg', n.loc);
+    this.insertBranchCounter(path.get('right'), b);
+}
+
+function coverFunction(path) {
+    this.insertFunctionCounter(path);
+}
+
+function coverVariableDeclarator(path) {
+    this.insertStatementCounter(path.get('init'));
+}
+
+function coverClassPropDeclarator(path) {
+    this.insertStatementCounter(path.get('value'));
+}
+
+function makeBlock(path) {
+    const T = this.types;
+    if (!path.node) {
+        path.replaceWith(T.blockStatement([]));
+    }
+    if (!path.isBlockStatement()) {
+        path.replaceWith(T.blockStatement([path.node]));
+        path.node.loc = path.node.body[0].loc;
+        path.node.body[0].leadingComments = path.node.leadingComments;
+        path.node.leadingComments = undefined;
+    }
+}
+
+function blockProp(prop) {
+    return function(path) {
+        makeBlock.call(this, path.get(prop));
+    };
+}
+
+function makeParenthesizedExpressionForNonIdentifier(path) {
+    const T = this.types;
+    if (path.node && !path.isIdentifier()) {
+        path.replaceWith(T.parenthesizedExpression(path.node));
+    }
+}
+
+function parenthesizedExpressionProp(prop) {
+    return function(path) {
+        makeParenthesizedExpressionForNonIdentifier.call(this, path.get(prop));
+    };
+}
+
+function convertArrowExpression(path) {
+    const n = path.node;
+    const T = this.types;
+    if (!T.isBlockStatement(n.body)) {
+        const bloc = n.body.loc;
+        if (n.expression === true) {
+            n.expression = false;
+        }
+        n.body = T.blockStatement([T.returnStatement(n.body)]);
+        // restore body location
+        n.body.loc = bloc;
+        // set up the location for the return statement so it gets
+        // instrumented
+        n.body.body[0].loc = bloc;
+    }
+}
+
+function coverIfBranches(path) {
+    const n = path.node;
+    const hint = this.hintFor(n);
+    const ignoreIf = hint === 'if';
+    const ignoreElse = hint === 'else';
+    const branch = this.cov.newBranch('if', n.loc);
+
+    if (ignoreIf) {
+        this.setAttr(n.consequent, 'skip-all', true);
+    } else {
+        this.insertBranchCounter(path.get('consequent'), branch, n.loc);
+    }
+    if (ignoreElse) {
+        this.setAttr(n.alternate, 'skip-all', true);
+    } else {
+        this.insertBranchCounter(path.get('alternate'), branch);
+    }
+}
+
+function createSwitchBranch(path) {
+    const b = this.cov.newBranch('switch', path.node.loc);
+    this.setAttr(path.node, 'branchName', b);
+}
+
+function coverSwitchCase(path) {
+    const T = this.types;
+    const b = this.getAttr(path.parentPath.node, 'branchName');
+    /* istanbul ignore if: paranoid check */
+    if (b === null) {
+        throw new Error('Unable to get switch branch name');
+    }
+    const increment = this.getBranchIncrement(b, path.node.loc);
+    path.node.consequent.unshift(T.expressionStatement(increment));
+}
+
+function coverTernary(path) {
+    const n = path.node;
+    const branch = this.cov.newBranch('cond-expr', path.node.loc);
+    const cHint = this.hintFor(n.consequent);
+    const aHint = this.hintFor(n.alternate);
+
+    if (cHint !== 'next') {
+        this.insertBranchCounter(path.get('consequent'), branch);
+    }
+    if (aHint !== 'next') {
+        this.insertBranchCounter(path.get('alternate'), branch);
+    }
+}
+
+function coverLogicalExpression(path) {
+    const T = this.types;
+    if (path.parentPath.node.type === 'LogicalExpression') {
+        return; // already processed
+    }
+    const leaves = [];
+    this.findLeaves(path.node, leaves);
+    const b = this.cov.newBranch(
+        'binary-expr',
+        path.node.loc,
+        this.reportLogic
+    );
+    for (let i = 0; i < leaves.length; i += 1) {
+        const leaf = leaves[i];
+        const hint = this.hintFor(leaf.node);
+        if (hint === 'next') {
+            continue;
+        }
+
+        if (this.reportLogic) {
+            const increment = this.getBranchLogicIncrement(
+                leaf,
+                b,
+                leaf.node.loc
+            );
+            if (!increment[0]) {
+                continue;
+            }
+            leaf.parent[leaf.property] = T.sequenceExpression([
+                increment[0],
+                increment[1]
+            ]);
+            continue;
+        }
+
+        const increment = this.getBranchIncrement(b, leaf.node.loc);
+        if (!increment) {
+            continue;
+        }
+        leaf.parent[leaf.property] = T.sequenceExpression([
+            increment,
+            leaf.node
+        ]);
+    }
+}
+
+const codeVisitor = {
+    ArrowFunctionExpression: entries(convertArrowExpression, coverFunction),
+    AssignmentPattern: entries(coverAssignmentPattern),
+    BlockStatement: entries(), // ignore processing only
+    ExportDefaultDeclaration: entries(), // ignore processing only
+    ExportNamedDeclaration: entries(), // ignore processing only
+    ClassMethod: entries(coverFunction),
+    ClassDeclaration: entries(parenthesizedExpressionProp('superClass')),
+    ClassProperty: entries(coverClassPropDeclarator),
+    ClassPrivateProperty: entries(coverClassPropDeclarator),
+    ObjectMethod: entries(coverFunction),
+    ExpressionStatement: entries(coverStatement),
+    BreakStatement: entries(coverStatement),
+    ContinueStatement: entries(coverStatement),
+    DebuggerStatement: entries(coverStatement),
+    ReturnStatement: entries(coverStatement),
+    ThrowStatement: entries(coverStatement),
+    TryStatement: entries(coverStatement),
+    VariableDeclaration: entries(), // ignore processing only
+    VariableDeclarator: entries(coverVariableDeclarator),
+    IfStatement: entries(
+        blockProp('consequent'),
+        blockProp('alternate'),
+        coverStatement,
+        coverIfBranches
+    ),
+    ForStatement: entries(blockProp('body'), coverStatement),
+    ForInStatement: entries(blockProp('body'), coverStatement),
+    ForOfStatement: entries(blockProp('body'), coverStatement),
+    WhileStatement: entries(blockProp('body'), coverStatement),
+    DoWhileStatement: entries(blockProp('body'), coverStatement),
+    SwitchStatement: entries(createSwitchBranch, coverStatement),
+    SwitchCase: entries(coverSwitchCase),
+    WithStatement: entries(blockProp('body'), coverStatement),
+    FunctionDeclaration: entries(coverFunction),
+    FunctionExpression: entries(coverFunction),
+    LabeledStatement: entries(coverStatement),
+    ConditionalExpression: entries(coverTernary),
+    LogicalExpression: entries(coverLogicalExpression)
+};
+const globalTemplateAlteredFunction = template(`
+        var Function = (function(){}).constructor;
+        var global = (new Function(GLOBAL_COVERAGE_SCOPE))();
+`);
+const globalTemplateFunction = template(`
+        var global = (new Function(GLOBAL_COVERAGE_SCOPE))();
+`);
+const globalTemplateVariable = template(`
+        var global = GLOBAL_COVERAGE_SCOPE;
+`);
+// the template to insert at the top of the program.
+const coverageTemplate = template(
+    `
+    function COVERAGE_FUNCTION () {
+        var path = PATH;
+        var hash = HASH;
+        GLOBAL_COVERAGE_TEMPLATE
+        var gcv = GLOBAL_COVERAGE_VAR;
+        var coverageData = INITIAL;
+        var coverage = global[gcv] || (global[gcv] = {});
+        if (!coverage[path] || coverage[path].hash !== hash) {
+            coverage[path] = coverageData;
+        }
+
+        var actualCoverage = coverage[path];
+        {
+            // @ts-ignore
+            COVERAGE_FUNCTION = function () {
+                return actualCoverage;
+            }
+        }
+
+        return actualCoverage;
+    }
+`,
+    { preserveComments: true }
+);
+// the rewire plugin (and potentially other babel middleware)
+// may cause files to be instrumented twice, see:
+// https://github.com/istanbuljs/babel-plugin-istanbul/issues/94
+// we should only instrument code for coverage the first time
+// it's run through istanbul-lib-instrument.
+function alreadyInstrumented(path, visitState) {
+    return path.scope.hasBinding(visitState.varName);
+}
+function shouldIgnoreFile(programNode) {
+    return (
+        programNode.parent &&
+        programNode.parent.comments.some(c => COMMENT_FILE_RE.test(c.value))
+    );
+}
+
+/**
+ * programVisitor is a `babel` adaptor for instrumentation.
+ * It returns an object with two methods `enter` and `exit`.
+ * These should be assigned to or called from `Program` entry and exit functions
+ * in a babel visitor.
+ * These functions do not make assumptions about the state set by Babel and thus
+ * can be used in a context other than a Babel plugin.
+ *
+ * The exit function returns an object that currently has the following keys:
+ *
+ * `fileCoverage` - the file coverage object created for the source file.
+ * `sourceMappingURL` - any source mapping URL found when processing the file.
+ *
+ * @param {Object} types - an instance of babel-types.
+ * @param {string} sourceFilePath - the path to source file.
+ * @param {Object} opts - additional options.
+ * @param {string} [opts.coverageVariable=__coverage__] the global coverage variable name.
+ * @param {boolean} [opts.reportLogic=false] report boolean value of logical expressions.
+ * @param {string} [opts.coverageGlobalScope=this] the global coverage variable scope.
+ * @param {boolean} [opts.coverageGlobalScopeFunc=true] use an evaluated function to find coverageGlobalScope.
+ * @param {Array} [opts.ignoreClassMethods=[]] names of methods to ignore by default on classes.
+ * @param {object} [opts.inputSourceMap=undefined] the input source map, that maps the uninstrumented code back to the
+ * original code.
+ */
+function programVisitor(types, sourceFilePath = 'unknown.js', opts = {}) {
+    const T = types;
+    opts = {
+        ...defaults.instrumentVisitor,
+        ...opts
+    };
+    const visitState = new VisitState(
+        types,
+        sourceFilePath,
+        opts.inputSourceMap,
+        opts.ignoreClassMethods,
+        opts.reportLogic
+    );
+    return {
+        enter(path) {
+            if (shouldIgnoreFile(path.find(p => p.isProgram()))) {
+                return;
+            }
+            if (alreadyInstrumented(path, visitState)) {
+                return;
+            }
+            path.traverse(codeVisitor, visitState);
+        },
+        exit(path) {
+            if (alreadyInstrumented(path, visitState)) {
+                return;
+            }
+            visitState.cov.freeze();
+            const coverageData = visitState.cov.toJSON();
+            if (shouldIgnoreFile(path.find(p => p.isProgram()))) {
+                return {
+                    fileCoverage: coverageData,
+                    sourceMappingURL: visitState.sourceMappingURL
+                };
+            }
+            coverageData[MAGIC_KEY] = MAGIC_VALUE;
+            const hash = createHash(SHA)
+                .update(JSON.stringify(coverageData))
+                .digest('hex');
+            coverageData.hash = hash;
+            if (
+                coverageData.inputSourceMap &&
+                Object.getPrototypeOf(coverageData.inputSourceMap) !==
+                    Object.prototype
+            ) {
+                coverageData.inputSourceMap = {
+                    ...coverageData.inputSourceMap
+                };
+            }
+            const coverageNode = T.valueToNode(coverageData);
+            delete coverageData[MAGIC_KEY];
+            delete coverageData.hash;
+            let gvTemplate;
+            if (opts.coverageGlobalScopeFunc) {
+                if (path.scope.getBinding('Function')) {
+                    gvTemplate = globalTemplateAlteredFunction({
+                        GLOBAL_COVERAGE_SCOPE: T.stringLiteral(
+                            'return ' + opts.coverageGlobalScope
+                        )
+                    });
+                } else {
+                    gvTemplate = globalTemplateFunction({
+                        GLOBAL_COVERAGE_SCOPE: T.stringLiteral(
+                            'return ' + opts.coverageGlobalScope
+                        )
+                    });
+                }
+            } else {
+                gvTemplate = globalTemplateVariable({
+                    GLOBAL_COVERAGE_SCOPE: opts.coverageGlobalScope
+                });
+            }
+            const cv = coverageTemplate({
+                GLOBAL_COVERAGE_VAR: T.stringLiteral(opts.coverageVariable),
+                GLOBAL_COVERAGE_TEMPLATE: gvTemplate,
+                COVERAGE_FUNCTION: T.identifier(visitState.varName),
+                PATH: T.stringLiteral(sourceFilePath),
+                INITIAL: coverageNode,
+                HASH: T.stringLiteral(hash)
+            });
+            // explicitly call this.varName to ensure coverage is always initialized
+            path.node.body.unshift(
+                T.expressionStatement(
+                    T.callExpression(T.identifier(visitState.varName), [])
+                )
+            );
+            path.node.body.unshift(cv);
+            return {
+                fileCoverage: coverageData,
+                sourceMappingURL: visitState.sourceMappingURL
+            };
+        }
+    };
+}
+
+module.exports = programVisitor;
